Header menu logo Euclid

Logo

Euclid

Euclid on nuget.org Build Status Docs Build Status Test Status license code size

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

🎯 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:

dotnet add package Euclid

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

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

Pt

Pnt

Vector

Vc

Vec

Unit Vector

UnitVc

UnitVec

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:

Development

Building from Source

git clone https://github.com/goswinr/Euclid.git
cd Euclid
dotnet build

Prerequisites

Testing

Tests run on both .NET and JavaScript platforms with TypeScript verification.

.NET Testing

cd Tests
dotnet run

JavaScript Testing

cd Tests
npm install
npm test

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

MIT

namespace Euclid
val point1: Pnt
Multiple items
[<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
val point2: Pnt
val vector: Vec
Multiple items
[<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
val distance: float
static member Pnt.distance: a: Pnt -> b: Pnt -> float
val unitVec: UnitVec
property Vec.Unitized: UnitVec with get
<summary> Returns the 3D vector unitized. Fails with EuclidDivByZeroException if the length of the vector is too small (1e-16) to unitize. </summary>
val matrix: Matrix
Multiple items
[<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
static member Matrix.createShear: xy: float * xz: float * yx: float * yz: float * zx: float * zy: float -> Matrix
static member Matrix.createRotationZ: angleDegrees: float -> Matrix
static member Pnt.translate: shift: Vec -> pt: Pnt -> Pnt
static member Pnt.scale: f: float -> pt: Pnt -> Pnt
static member Pnt.transform: m: Matrix -> p: Pnt -> Pnt
val normalized: obj

Type something to start searching.