Euclid
A comprehensive 2D and 3D geometry library in F# without dependencies, designed for precision engineering and computational design.
It runs on JavaScript too.
Table of Contents
- Features
- Installation
- Quick Start
- Coordinate System
- Design Philosophy
- Usage Examples
- API Documentation
- Platform Support
- Development
- Testing
- Contributing
- License
Features
🎯 Core Geometry Types
- Points (Pt
, Pnt
), Vectors (Vc
, Vec
), Unit Vectors (UnitVc
, UnitVec
)
- Lines, Planes, Boxes, Bounding Boxes, Polylines
- Rotations, Quaternions, 4x4 and rigid orthonormal 4x3 matrices
✨ Key Advantages - Zero dependencies - lightweight and self-contained - Double precision - engineered for CAD/manufacturing accuracy - Immutable types - functional programming friendly - Type safety - dedicated unit vector types prevent common errors - Cross-platform - compiles to .NET, JavaScript, TypeScript, Rust, Python via Fable - Performant - All small types are structs, functions are often inline and try to minimize the allocation of intermediate objects.
🔧 Design & Manufacturing Focus - Optimized for design, construction, and manufacturing workflows - Integrates seamlessly with Rhino3D - Right-handed coordinate system (Z-up) matching industry standards
Installation
Add Euclid to your F# project via NuGet:
|
Or in F# scripting:
#r "nuget: Euclid"
Quick Start
open Euclid
// Create 3D points and vectors
let point1 = Pnt(1.0, 2.0, 3.0)
let point2 = Pnt(4.0, 5.0, 6.0)
let vector = Vec(1.0, 1.0, 0.0)
// Calculate distance
let distance = Pnt.distance point1 point2
// Create and use unit vectors
let unitVec = vector.Unitized // returns a UnitVec
// Transform with 4x4 matrix
let matrix =
Matrix.createShear(3.0, 0, 0, 0, 0, 0)
*** // Combine transfromations
Matrix.createRotationZ 45
point1
|> Pnt.translate vector
|> Pnt.scale 3.0
|> Pnt.transform matrix
Coordinate System
This library uses a right-handed coordinate system with the Z-axis pointing up.
✅ Same as in: Rhino3D, Blender, SketchUp, Revit, AutoCAD ❌ Different from: Unity, Unreal Engine, Maya
This choice aligns with industry-standard CAD and architectural software.
Design Philosophy
Points vs Vectors
- Points (
Pt
,Pnt
): Positions in space - Vectors (
Vc
,Vec
): Directions and displacements
When a 4x4 transformation matrix is applied: - Points: Undergo full transformation (rotation, scaling, translation) - Vectors: Only rotate and scale (no translation)
This follows homogeneous coordinate conventions where vectors have w=0.
Naming Conventions
Type |
2D |
3D |
---|---|---|
Point |
|
|
Vector |
|
|
Unit Vector |
|
|
Function Patterns
Functions are available in multiple forms:
// Static module function (lowercase)
let normalized = Vec.unitized myVector
// Instance method/property (uppercase)
let normalized = myVector.Unitized
API Documentation
📚 Full API Reference: goswinr.github.io/Euclid
Platform Support
Thanks to Fable, Euclid can be compiled to multiple platforms:
- ✅ .NET (Primary target)
- ✅ JavaScript (Browser/Node.js)
- ✅ TypeScript (Type-safe JS)
- ✅ Rust (Systems programming)
- ✅ Python (Data science/ML)
Development
Building from Source
|
Prerequisites
- .NET SDK 6.0 or later
- Node.js (for JavaScript testing)
Testing
Tests run on both .NET and JavaScript platforms with TypeScript verification.
.NET Testing
|
JavaScript Testing
|
The test suite ensures cross-platform compatibility and verifies TypeScript type definitions.
Contributing
Contributions are welcome!
Changelog
📋 See CHANGELOG.md for version history.
Related Projects
🦏 Euclid.Rhino - Rhino3D integration
License
[<Struct>] type Pnt = new: x: float * y: float * z: float -> Pnt val X: float val Y: float val Z: float override ToString: unit -> string static member ( * ) : a: Pnt * f: float -> Pnt + 1 overload static member (+) : a: Pnt * b: Pnt -> Pnt + 2 overloads static member (-) : a: Pnt * b: Pnt -> Vec + 2 overloads static member (/) : p: Pnt * f: float -> Pnt static member DivideByInt: pt: Pnt * i: int -> Pnt ...
<summary> An immutable 3D point. Made up from 3 floats: X, Y, and Z. A 3D point represents a location in space, but not direction or an offset. (use Vec for that.) (2D Points are called 'Pt' ) </summary>
--------------------
Pnt ()
new: x: float * y: float * z: float -> Pnt
[<Struct>] type Vec = new: x: float * y: float * z: float -> Vec val X: float val Y: float val Z: float override ToString: unit -> string static member ( * ) : a: Vec * f: float -> Vec + 1 overload static member ( *** ) : a: Vec * b: Vec -> float static member (+) : a: Vec * b: Vec -> Vec static member (-) : a: Vec * b: Vec -> Vec static member (/) : v: Vec * f: float -> Vec ...
<summary> An immutable 3D vector of any length. Made up from 3 floats: X, Y, and Z. A 3D vector represents a direction or an offset in space, but not a location. A 4x4 transformation matrix applied to a vector will only rotate and scale the vector but not translate it. (3D unit-vectors of length 1.0 are called 'UnitVec' ) (2D vectors are called 'Vc' ) </summary>
--------------------
Vec ()
new: x: float * y: float * z: float -> Vec
<summary> Returns the 3D vector unitized. Fails with EuclidDivByZeroException if the length of the vector is too small (1e-16) to unitize. </summary>
[<Struct>] type Matrix = new: m11: float * m21: float * m31: float * x41: float * m12: float * m22: float * m32: float * y42: float * m13: float * m23: float * m33: float * z43: float * m14: float * m24: float * m34: float * m44: float -> Matrix val M11: float val M21: float val M31: float val X41: float val M12: float val M22: float val M32: float val Y42: float val M13: float ...
<summary> An immutable 4x4 transformation matrix. The matrix is represented in the following column-vector syntax form: M11 M21 M31 X41 M12 M22 M32 Y42 M13 M23 M33 Z43 M14 M24 M34 M44 Where X41, Y42 and Z43 refer to the translation part of the matrix. Note: Never use the struct default constructor Matrix() as it will create an invalid zero Matrix. Use Matrix.create or Matrix.createUnchecked instead. </summary>
--------------------
Matrix ()
new: m11: float * m21: float * m31: float * x41: float * m12: float * m22: float * m32: float * y42: float * m13: float * m23: float * m33: float * z43: float * m14: float * m24: float * m34: float * m44: float -> Matrix