Skip to content

Commit 6b4de36

Browse files
committed
first commit
1 parent 8a64554 commit 6b4de36

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+9125
-87
lines changed

README.md

Lines changed: 28 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,29 @@
11
# go-module-template
2-
[![go.dev reference](https://pkg.go.dev/badge/github.com/soypat/go-module-template)](https://pkg.go.dev/github.com/soypat/go-module-template)
3-
[![Go Report Card](https://goreportcard.com/badge/github.com/soypat/go-module-template)](https://goreportcard.com/report/github.com/soypat/go-module-template)
4-
[![codecov](https://codecov.io/gh/soypat/go-module-template/branch/main/graph/badge.svg)](https://codecov.io/gh/soypat/go-module-template)
5-
[![Go](https://github.com/soypat/go-module-template/actions/workflows/go.yml/badge.svg)](https://github.com/soypat/go-module-template/actions/workflows/go.yml)
6-
[![sourcegraph](https://sourcegraph.com/github.com/soypat/go-module-template/-/badge.svg)](https://sourcegraph.com/github.com/soypat/go-module-template?badge)
7-
<!--
8-
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
9-
10-
[![stability-experimental](https://img.shields.io/badge/stability-experimental-orange.svg)](https://github.com/emersion/stability-badges#experimental)
11-
12-
See https://github.com/emersion/stability-badges#unstable for more stability badges.
13-
-->
14-
15-
Go module template with instructions on how to make your code importable and setting up codecov CI.
16-
17-
How to install package with newer versions of Go (+1.16):
18-
```sh
19-
go mod download github.com/soypat/go-module-template@latest
20-
```
21-
22-
23-
## First steps
24-
25-
0. Replace LICENSE with your desired license. BSD 3 clause is included by default.
26-
27-
1. Fix `go.mod` file by replacing `github.com/YOURUSER/YOURREPONAME` with your corresponding project repository link.
28-
29-
2. Replace `soypat/go-module-template` in the badge URLs. Make sure you've replaced all of them by performing text search in the readme for `soypat` and `template`.
30-
31-
3. Rename `module.go` and `module_test.go` to fit your own repository needs. Below are some exemplary modules that abide by what's generally considered "good practices":
32-
- [`mu8` minimal machine learning library](https://github.com/soypat/mu8). Note how most interfaces and interface algorithms are defined at the root package level and how the concrete implementations live in the subdirectories.
33-
- Similarily [`sdf`](https://github.com/soypat/sdf) also does the same with defining interfaces top level.
34-
35-
## Setting up codecov CI
36-
This instructive will allow for tests to run on pull requests and pushes to your repository.
37-
38-
1. Create an account on [codecov.io](https://app.codecov.io/)
39-
40-
2. Setup repository on codecov and obtain the CODECOV_TOKEN token, which is a string of base64 characters.
41-
42-
3. Open up the github repository for this project and go to `Settings -> Secrets and variables -> Actions`. Once there create a New Repository Secret. Name it `CODECOV_TOKEN` and copy paste the token obtained in the previous step in the `secret` input box. Click "Add secret".
43-
44-
2+
[![go.dev reference](https://pkg.go.dev/badge/github.com/soypat/geometry)](https://pkg.go.dev/github.com/soypat/geometry)
3+
[![Go Report Card](https://goreportcard.com/badge/github.com/soypat/geometry)](https://goreportcard.com/report/github.com/soypat/geometry)
4+
[![codecov](https://codecov.io/gh/soypat/geometry/branch/main/graph/badge.svg)](https://codecov.io/gh/soypat/geometry)
5+
[![Go](https://github.com/soypat/geometry/actions/workflows/go.yml/badge.svg)](https://github.com/soypat/geometry/actions/workflows/go.yml)
6+
[![sourcegraph](https://sourcegraph.com/github.com/soypat/geometry/-/badge.svg)](https://sourcegraph.com/github.com/soypat/geometry?badge)
7+
8+
Stackful, correct, lean and performant library ideal for any use case. From embedded systems to GPU usage.
9+
10+
## Features
11+
- Vector and matrices that map to GPU alignment
12+
- Quaternions
13+
- 2D/3D Grid generation and traversal
14+
- Performant 3x3 SVD and QR decomposition
15+
- 2D/3D Triangles
16+
- Bounding boxes
17+
- Polygon generation with arc and chamfering
18+
- 2D splines with support for Quadratic and cubic modes
19+
- Provided splines are: Cubic/quadratic Bezier, Hermite spline, Basis spline, Cardinal spline, Catmull-Rom spline
20+
- Few 1D math conveniences
21+
22+
## Module structure
23+
- ms3..ms1 contain 32-bit (`float32`) spatial geometrical primitives.
24+
- md3..md1 contain 64-bit (`float64`) spatial geometrical primitive. This code is identically duplicated from ms* packages using code generation, including tests.
25+
26+
## Development
27+
Code developed is exclusively `float32`. `float64` code is generated automatically from the `float32` code by running `gen.go`.
28+
29+
The `internal` package serves as a place to store data that is dependent on whether the implementation is 64 or 32 bit.

cmd/hello-world/main.go

Lines changed: 0 additions & 9 deletions
This file was deleted.

gen.go

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
package main
2+
3+
import (
4+
"embed"
5+
"io"
6+
"log"
7+
"os"
8+
"path/filepath"
9+
"strings"
10+
)
11+
12+
var (
13+
//go:embed ms*
14+
srcmath embed.FS
15+
replaceWithF64 = [][2]string{
16+
{"ms1", "md1"},
17+
{"ms2", "md2"},
18+
{"ms3", "md3"},
19+
}
20+
)
21+
22+
func main() {
23+
err := run()
24+
if err != nil {
25+
log.Fatal(err)
26+
}
27+
log.Println("generated files")
28+
}
29+
30+
func run() error {
31+
for _, rep := range replaceWithF64 {
32+
files, err := srcmath.ReadDir(rep[0])
33+
if err != nil {
34+
return err
35+
}
36+
os.RemoveAll(rep[1])
37+
err = os.MkdirAll(rep[1], 0777)
38+
if err != nil {
39+
return err
40+
}
41+
for _, file := range files {
42+
43+
src, err := srcmath.Open(filepath.Join(rep[0], file.Name()))
44+
if err != nil {
45+
return err
46+
}
47+
newName := strings.ReplaceAll(file.Name(), rep[0], rep[1])
48+
dst, err := os.Create(filepath.Join(rep[1], newName))
49+
if err != nil {
50+
return err
51+
}
52+
defer dst.Close()
53+
b, err := io.ReadAll(src)
54+
if err != nil {
55+
return err
56+
}
57+
58+
repr := strings.NewReplacer(
59+
"float32", "float64",
60+
"package "+rep[0], "package "+rep[1],
61+
"\"github.com/chewxy/math32\"", "\"math\"",
62+
"\"github.com/soypat/geometry/ms1\"", "ms1 \"github.com/soypat/geometry/md1\"",
63+
"\"github.com/soypat/geometry/ms3\"", "ms3 \"github.com/soypat/geometry/md3\"",
64+
)
65+
dst.WriteString(`// DO NOT EDIT.
66+
// This file was generated automatically
67+
// from gen.go. Please do not edit this file.
68+
69+
`)
70+
_, err = repr.WriteString(dst, string(b))
71+
if err != nil {
72+
return err
73+
}
74+
}
75+
}
76+
return nil
77+
}

go.mod

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1-
module github.com/YOURUSER/YOURREPONAME
1+
module github.com/soypat/geometry
22

3-
go 1.20
3+
go 1.18
4+
5+
require github.com/chewxy/math32 v1.11.1

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
github.com/chewxy/math32 v1.11.1 h1:b7PGHlp8KjylDoU8RrcEsRuGZhJuz8haxnKfuMMRqy8=
2+
github.com/chewxy/math32 v1.11.1/go.mod h1:dOB2rcuFrCn6UHrze36WSLVPKtzPMRAQvBvUwkSsLqs=

internal/internalmath.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package internal
2+
3+
const (
4+
Smallfloat32 = 1e-5
5+
Smallfloat64 = 1e-8
6+
)

md1/md1.go

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
// DO NOT EDIT.
2+
// This file was generated automatically
3+
// from gen.go. Please do not edit this file.
4+
5+
// package md1 implements basic 1D math useful for 3D graphics applications.
6+
// Functions in this package have their OpenGL equivalent which is usually of the same name.
7+
package md1
8+
9+
import (
10+
math "math"
11+
"github.com/soypat/geometry/internal"
12+
)
13+
14+
// Sign returns -1, 0, or 1 for negative, zero or positive x argument, respectively, just like OpenGL's "sign" function.
15+
func Sign(x float64) float64 {
16+
if x == 0 {
17+
return 0
18+
}
19+
return math.Copysign(1, x)
20+
}
21+
22+
// Clamp returns value v clamped between Min and Max.
23+
func Clamp(v, Min, Max float64) float64 {
24+
return math.Min(Max, math.Max(v, Min))
25+
}
26+
27+
// Interp performs the linear interpolation between x and y, mapping with a in interval [0,1].
28+
// This function is known as "mix" in OpenGL.
29+
func Interp(x, y, a float64) float64 {
30+
return x*(1-a) + y*a
31+
}
32+
33+
// SmoothStep performs smooth cubic hermite interpolation between 0 and 1 when edge0 < x < edge1.
34+
func SmoothStep(edge0, edge1, x float64) float64 {
35+
t := Clamp((x-edge0)/(edge1-edge0), 0, 1)
36+
return t * t * (3 - 2*t)
37+
}
38+
39+
// EqualWithinAbs checks if a and b are within tol of eachother.
40+
func EqualWithinAbs(a, b, tol float64) bool {
41+
return math.Abs(a-b) <= tol
42+
}
43+
44+
// DefaultNewtonRaphsonSolver returns a [NewtonRaphsonSolver] with recommended parameters.
45+
func DefaultNewtonRaphsonSolver() NewtonRaphsonSolver {
46+
return NewtonRaphsonSolver{
47+
MaxIterations: 17,
48+
Dx: internal.Smallfloat64,
49+
Tolerance: 1.49012 * internal.Smallfloat64,
50+
}
51+
}
52+
53+
// NewtonRaphsonSolver implements Newton-Raphson root finding algorithm for an arbitrary function.
54+
type NewtonRaphsonSolver struct {
55+
// MaxIterations specifies how many iterations of Newton's succesive
56+
// approximations to perform. Each iteration evaluates function 3 times. Parameter is required.
57+
MaxIterations int
58+
// Tolerance sets the criteria for ending the root search when f(x)/f'(x) <= Tolerance.
59+
Tolerance float64
60+
// Dx is the step with which the gradient is calculated with central-finite-differences.
61+
Dx float64
62+
63+
// Optional parameters below:
64+
65+
// Relaxation is optional parameter to avoid overshooting during gradient descent for ill conditioned functions, i.e: large gradient near root.
66+
Relaxation float64
67+
// AdaptiveDxMaxIterations sets maximum amount of changes to step (Dx) throughout root search when encountering numerical issues.
68+
// If not set then not used.
69+
AdaptiveDxMaxIterations int
70+
// RootLims clamps search for root to x_min=RootLims[0], x_max=RootLims[1].
71+
RootLims [2]float64
72+
}
73+
74+
// Root solves for a root of f such that f(x)=0 by starting guessing at x0 solving using Newton-Raphson method.
75+
// Root returns the first root found and the amount of interations before converging.
76+
//
77+
// If the convergence parameter returned is negative a solution was not found within the desired tolerance.
78+
func (nra NewtonRaphsonSolver) Root(x0 float64, f func(xGuess float64) float64) (x_root float64, convergedIn int) {
79+
switch {
80+
case nra.RootLims[0] > nra.RootLims[1]:
81+
panic("invalid RootLims")
82+
case nra.MaxIterations <= 0:
83+
panic("invalid MaxIterations")
84+
case nra.Tolerance <= 0 || math.IsNaN(nra.Tolerance):
85+
panic("invalid Tolerance")
86+
case nra.Dx <= 0 || math.IsNaN(nra.Dx):
87+
panic("invalid Step")
88+
case nra.AdaptiveDxMaxIterations < 0:
89+
panic("invalid AdaptiveStepMaxIterations")
90+
case math.IsNaN(nra.Relaxation):
91+
panic("invalid Relaxation")
92+
}
93+
94+
clampSol := nra.RootLims != [2]float64{}
95+
krelax := 1 - nra.Relaxation
96+
x_root = x0
97+
98+
adapt := 1
99+
dx := nra.Dx
100+
dxdiv2 := dx / 2
101+
102+
for i := 1; i <= nra.MaxIterations; i++ {
103+
// Approximate derivative f'(x) with central finite difference method.
104+
// Requires more evaluations but is more precise than regular finite differences.
105+
fxp := f(x_root + dxdiv2)
106+
fxn := f(x_root - dxdiv2)
107+
fprime := (fxp - fxn) / dx
108+
109+
if fprime == 0 || math.IsNaN(fprime) {
110+
// Converged to a local minimum which is not a root or problem badly conditioned.
111+
if adapt > nra.AdaptiveDxMaxIterations {
112+
return x_root, -i
113+
}
114+
// Adapt step to be larger to maybe get out of badly conditioned problem.
115+
dx = nra.Dx * float64(int(1<<adapt))
116+
dxdiv2 = dx / 2
117+
adapt++
118+
continue
119+
}
120+
121+
fx := f(x_root)
122+
diff := fx / fprime
123+
if math.Abs(diff) <= nra.Tolerance {
124+
// SOLUTION FOUND.
125+
// apply one more iteration if permitted, we have two evaluations we can make use of.
126+
xnew := x_root - diff*krelax
127+
if i < nra.MaxIterations && math.Abs(fx) > math.Abs(f(xnew)) {
128+
x_root = xnew
129+
i++
130+
}
131+
return x_root, i
132+
}
133+
x_root -= diff * krelax
134+
if clampSol {
135+
x_root = Clamp(x_root, nra.RootLims[0], nra.RootLims[1])
136+
}
137+
}
138+
return x_root, -nra.MaxIterations
139+
}

0 commit comments

Comments
 (0)