├── .gitignore
├── .travis.yml
├── LICENSE
├── README.md
├── benchmark
├── regularCurveSampling.js
├── regularSurfaceDerivatives.js
└── regularSurfaceSampling.js
├── build
├── .gitignore
└── js
│ ├── verb.es.js
│ ├── verb.js
│ ├── verb.min.js
│ └── verbHaxe.js
├── buildcpp.hxml
├── buildcs.hxml
├── buildjs.hxml
├── buildphp.hxml
├── buildpython.hxml
├── docs
├── .gitignore
├── README.md
├── custom_theme
│ ├── base.html
│ └── css
│ │ └── base.css
├── docs
│ ├── .gitignore
│ └── index.md
├── gen.js
├── mkdocs.yml
├── package.json
├── parse.js
└── template.md
├── examples
├── conics.html
├── css
│ ├── codemirror.css
│ ├── colorforth.css
│ └── example.css
├── curveByPointInterpolation.html
├── curveClosestPoint.html
├── curveDivide.html
├── curveIntersection.html
├── curveReverse.html
├── curveSplit.html
├── cylindricalSurface.html
├── extrudedSurface.html
├── js
│ ├── OrbitControls.js
│ ├── codemirror.js
│ ├── example.js
│ ├── javascript.js
│ ├── three.min.js
│ ├── threeBasic.js
│ ├── verb.min.js
│ └── verbToThreeConversion.js
├── loftedSurface.html
├── meshIntersection.html
├── meshSlicing.html
├── revolvedSurface.html
├── surface.html
├── surfaceAdaptiveTessellation.html
├── surfaceBoundaries.html
├── surfaceClosestPoint.html
├── surfaceIntersection.html
├── surfaceIsocurves.html
├── surfaceSplit.html
└── sweptSurface.html
├── package-lock.json
├── package.json
├── rollup.config.mjs
├── site
├── css
│ └── style.css
├── index.html
└── pictures
│ ├── conics.png
│ ├── curveByPointInterpolation.png
│ ├── curveClosestPoint.png
│ ├── curveDivide.png
│ ├── curveIntersection.png
│ ├── curveSplit.png
│ ├── cylindricalSurface.png
│ ├── extrudedSurface.png
│ ├── loftedSurface.png
│ ├── meshIntersection.png
│ ├── meshSlicing.png
│ ├── revolvedSurface.png
│ ├── surface.png
│ ├── surfaceAdaptiveTessellation.png
│ ├── surfaceBoundaries.png
│ ├── surfaceClosestPoint.png
│ ├── surfaceIntersection.png
│ ├── surfaceIsocurves.png
│ ├── surfaceSplit.png
│ └── sweptSurface.png
├── src
├── support
│ ├── footer.js
│ └── header.js
└── verb
│ ├── Verb.hx
│ ├── core
│ ├── ArrayExtensions.hx
│ ├── Binomial.hx
│ ├── BoundingBox.hx
│ ├── Constants.hx
│ ├── Data.hx
│ ├── Intersections.hx
│ ├── KdTree.hx
│ ├── LazyCurveBoundingBoxTree.hx
│ ├── LazyMeshBoundingBoxTree.hx
│ ├── LazyPolylineBoundingBoxTree.hx
│ ├── LazySurfaceBoundingBoxTree.hx
│ ├── Mat.hx
│ ├── Mesh.hx
│ ├── MeshBoundingBoxTree.hx
│ ├── Minimizer.hx
│ ├── Serialization.hx
│ ├── SurfaceBoundingBoxTree.hx
│ ├── Trig.hx
│ └── Vec.hx
│ ├── eval
│ ├── Analyze.hx
│ ├── Check.hx
│ ├── Divide.hx
│ ├── Eval.hx
│ ├── Intersect.hx
│ ├── Make.hx
│ ├── Modify.hx
│ └── Tess.hx
│ ├── exe
│ ├── Dispatcher.hx
│ ├── ThreadPool.hx
│ └── WorkerPool.hx
│ └── geom
│ ├── Arc.hx
│ ├── BezierCurve.hx
│ ├── Circle.hx
│ ├── ConicalSurface.hx
│ ├── CylindricalSurface.hx
│ ├── Ellipse.hx
│ ├── EllipseArc.hx
│ ├── ExtrudedSurface.hx
│ ├── ICurve.hx
│ ├── ISurface.hx
│ ├── Intersect.hx
│ ├── Line.hx
│ ├── NurbsCurve.hx
│ ├── NurbsSurface.hx
│ ├── RevolvedSurface.hx
│ ├── SphericalSurface.hx
│ └── SweptSurface.hx
├── test
├── testCore.js
├── testEval.js
└── testGeom.js
├── todo
└── verb.iml
/.gitignore:
--------------------------------------------------------------------------------
1 | coverage.html
2 | .DS_Store
3 | out/
4 | .idea/
5 | build/cs/
6 | lib-cov
7 | *.seed
8 | *.log
9 | *.csv
10 | *.dat
11 | *.out
12 | *.pid
13 | *.swp
14 | *.swo
15 | node_modules/
16 | *.VC.db
17 | *.VC.db-wal
18 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - "7"
4 | before_install:
5 | - sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
6 | - sudo apt-get update -qq # run update before installing anything
7 | - sudo apt-get install python-software-properties -y # for the next command
8 | - sudo add-apt-repository ppa:haxe/releases -y # add the ubuntu ppa that contains haxe
9 | - sudo apt-get update # pull info from ppa
10 | - sudo apt-get install haxe -y # install haxe (and neko)
11 | - npm install -g grunt-cli
12 | - mkdir ~/haxelib # create a folder for installing haxelib
13 | - haxelib setup ~/haxelib
14 | - haxelib install promhx
15 | - haxelib install nodejs
16 | install:
17 | - sudo apt-get install -qq g++-4.8
18 | - export CXX="g++-4.8"
19 | - npm install
20 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) Peter Boyer 2014-6
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # verb
2 |
3 | [](https://badge.fury.io/js/verb-nurbs)
4 | [](https://www.npmjs.com/package/verb-nurbs)
5 | [](https://github.com/emersion/stability-badges#stable)
6 | [](https://github.com/pboyer/verb/blob/master/LICENSE)
7 |
8 | ### Open-source, cross-platform NURBS
9 |
10 | verb is a library for creating and manipulating NURBS surfaces and curves in many languages including JavaScript.
11 |
12 | verb provides advanced tools like derivative evaluation, adaptive tessellation, and intersection. Verb provides a concurrent execution runtime via WebWorkers in modern browsers and thread pools on other platforms and is suitable for use in a datacenter or in the browser.
13 |
14 | ### Platforms
15 |
16 | Using haxe, verb compiles for:
17 |
18 | * JavaScript
19 | * C#
20 | * C++
21 | * Python
22 | * PHP
23 |
24 | ### Documentation
25 |
26 | For information on building and using verb, **go to the [docs](http://verbnurbs.com/docs)**
27 |
28 | ### JavaScript Quick Start
29 |
30 | You can install verb with
31 |
32 | npm install verb-nurbs
33 |
34 | Pre-compiled JavaScript can be found in [build/js](https://github.com/pboyer/verb/blob/master/build/js).
35 |
36 | In addition, this package is hosted at UNPKG, and can be imported directly into webpages.
37 | ```
38 |
39 | ```
40 |
41 | ### Examples
42 |
43 | You'll find many usage examples in the [examples directory](https://github.com/pboyer/verb/blob/master/examples) and amongst the [tests](https://github.com/pboyer/verb/tree/master/test).
44 |
45 |
--------------------------------------------------------------------------------
/benchmark/regularCurveSampling.js:
--------------------------------------------------------------------------------
1 | var Benchmark = require('benchmark')
2 | , verb = require('../build/js/verb.js');
3 |
4 |
5 | var crv = verb.eval.Make.rationalBezierCurve( [[0,0,0], [1,1,1], [2,1,1], [3,1,0]] );
6 |
7 | module.exports = {
8 | name: 'Regular curve sampling',
9 | tests: {
10 | 'curveRegularSamplePoints (100)': function() {
11 | var p = verb.eval.Eval.curveRegularSamplePoints( crv, 100 );
12 | },
13 | 'direct evaluation (100)': function() {
14 | var p = [];
15 | var sp = 1 / 100;
16 |
17 | for (var i = 0; i < 101; i++){
18 | p.push( verb.eval.Eval.rationalCurvePoint( crv, i*sp ) )
19 | }
20 | }
21 | }
22 | };
23 |
24 |
--------------------------------------------------------------------------------
/benchmark/regularSurfaceDerivatives.js:
--------------------------------------------------------------------------------
1 | var Benchmark = require('benchmark')
2 | , verb = require('../build/js/verb.js');
3 |
4 | function getComplexSurface(){
5 |
6 | var degree = 3
7 | , knots = [0, 0, 0, 0, 0.333, 0.666, 1, 1, 1, 1]
8 | , pts = [ [ [0, 0, -10], [10, 0, 0], [20, 0, 0], [30, 0, 0] , [40, 0, 0], [50, 0, 0] ],
9 | [ [0, -10, 0], [10, -10, 10], [20, -10, 10], [30, -10, 0] , [40, -10, 0], [50, -10, 0] ],
10 | [ [0, -20, 0], [10, -20, 10], [20, -20, 10], [30, -20, 0] , [40, -20, -2], [50, -20, 0] ],
11 | [ [0, -30, 0], [10, -30, 0], [20, -30, -23], [30, -30, 0] , [40, -30, 0], [50, -30, 0] ],
12 | [ [0, -40, 0], [10, -40, 0], [20, -40, 0], [30, -40, 4] , [40, -40, -20], [50, -40, 0] ],
13 | [ [0, -50, 12], [10, -50, 0], [20, -50, 0], [30, -50, 0] , [50, -50, 0], [50, -50, -15] ], ]
14 | , wts = [ [ 1, 1, 1, 1, 1, 1],
15 | [ 1, 1, 1, 1, 1, 1],
16 | [ 1, 1, 1, 1, 1, 1],
17 | [ 1, 1, 1, 1, 1, 1],
18 | [ 1, 1, 1, 1, 1, 1],
19 | [ 1, 1, 1, 1, 1, 1] ];
20 |
21 | pts = verb.eval.Eval.homogenize2d(pts, wts);
22 |
23 | var srfObj = {
24 | degreeU : degree,
25 | degreeV : degree,
26 | knotsU : knots,
27 | knotsV : knots,
28 | controlPoints : pts
29 | };
30 |
31 | return srfObj;
32 | }
33 |
34 | var complexSurface = getComplexSurface();
35 |
36 | module.exports = {
37 | name: 'Regular surface derivatives',
38 | tests: {
39 | 'rationalSurfaceRegularSampleDerivatives (80 x 80)': function() {
40 | var ar = verb.eval.Eval.rationalSurfaceRegularSampleDerivatives( complexSurface, 80, 80, 1 );
41 | },
42 | 'direct evaluation (80 x 80)': function() {
43 | var ar = [];
44 | var sp = 1 / 80;
45 |
46 | for (var i = 0; i < 81; i++){
47 | var ari = [];
48 | ar.push(ari);
49 | for (var j = 0; j < 81; j++){
50 | ari.push( verb.eval.Eval.rationalSurfaceDerivatives( complexSurface, i*sp, j*sp, 1 ) )
51 | }
52 | }
53 | }
54 | }
55 | };
56 |
57 |
--------------------------------------------------------------------------------
/benchmark/regularSurfaceSampling.js:
--------------------------------------------------------------------------------
1 | var Benchmark = require('benchmark')
2 | , verb = require('../build/js/verb.js');
3 |
4 | function getComplexSurface(){
5 |
6 | var degree = 3
7 | , knots = [0, 0, 0, 0, 0.333, 0.666, 1, 1, 1, 1]
8 | , pts = [ [ [0, 0, -10], [10, 0, 0], [20, 0, 0], [30, 0, 0] , [40, 0, 0], [50, 0, 0] ],
9 | [ [0, -10, 0], [10, -10, 10], [20, -10, 10], [30, -10, 0] , [40, -10, 0], [50, -10, 0] ],
10 | [ [0, -20, 0], [10, -20, 10], [20, -20, 10], [30, -20, 0] , [40, -20, -2], [50, -20, 0] ],
11 | [ [0, -30, 0], [10, -30, 0], [20, -30, -23], [30, -30, 0] , [40, -30, 0], [50, -30, 0] ],
12 | [ [0, -40, 0], [10, -40, 0], [20, -40, 0], [30, -40, 4] , [40, -40, -20], [50, -40, 0] ],
13 | [ [0, -50, 12], [10, -50, 0], [20, -50, 0], [30, -50, 0] , [50, -50, 0], [50, -50, -15] ], ]
14 | , wts = [ [ 1, 1, 1, 1, 1, 1],
15 | [ 1, 1, 1, 1, 1, 1],
16 | [ 1, 1, 1, 1, 1, 1],
17 | [ 1, 1, 1, 1, 1, 1],
18 | [ 1, 1, 1, 1, 1, 1],
19 | [ 1, 1, 1, 1, 1, 1] ];
20 |
21 | pts = verb.eval.Eval.homogenize2d(pts, wts);
22 |
23 | var srfObj = {
24 | degreeU : degree,
25 | degreeV : degree,
26 | knotsU : knots,
27 | knotsV : knots,
28 | controlPoints : pts
29 | };
30 |
31 | return srfObj;
32 | }
33 |
34 | var complexSurface = getComplexSurface();
35 |
36 | module.exports = {
37 | name: 'Regular surface sampling',
38 | tests: {
39 | 'surfaceRegularSample (80 x 80)': function() {
40 | verb.eval.Eval.surfaceRegularSamplePoints( complexSurface, 80, 80 );
41 | },
42 | 'direct evaluation (80 x 80)': function() {
43 | var ar = [];
44 | var sp = 1 / 80;
45 |
46 | for (var i = 0; i < 81; i++){
47 | var ari = [];
48 | ar.push(ari);
49 | for (var j = 0; j < 81; j++){
50 | ari.push( verb.eval.Eval.surfacePoint( complexSurface, i*sp, j*sp ) )
51 | }
52 | }
53 | }
54 | }
55 | };
56 |
57 |
--------------------------------------------------------------------------------
/build/.gitignore:
--------------------------------------------------------------------------------
1 | cpp
2 | cs
3 | python.py
4 | php
5 | java
6 |
--------------------------------------------------------------------------------
/build/js/verb.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Index / Entry point for the VERB-NURBS package.
3 | */
4 |
5 | // provide window as required by the promhx library
6 | if (typeof window === "undefined") {
7 | var window = global;
8 | }
9 |
10 | // setup the promise handling for async method invocations
11 | const lookup = function(className, methodName){
12 | var obj = { verb: verb };
13 |
14 | className.split(".").forEach(function(x){
15 | if (obj) obj = obj[ x ];
16 | });
17 |
18 | if (!obj) return null;
19 |
20 | return obj[ methodName ];
21 | }
22 |
23 | const onmessage = function( e ) {
24 | if (!e.data || !e.data.className || !e.data.methodName) return;
25 |
26 | const method = lookup( e.data.className, e.data.methodName );
27 |
28 | if (!method){
29 | return console.error("could not find " + e.data.className + "." + e.data.methodName)
30 | }
31 |
32 | postMessage( { result: method.apply( null, e.data.args ), id: e.data.id } );
33 | }
34 |
35 |
36 | // provide the Worker class for async library functions
37 | if (typeof Worker === "undefined") {
38 | var Worker = require("web-worker")
39 | }
40 |
41 | // import and re-export the Javascript library
42 | const verb = require('./verbHaxe.js');
43 |
44 | module.exports = verb
45 |
--------------------------------------------------------------------------------
/buildcpp.hxml:
--------------------------------------------------------------------------------
1 | -lib promhx
2 | -main verb.Verb
3 | -cp src
4 | -cpp build/cpp
5 | -dce std
6 | -D dll
7 |
--------------------------------------------------------------------------------
/buildcs.hxml:
--------------------------------------------------------------------------------
1 | -lib promhx
2 | -main verb.Verb
3 | -cp src
4 | -cs build/cs
5 | -dce std
6 | -D dll
--------------------------------------------------------------------------------
/buildjs.hxml:
--------------------------------------------------------------------------------
1 | -lib promhx
2 | -main verb.Verb
3 | -cp src
4 | -js build/js/verbHaxe.js
5 | -dce std
--------------------------------------------------------------------------------
/buildphp.hxml:
--------------------------------------------------------------------------------
1 | -lib promhx
2 | -main verb.Verb
3 | -cp src
4 | -php build/php
5 | -dce std
6 | -D dll
7 |
--------------------------------------------------------------------------------
/buildpython.hxml:
--------------------------------------------------------------------------------
1 | -lib promhx
2 | -main verb.Verb
3 | -cp src
4 | -python build/verb.py
5 | -dce std
6 | -D dll
7 |
--------------------------------------------------------------------------------
/docs/.gitignore:
--------------------------------------------------------------------------------
1 | docs
2 | site
3 | node_modules
4 |
--------------------------------------------------------------------------------
/docs/README.md:
--------------------------------------------------------------------------------
1 | ## Dependencies
2 |
3 | Install [mkdocs](http://www.mkdocs.org/#installation) and [node.js](https://nodejs.org/en/download/)
4 |
5 | Install node dependencies:
6 |
7 | ```
8 | > npm install
9 | ```
10 |
11 | ## Building
12 |
13 | You'll need to generate all of the md files, which are generated from the .hx files and transported into the docs directory.
14 |
15 | ```
16 | > node gen.js
17 | ```
18 |
19 | Use mkdocs to generate the static html:
20 |
21 | ```
22 | > mkdocs build
23 | ```
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/docs/custom_theme/base.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | verb docs - {{ current_page.title }}
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
54 |
55 |
56 |
66 |
67 |
68 | {{ content }}
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
--------------------------------------------------------------------------------
/docs/custom_theme/css/base.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | font-family: 'Source Sans Pro', sans-serif;
4 | font-size: 18px;
5 | }
6 |
7 | .row, .col { overflow: hidden; position: absolute; }
8 | .row { left: 0; right: 0; }
9 | .col { top: 0; bottom: 0; }
10 | .scroll-x { overflow-x: auto; }
11 | .scroll-y { overflow-y: auto; }
12 |
13 | #header {
14 | overflow: visible;
15 | height: 65px;
16 | background: #444;
17 | z-index: 2;
18 | box-shadow: 2px 0px 10px rgba(0,0,0,0.5);
19 | }
20 |
21 | #search {
22 | float: right;
23 | position: relative;
24 | z-index: 0;
25 | }
26 |
27 | #title {
28 | position: absolute;
29 | top: 10px;
30 | left: 380px;
31 | right: 300px;
32 | font-weight: 300;
33 | text-align: center;
34 | font-size: 30px;
35 | color: #ccc;
36 | pointer-events: none;
37 | }
38 |
39 | #title span {
40 | font-weight: 400;
41 | }
42 |
43 | #site {
44 | float: right;
45 | padding-top: 20px;
46 | }
47 |
48 | #site a {
49 | text-decoration: none;
50 | color: #aaa;
51 | padding: 10px 22px;
52 | }
53 |
54 | #site a:hover {
55 | color: white;
56 | }
57 |
58 | #search input {
59 | padding: 15px;
60 | font-size: 18px;
61 | width: 200px;
62 | margin: 0;
63 | border: none;
64 | box-size: border-box;
65 | height: 65px;
66 | font-family: 'Source Sans Pro', sans-serif;
67 | outline-width: 0;
68 | background: #eee;
69 | }
70 |
71 | #search input:focus {
72 | background: white;
73 | }
74 |
75 | #search input:focus + div {
76 | display: block;
77 | }
78 |
79 | #mkdocs-search-results:hover {
80 | display: block;
81 | }
82 |
83 | #mkdocs-search-results {
84 | z-index: 1;
85 | display: none;
86 | box-size: border-box;
87 | position: absolute;
88 | top: 65px;
89 | left: -200px;
90 | width: 400px;
91 | background: #333;
92 | color: white;
93 | font-size: 18px;
94 | max-height: 600px;
95 | overflow-y: auto;
96 | box-shadow: -2px 5px 10px rgba(0,0,0,0.5);
97 | }
98 |
99 | #mkdocs-search-results article {
100 | padding: 5px;
101 | }
102 |
103 | #mkdocs-search-results article:hover {
104 | background: #444;
105 | }
106 |
107 | #mkdocs-search-results p {
108 | padding: 5px;
109 | }
110 |
111 | #mkdocs-search-results a {
112 | color: white;
113 | }
114 |
115 | #mkdocs-search-results article h3 {
116 | padding: 5px;
117 | margin: 0;
118 | }
119 |
120 | #mkdocs-search-results article p {
121 | padding: 0;
122 | color: #888;
123 | }
124 |
125 | #nav {
126 | display: inline-block;
127 | }
128 |
129 | #nav .nav-list {
130 | padding: 0;
131 | margin: 0;
132 | list-style-type: none;
133 | border: 0;
134 | font-size: 0;
135 | }
136 |
137 | .nav-major a {
138 | color: white;
139 | text-decoration: none;
140 | }
141 |
142 | .nav-major:nth-of-type(1) {
143 | background: #444;
144 | }
145 |
146 | .nav-major:nth-of-type(2) {
147 | background: #DD5500;
148 | }
149 |
150 | .nav-major:nth-of-type(3) {
151 | background: #B10064;
152 | }
153 |
154 | .nav-major:nth-of-type(4) {
155 | background: #008E6E;
156 | }
157 |
158 | .nav-major:nth-of-type(5) {
159 | background: #89CE00;
160 | }
161 |
162 | #nav .nav-major {
163 | text-shadow: 0px 1px #000000;
164 | color: white;
165 | box-sizing: border-box;
166 | height: 65px;
167 | text-transform: lowercase;
168 | font-size: 24px;
169 | border: 0;
170 | padding: 15px 15px;
171 | margin: 0;
172 | display: inline-block;
173 | list-style-type: none;
174 | position: relative;
175 | }
176 |
177 | #nav .nav-major:hover {
178 | background: #333;
179 | }
180 |
181 | #nav .nav-major:hover .nav-minor {
182 | display: inline-block;
183 | }
184 |
185 | #nav .nav-minor {
186 | box-shadow: 2px 2px 10px rgba(0,0,0,0.5);
187 | text-transform: none;
188 | position: absolute;
189 | z-index: 1;
190 | top: 65px;
191 | left: 0;
192 | border: 0;
193 | padding: 0;
194 | margin: 0;
195 | display: none;
196 | list-style-type: none;
197 | }
198 |
199 | #nav .nav-minor-minor {
200 | padding: 0;
201 | margin: 0;
202 | list-style-type: none;
203 | }
204 |
205 | #nav .nav-minor-minor a {
206 | box-sizing: border-box;
207 | background: #333;
208 | padding: 10px;
209 | display: block;
210 | width: 100%;
211 | margin: 0;
212 | font-size: 18px;
213 | }
214 |
215 | #nav .nav-minor-minor a:hover {
216 | background: #444;
217 | }
218 |
219 | #body {
220 | top: 65px;
221 | bottom: 0;
222 | }
223 |
224 | #toc {
225 | width: 300px;
226 | color: #222;
227 | text-shadow: 0px 1px white;
228 | background: #fafafa;
229 | }
230 |
231 | #toc h3 {
232 | text-transform: uppercase;
233 | padding: 5px 10px;
234 | color: #333;
235 | }
236 |
237 | #toc .toc-major {
238 | background: #ddd;
239 | }
240 |
241 | #toc ul {
242 | background: #e8e8e8;
243 | padding: 0;
244 | margin: 0;
245 | list-style-type: none;
246 | }
247 |
248 | #toc li {
249 | padding: 0;
250 | margin: 0;
251 | }
252 |
253 | #toc li a {
254 | display: block;
255 | width: 300px;
256 | padding: 15px;
257 | border-bottom: 1px solid #ddd;
258 | }
259 |
260 | #toc a:hover {
261 | background: #fafafa;
262 | }
263 |
264 | #toc a {
265 | text-decoration: none;
266 | color: #222;
267 | }
268 |
269 | #content {
270 | left: 300px;
271 | right: 0;
272 | padding: 20px;
273 | font-size: 20px;
274 | color: #555;
275 | box-shadow: 0px -2px 10px rgba(0,0,0,0.5);
276 | }
277 |
278 | #content a {
279 | color: #444;
280 | }
281 |
282 | #content a:hover {
283 | color: #aaa;
284 | }
285 |
286 | #content h1 {
287 | text-shadow: 0px 1px #000000;
288 | font-size: 60px;
289 | padding-bottom: 0px;
290 | padding-top: 20px;
291 | }
292 |
293 | #content h1:nth-of-type(1){
294 | padding-top: 0;
295 | margin-top: 0;
296 | }
297 |
298 | #content h2 {
299 | padding-top: 15px;
300 | font-size: 40px;
301 | padding-bottom: 0px;
302 | margin-bottom: 10px;
303 | }
304 |
305 | code {
306 | color: #888;
307 | }
--------------------------------------------------------------------------------
/docs/docs/.gitignore:
--------------------------------------------------------------------------------
1 | core
2 | geom
3 | topo
4 | eval
5 | exe
6 |
--------------------------------------------------------------------------------
/docs/docs/index.md:
--------------------------------------------------------------------------------
1 | # verb
2 |
3 | ## What is verb?
4 |
5 | verb is a library for creating and manipulating NURBS surfaces and curves in many languages including JavaScript.
6 |
7 | verb provides advanced tools like derivative evaluation, adaptive tessellation, and intersection. Verb provides a
8 | concurrent execution runtime via WebWorkers in modern browsers and thread pools on other platforms and is suitable
9 | for use in a datacenter or in the browser.
10 |
11 | verb is not a graphics library. It nicely compliments web graphics libraries like three.js, but is happy to live without
12 | one.
13 |
14 | ## How is verb organized?
15 |
16 | The library is split into four parts:
17 |
18 | * **verb.geom** - Geometric types that make it easy to work with NURBS. Includes many commonly used curve and surface types.
19 | * **verb.core** - Mathematical and geometric utilities that are shared throughout the library.
20 | * **verb.eval** - Fundamental NURBS algorithms for evaluation, intersection, analysis, and more.
21 | * **verb.exe** - Tools for managing multi-core evaluation on different platforms.
22 |
23 | **Most people should just use verb.geom.** The other parts provide more powerful features and more direct access to
24 | core parts of the library.
25 |
26 | ## Platforms
27 |
28 | verb compiles for:
29 |
30 | * JavaScript
31 | * C#
32 | * C++
33 | * Python
34 | * PHP
35 |
36 | ## Getting started
37 |
38 | Install haxe and node.js
39 |
40 | You should have installed **haxe** and **node.js**.
41 |
42 | haxe --version
43 |
44 | node --version
45 |
46 | Install node.js dependencies:
47 |
48 | npm install
49 |
50 | Install haxe dependencies:
51 |
52 | haxelib install promhx
53 |
54 | ## Using with JavaScript
55 |
56 | You can install verb with npm
57 |
58 | npm install verb-nurbs
59 |
60 | And immediately use the pre-compiled JavaScript packages found in [build/js](https://github.com/pboyer/verb/blob/master/build/js).
61 |
62 | You can use verb with require.js (AMD) or browserify (commonjs) in the browser or in node.js.
63 |
64 | You'll find many usage examples in the [examples directory](https://github.com/pboyer/verb/blob/master/examples).
65 |
66 | ## Compiling for JavaScript
67 |
68 | Compile to javascript:
69 |
70 | npm run build
71 |
72 | Create both ES and UMD versions of the verb package:
73 |
74 | npm run package
75 |
76 | Run all unit tests:
77 |
78 | npm run test
79 |
80 | ## Compiling for C#
81 |
82 | If you're using OS X, ensure that you have installed XCode 7.
83 |
84 | Install [mono](http://www.mono-project.com/docs/getting-started/install/)
85 |
86 | Install hxcs:
87 |
88 | haxelib install hxcs
89 |
90 | Build:
91 |
92 | haxe buildcs.hxml
93 |
94 | Output goes to build/cs.
95 |
96 | ## Compiling for C++
97 |
98 | If you're using OS X, ensure that you have installed XCode 7.
99 |
100 | Install hxcpp:
101 |
102 | haxelib install hxcpp
103 |
104 | Build:
105 |
106 | haxe buildcpp.hxml
107 |
108 | Output goes to build/cpp.
109 |
110 | ## Compiling for Python
111 |
112 | Make sure python is installed.
113 |
114 | Build:
115 |
116 | haxe buildpython.hxml
117 |
118 | Output goes to build/verb.py
119 |
120 | ## Compiling for PHP
121 |
122 | Build:
123 |
124 | haxe buildphp.hxml
125 |
126 | Output goes to build/php
127 |
128 | ## Compiling for other platforms
129 |
130 | Haxe compiles for other platforms, including Flash and Neko. I have not tried to compile for these platforms - [would you like to contribute?](http://github.com/pboyer/verb)
131 |
132 | ### Compiling for Java
133 |
134 | verb does not currently compile for Java. It probably wouldn't be hard to do - [would you like to contribute?](http://github.com/pboyer/verb)
135 |
136 | ## Using verb with three.js
137 |
138 | You can find good examples of using verb with three in the examples directory. There's an example code showing how
139 | to convert verb geometric types in to three.js Meshes and Lines [in the verb examples](https://github.com/pboyer/verb/blob/master/examples/js/verbToThreeConversion.js).
140 |
--------------------------------------------------------------------------------
/docs/gen.js:
--------------------------------------------------------------------------------
1 | var glob = require('glob')
2 | , mkdirp = require('mkdirp')
3 | , fs = require('fs')
4 | , path = require('path')
5 | , rimraf = require('rimraf')
6 | , _ = require('underscore')
7 | , parseHaxe = require('./parse').parse;
8 |
9 | //
10 | // CONSTANTS
11 | //
12 |
13 | var REPO_URL = "https://github.com/pboyer/verb/";
14 | var TARGET_DIR = __dirname + "/docs";
15 | var SRC = path.resolve(__dirname, "..", "src/verb");
16 | var HX_GLOB = SRC + "/*/*.hx";
17 | var HX_EXT = ".hx";
18 | var MD_EXT = ".md";
19 | var TEMPLATE_SRC = fs.readFileSync(path.join(__dirname, "template.md"), "utf8");
20 | var TEMPLATE = _.template( TEMPLATE_SRC );
21 |
22 | //
23 | // THE ACTUAL SCRIPT
24 | //
25 |
26 | // Remove the existing docs directory, if present
27 |
28 | if (fs.existsSync(TARGET_DIR)) {
29 | console.log("REMOVING TARGET DIRS: ", TARGET_DIR);
30 |
31 | getDirectories(TARGET_DIR)
32 | .map((d) => path.join(TARGET_DIR, d))
33 | .forEach( rmdir );
34 | }
35 |
36 | // Get all of the hx files, and generate their md files
37 |
38 | glob(HX_GLOB, (er, files) => {
39 |
40 | // for each file, generate the corresponding doc file
41 | files.forEach((srcfn) => {
42 | // remove the trailing file name
43 | var cleanfn = srcfn.slice( SRC.length ).slice(0, -HX_EXT.length);
44 |
45 | // build the name of the output file
46 | var outputfn = TARGET_DIR + cleanfn + MD_EXT;
47 |
48 | // make the doc file
49 | gen( srcfn, outputfn );
50 | });
51 | });
52 |
53 | //
54 | // HELPERS
55 | //
56 |
57 | function gen(srcfn, outputfn) {
58 | console.log("GEN: ", outputfn);
59 |
60 | // make the directory (doing nothing if it already exists)
61 | mkdirp.sync( path.dirname( outputfn ) );
62 |
63 | // compile the doc file
64 | compile(srcfn, outputfn);
65 | };
66 |
67 | function compile(srcfn, outputfn){
68 |
69 | var parsed = parseHaxe(srcfn);
70 | if (parsed.length === 0) return;
71 |
72 | var stream = fs.createWriteStream(outputfn);
73 |
74 | // build the url of the file on github
75 | var index0 = srcfn.indexOf("src/verb");
76 | var fn = srcfn.slice( index0 );
77 | var loc = REPO_URL + "blob/master/" + fn + "/"; // verb/Verb.hx/
78 |
79 | var sfn = fn.slice(9, -3);
80 | var index1 = sfn.lastIndexOf("/");
81 | var name = sfn.slice(0, index1);
82 | var index2 = name.lastIndexOf("/");
83 | var namespace = name.slice(0, index1);
84 |
85 | writeln(stream,TEMPLATE({ types: parsed, sourceFile: loc, fn : fn, namespace : namespace }));
86 | stream.end();
87 | }
88 |
89 | function writeln(stream, text){
90 | return stream.write(text+ "\n");
91 | }
92 |
93 | function rmdir(dirpath){
94 | console.log("REMOVING DIRECTORY: ", dirpath);
95 | rimraf.sync(dirpath);
96 | }
97 |
98 | function getDirectories(srcpath) {
99 | return fs.readdirSync(srcpath).filter((file) => {
100 | return fs.statSync(path.join(srcpath, file)).isDirectory();
101 | });
102 | }
103 |
--------------------------------------------------------------------------------
/docs/mkdocs.yml:
--------------------------------------------------------------------------------
1 | site_name: Verb
2 | theme_dir: custom_theme
3 |
--------------------------------------------------------------------------------
/docs/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "verb",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "gen.js",
6 | "directories": {
7 | "doc": "docs"
8 | },
9 | "scripts": {
10 | "test": "echo \"Error: no test specified\" && exit 1"
11 | },
12 | "author": "",
13 | "license": "MIT",
14 | "devDependencies": {
15 | "glob": "^5.0.14",
16 | "mkdirp": "^0.5.1",
17 | "rimraf": "^2.4.3",
18 | "underscore": "^1.8.3"
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/docs/template.md:
--------------------------------------------------------------------------------
1 | <% _.each(types, function(x) { %>
2 |
3 | # <%= x.name %>
4 | `verb.<%= namespace + "." + x.name %>`
5 |
6 | **<%= x.$type.toUpperCase() %>**
7 |
8 | [Source code](<%= sourceFile + "#L" + x.line %>)
9 |
10 | <%= x.$type.toUpperCase() === "TYPEDEF" && x.alias ? "`" + x.name + " = " + x.alias + "`" : "" %>
11 |
12 | <%= x.description %>
13 |
14 | <% if (x.$type === "Class" || x.$type === "Interface") { %>
15 |
16 | <% if (x.parentClass) { %>
17 | **Extends:** [<%= x.parentClass %>]( <%= x.parentClass %>)
18 | <% } %>
19 |
20 | <% if (x.interfaces && x.interfaces.length) { %>
21 | **Implements:** <%= _.map(x.interfaces, function(x){ return "[`" + x + "`](" + x + ")"}).join(", ") %>
22 | <% } %>
23 |
24 | <% _.each(x.methods, function(y) { %>
25 | ## <%= y.name === "new" ? "constructor" : y.name %>
26 | **<%= y.isStatic ? "STATIC " : "" %>METHOD**
27 |
28 | [Source code](<%= sourceFile + "#L" + y.line %>)
29 |
30 | `<%= y.name === "new" ? y.name + " " + x.name : y.name %>(<%= _.map(y.args,function(x){ return x.name + " : " + x.type }).join(", ") %>) <% if (y.returnType) { %>: <%= y.returnType %><% } %>`
31 |
32 | <%= y.description %>
33 | <% }) %>
34 |
35 | <% _.each(x.properties, function(y) { %>
36 | ## <%= y.name %>
37 | **<%= y.isStatic ? "STATIC " : "" %>PROPERTY**
38 |
39 | [Source code](<%= sourceFile + "#L" + y.line %>)
40 |
41 | `<%= y.name %> <% if (y.type) { %>: <%=y.type %><% } %><% if (y.defaultValue) { %> = <%=y.defaultValue %><% } %>`
42 |
43 | <%= (y.description || "").replace(/\n\+/g,"\n*") %>
44 | <% }) %>
45 |
46 | <% } %>
47 |
48 | <% }) %>
49 |
--------------------------------------------------------------------------------
/examples/conics.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Conics
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | Show/Hide Code
23 |
26 |
27 |
28 |
29 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/examples/css/colorforth.css:
--------------------------------------------------------------------------------
1 | .cm-s-colorforth.CodeMirror { background: none; color: #f8f8f8; }
2 | .cm-s-colorforth .CodeMirror-gutters { background: #0a001f; border-right: 1px solid #aaa; }
3 | .cm-s-colorforth .CodeMirror-guttermarker { color: #FFBD40; }
4 | .cm-s-colorforth .CodeMirror-guttermarker-subtle { color: #78846f; }
5 | .cm-s-colorforth .CodeMirror-linenumber { color: #bababa; }
6 | .cm-s-colorforth .CodeMirror-cursor { border-left: 1px solid white; }
7 |
8 | .cm-s-colorforth span.cm-comment { color: #ededed; }
9 | .cm-s-colorforth span.cm-def { color: #ff1c1c; font-weight:bold; }
10 | .cm-s-colorforth span.cm-keyword { color: #ffd900; }
11 | .cm-s-colorforth span.cm-builtin { color: #00d95a; }
12 | .cm-s-colorforth span.cm-variable { color: #73ff00; }
13 | .cm-s-colorforth span.cm-string { color: #007bff; }
14 | .cm-s-colorforth span.cm-number { color: #00c4ff; }
15 | .cm-s-colorforth span.cm-atom { color: #606060; }
16 |
17 | .cm-s-colorforth span.cm-variable-2 { color: #EEE; }
18 | .cm-s-colorforth span.cm-variable-3 { color: #DDD; }
19 | .cm-s-colorforth span.cm-property {}
20 | .cm-s-colorforth span.cm-operator {}
21 |
22 | .cm-s-colorforth span.cm-meta { color: yellow; }
23 | .cm-s-colorforth span.cm-qualifier { color: #FFF700; }
24 | .cm-s-colorforth span.cm-bracket { color: #cc7; }
25 | .cm-s-colorforth span.cm-tag { color: #FFBD40; }
26 | .cm-s-colorforth span.cm-attribute { color: #FFF700; }
27 | .cm-s-colorforth span.cm-error { color: #f00; }
28 |
29 | .cm-s-colorforth div.CodeMirror-selected { background: #333d53; }
30 |
31 | .cm-s-colorforth span.cm-compilation { background: rgba(255, 255, 255, 0.12); }
32 |
33 | .cm-s-colorforth .CodeMirror-activeline-background { background: #253540; }
34 |
--------------------------------------------------------------------------------
/examples/css/example.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | font-family: 'Source Sans Pro', sans-serif;
4 | color: white;
5 | }
6 |
7 | .row, .col { overflow: hidden; position: absolute; }
8 | .row { left: 0; right: 0; }
9 | .col { top: 0; bottom: 0; }
10 | .scroll-x { overflow-x: auto; }
11 | .scroll-y { overflow-y: auto; }
12 |
13 | #viewer {
14 | left: 0;
15 | right: 0;
16 | }
17 |
18 | #button {
19 | font-size: 15px;
20 | color: white;
21 | position: absolute;
22 | background: green;
23 | bottom: 20px;
24 | padding: 10px;
25 | left: 20px;
26 | z-index: 2;
27 | }
28 |
29 | #button:hover{
30 | background: grey;
31 | }
32 |
33 | #title {
34 | font-size: 40px;
35 | position: absolute;
36 | top: 20px;
37 | left: 20px;
38 | text-shadow: 0px 2px black;
39 | }
40 |
41 | #code-container {
42 | padding: 20px;
43 | background: rgba(0,0,0,0.75);
44 | right: 0;
45 | left: 0;
46 | }
47 |
48 | #code {
49 | font-size: 10px;
50 | padding: 10px;
51 | margin: 10px;
52 | top: 80px;
53 | bottom: 0;
54 | resize: none;
55 | width: 650px;
56 | border: 0;
57 | }
58 |
59 | .CodeMirror {
60 | height: auto;
61 | }
--------------------------------------------------------------------------------
/examples/curveByPointInterpolation.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Curve by Point Interpolation
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | Show/Hide Code
23 |
26 |
27 |
28 |
29 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/examples/curveClosestPoint.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Curve Closest Point
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | Show/Hide Code
23 |
26 |
27 |
28 |
29 |
30 |
70 |
71 |
72 |
73 |
--------------------------------------------------------------------------------
/examples/curveDivide.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Divide A Curve By Equal Arc Length
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | Show/Hide Code
23 |
26 |
27 |
28 |
29 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/examples/curveIntersection.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Curve-Curve Intersection
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | Show/Hide Code
23 |
26 |
27 |
28 |
29 |
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/examples/curveReverse.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Curve Reversal
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | Show/Hide Code
23 |
26 |
27 |
28 |
29 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/examples/curveSplit.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Splitting a Curve
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | Show/Hide Code
23 |
26 |
27 |
28 |
29 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/examples/cylindricalSurface.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Cylindrical Surface
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | Show/Hide Code
23 |
26 |
27 |
28 |
29 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/examples/extrudedSurface.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Extruded Surface
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | Show/Hide Code
23 |
26 |
27 |
28 |
29 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/examples/js/example.js:
--------------------------------------------------------------------------------
1 |
2 | var codecontainer = document.getElementById("code-container");
3 | codecontainer.innerHTML += '';
4 |
5 | var title = document.getElementById("title");
6 | title.innerHTML += document.title;
7 |
8 | var code = document.getElementById("code");
9 | code.innerHTML = document.getElementById("script").innerHTML;
10 |
11 | var codemirror = CodeMirror.fromTextArea(code, {
12 | mode : "javascript",
13 | readOnly : true,
14 | "theme" : "colorforth"
15 | });
16 |
17 | codecontainer.style.display='none';
18 |
19 | var button = document.getElementById("button");
20 | var isHidden = true;
21 | button.addEventListener("click", function(){
22 | if (isHidden){
23 | codecontainer.style.display='block';
24 | isHidden = false;
25 | } else {
26 | codecontainer.style.display='none';
27 | isHidden = true;
28 | }
29 | });
30 |
--------------------------------------------------------------------------------
/examples/js/threeBasic.js:
--------------------------------------------------------------------------------
1 | // Some helper methods for the examples
2 |
3 | var scene, camera, renderer;
4 |
5 | var raycaster = new THREE.Raycaster();
6 | var mouse = new THREE.Vector2();
7 |
8 | raycaster.lineprecision = 0.00001;
9 | raycaster.precision = 0.001;
10 |
11 | function onMouseMove( event ) {
12 |
13 | // calculate mouse position in normalized device coordinates
14 | // (-1 to +1) for both components
15 |
16 | mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
17 | mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
18 |
19 | }
20 |
21 | window.addEventListener( 'mousemove', onMouseMove, false );
22 |
23 | function setupScene(doUseRaycaster){
24 | useRaycaster = doUseRaycaster;
25 |
26 | scene = new THREE.Scene();
27 |
28 | camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
29 | camera.lookAt(20,-20,0);
30 | camera.position.x = 30;
31 | camera.position.y = -30;
32 | camera.position.z = 10;
33 |
34 | camera.up.set( 0, 0, 1 );
35 |
36 | renderer = new THREE.WebGLRenderer({ antialias: true });
37 | renderer.setSize( window.innerWidth, window.innerHeight );
38 |
39 | var viewerele = document.getElementById("viewer");
40 |
41 | viewerele.appendChild( renderer.domElement );
42 |
43 | var ambientLight = new THREE.AmbientLight( 0xbbbbbb );
44 | scene.add( ambientLight );
45 |
46 | var lights = [];
47 | lights[0] = new THREE.PointLight( 0xececec, 0.25, 0 );
48 | lights[1] = new THREE.PointLight( 0xececec, 0.25, 0 );
49 | lights[2] = new THREE.PointLight( 0xececec, 0.25, 0 );
50 |
51 | lights[0].position.set( 0, 100, 0 );
52 | lights[1].position.set( 100, 200, 100 );
53 | lights[2].position.set( -100, -200, -100 );
54 |
55 | scene.add( lights[0] );
56 | scene.add( lights[1] );
57 | scene.add( lights[2] );
58 | }
59 |
60 | var intersects = [];
61 |
62 | function renderScene(){
63 | var controls = new THREE.OrbitControls(camera, renderer.domElement);
64 |
65 | function render() {
66 | if (useRaycaster){
67 |
68 | // update the picking ray with the camera and mouse position
69 | raycaster.setFromCamera( mouse, camera );
70 |
71 | // clear color
72 | for ( var i = 0; i < intersects.length; i++ ) {
73 | if (!intersects[ i ].object.material.color) continue;
74 | intersects[ i ].object.material.color.set( 0xffffff );
75 | }
76 |
77 | // calculate objects intersecting the picking ray
78 | intersects = raycaster.intersectObjects( scene.children );
79 |
80 | for ( var i = 0; i < intersects.length; i++ ) {
81 | if (!intersects[ i ].object.material.color) continue;
82 | intersects[ i ].object.material.color.set( 0xff0000 );
83 | }
84 | }
85 |
86 | requestAnimationFrame( render );
87 | renderer.render( scene, camera );
88 | }
89 | render();
90 | }
91 |
92 | function addCurveToScene(geom, material){
93 | material = material || new THREE.LineBasicMaterial({ linewidth: 2, color: 0xdcdcdc});
94 | scene.add( new THREE.Line( geom, material ) );
95 | }
96 |
97 | function addLineToScene(pts, mat){
98 | addCurveToScene(asGeometry(asVector3(pts)), mat);
99 | }
100 |
101 | function addMeshToScene(mesh, material, wireframe ){
102 | material = material || new THREE.MeshNormalMaterial( { side: THREE.DoubleSide, wireframe: false, shading: THREE.SmoothShading, transparent: true, opacity: 0.4 } )
103 |
104 | // new THREE.MeshPhongMaterial({
105 | // specular: '#ffffff',
106 | // color: '#8e8e8e',
107 | // side: THREE.DoubleSide,
108 | // ambient: '#ffffff',
109 | // emissive: '#111111',
110 | // shininess: 40
111 | // });
112 |
113 | scene.add( new THREE.Mesh( mesh, material ) );
114 |
115 | if (wireframe){
116 | var material2 = new THREE.MeshBasicMaterial( { color: 0x000000, side: THREE.DoubleSide, wireframe: true } );
117 | var mesh2 = new THREE.Mesh( mesh, material2 );
118 | scene.add( mesh2 );
119 | }
120 | }
121 |
122 | function asVector3(pts){
123 | return pts.map(function(x){
124 | return new THREE.Vector3(x[0],x[1],x[2]);
125 | });
126 | }
127 |
128 | function asGeometry(threePts){
129 | var geometry = new THREE.Geometry();
130 | geometry.vertices.push.apply( geometry.vertices, threePts );
131 | return geometry;
132 | }
133 |
134 | function benchmark(func, runs){
135 | var d1 = Date.now();
136 | for (var i = 0 ; i < runs; i++)
137 | res = func();
138 | var d2 = Date.now();
139 | return { result : res, elapsed : d2-d1, each : (d2-d1)/runs };
140 | }
141 |
142 | function pointsAsGeometry(pts){
143 | return asGeometry( asVector3(pts) )
144 | }
145 |
146 | function addPointsToScene(pts){
147 |
148 | var geom = asGeometry( asVector3( pts ) );
149 | var cloudMat2 = new THREE.PointCloudMaterial({ size: 6.5, sizeAttenuation: false, color: 0xffffff });
150 | var cloud2 = new THREE.PointCloud( geom, cloudMat2 );
151 |
152 | scene.add( cloud2 );
153 | }
154 |
155 |
--------------------------------------------------------------------------------
/examples/js/verbToThreeConversion.js:
--------------------------------------------------------------------------------
1 | // Utility methods to support converting verb.geom types to THREE.Geometry
2 |
3 | (function(verb){
4 |
5 | verb.geom.NurbsCurve.prototype.toThreeGeometry = function(){
6 | return tessellateCurve( this );
7 | }
8 |
9 | verb.geom.NurbsSurface.prototype.toThreeGeometry = function(){
10 | return tessellateSurface( this );
11 | }
12 |
13 | function asVector3(pts){
14 | return pts.map(function(x){
15 | return new THREE.Vector3(x[0],x[1],x[2]);
16 | });
17 | }
18 |
19 | function tessellateCurve( curve ){
20 | var geometry = new THREE.Geometry();
21 | geometry.vertices = asVector3( curve.tessellate() );
22 | return geometry;
23 | }
24 |
25 | function tessellateSurface(srf) {
26 |
27 | var tess = srf.tessellate();
28 |
29 | var geometry = new THREE.Geometry();
30 |
31 | geometry.vertices = asVector3( tess.points );
32 |
33 | geometry.faces = tess.faces.map(function(faceIndices){
34 | var normals = faceIndices.map(function(x){
35 | var vn = tess.normals[x];
36 | return new THREE.Vector3( vn[0], vn[1], vn[2] );
37 | });
38 |
39 | return new THREE.Face3(faceIndices[0],faceIndices[1],faceIndices[2], normals);
40 | });
41 |
42 | return geometry;
43 | }
44 |
45 | })(verb);
--------------------------------------------------------------------------------
/examples/loftedSurface.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Surface Lofting
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | Show/Hide Code
23 |
26 |
27 |
28 |
29 |
46 |
47 |
--------------------------------------------------------------------------------
/examples/meshIntersection.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Mesh-Mesh Intersection
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | Show/Hide Code
23 |
26 |
27 |
28 |
29 |
209 |
210 |
211 |
--------------------------------------------------------------------------------
/examples/meshSlicing.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Mesh Slicing
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | Show/Hide Code
23 |
26 |
27 |
28 |
29 |
72 |
73 |
74 |
75 |
--------------------------------------------------------------------------------
/examples/revolvedSurface.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Revolved Surface
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | Show/Hide Code
23 |
26 |
27 |
28 |
29 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/examples/surface.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | NURBS Surface
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | Show/Hide Code
23 |
26 |
27 |
28 |
29 |
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/examples/surfaceAdaptiveTessellation.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Adaptive surface tessellation
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | Show/Hide Code
23 |
26 |
27 |
28 |
29 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/examples/surfaceBoundaries.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Surface Boundary Curves
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | Show/Hide Code
23 |
26 |
27 |
28 |
29 |
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/examples/surfaceClosestPoint.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Closest Point to a Surface
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | Show/Hide Code
23 |
26 |
27 |
28 |
29 |
67 |
68 |
69 |
70 |
--------------------------------------------------------------------------------
/examples/surfaceIntersection.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Surface-Surface Intersection
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | Show/Hide Code
23 |
26 |
27 |
28 |
29 |
140 |
141 |
142 |
143 |
144 |
--------------------------------------------------------------------------------
/examples/surfaceIsocurves.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Surface Isocurve Extraction
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | Show/Hide Code
23 |
26 |
27 |
28 |
29 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/examples/surfaceSplit.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Splitting a Surface
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | Show/Hide Code
23 |
26 |
27 |
28 |
29 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/examples/sweptSurface.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Swept Surface
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | Show/Hide Code
23 |
26 |
27 |
28 |
29 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "verb-nurbs",
3 | "version": "3.0.3",
4 | "author": "pboyer ",
5 | "description": "A library for creating and manipulating NURBS surfaces and curves in many languages",
6 | "repository": {
7 | "type": "git",
8 | "url": "https://github.com/pboyer/verb.git"
9 | },
10 | "main": "build/js/verb.js",
11 | "unpkg": "build/js/verb.min.js",
12 | "module": "build/js//verb.es.js",
13 | "scripts": {
14 | "build": "haxe buildjs.hxml",
15 | "package": "rollup --config",
16 | "test": "mocha"
17 | },
18 | "keywords": [
19 | "NURBS",
20 | "geometry",
21 | "cad",
22 | "surface",
23 | "curve",
24 | "spline",
25 | "mesh"
26 | ],
27 | "files": [
28 | "LICENSE",
29 | "README.md",
30 | "build",
31 | "buildcpp.hxml",
32 | "buildcs.hxml",
33 | "buildjs.hxml",
34 | "buildphp.hxml",
35 | "buildpython.hxml",
36 | "examples",
37 | "package-lock.json",
38 | "package.json",
39 | "rollup.config.mjs",
40 | "src",
41 | "test",
42 | "verb.iml"
43 | ],
44 | "dependencies": {
45 | "web-worker": "^1.3.0"
46 | },
47 | "devDependencies": {
48 | "@rollup/plugin-commonjs": "^26.0.1",
49 | "@rollup/plugin-node-resolve": "^15.2.3",
50 | "@rollup/plugin-terser": "^0.4.4",
51 | "mocha": "^10.6.0",
52 | "rollup": "^4.18.0",
53 | "rollup-plugin-polyfill-node": "^0.13.0",
54 | "should": "^13.2.3"
55 | },
56 | "license": "MIT"
57 | }
58 |
--------------------------------------------------------------------------------
/rollup.config.mjs:
--------------------------------------------------------------------------------
1 | import commonjs from '@rollup/plugin-commonjs'
2 | import nodePolyfills from 'rollup-plugin-polyfill-node';
3 | import terser from '@rollup/plugin-terser'
4 | import { nodeResolve } from '@rollup/plugin-node-resolve'
5 |
6 | export default {
7 | external: 'web-worker',
8 | input: 'build/js/verb.js',
9 | output: [
10 | {
11 | file: 'build/js/verb.min.js',
12 | format: 'umd',
13 | name: 'verb',
14 | },
15 | {
16 | file: 'build/js/verb.es.js',
17 | format: 'es',
18 | }
19 | ],
20 | plugins: [
21 | nodeResolve(),
22 | commonjs(),
23 | nodePolyfills( /* options */ )
24 | ]
25 | }
26 |
--------------------------------------------------------------------------------
/site/css/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | font-family: 'Source Sans Pro', sans-serif;
3 | font-size: 14px;
4 | margin: 0 auto;
5 | background: black;
6 | }
7 |
8 | #title-box {
9 | background: #DD5500;
10 | text-align: right;
11 | }
12 |
13 | #title-box .inner-box {
14 | padding-top: 0px;
15 | }
16 |
17 | #title-box h1 {
18 | padding: none;
19 | margin: none;
20 | font-size: 60px;
21 | }
22 |
23 | #source-box {
24 | background: #B10064;
25 | }
26 |
27 | #docs-box {
28 | background: #008E6E;
29 | }
30 |
31 | #download-box {
32 | background: #89CE00;
33 | }
34 |
35 | .box {
36 | position: relative;
37 | flex-grow: 1;
38 | overflow: hidden;
39 | color: white;
40 | height: 300px;
41 | width: 300px;
42 | text-shadow: 0px 1px #000000;
43 | }
44 |
45 | .box h1 {
46 | font-size: 40px;
47 | }
48 |
49 | .box a {
50 | color: white;
51 | text-decoration: none;
52 | }
53 |
54 | .inner-box {
55 | padding: 30px;
56 | height: 100%;
57 | width: 100%;
58 | box-sizing: border-box;
59 | }
60 |
61 | .link-box:hover {
62 | background: #222 !important;
63 | }
64 |
65 | .examples {
66 | background-color: black;
67 | display: flex;
68 | align-content: flex-start;
69 | flex-wrap: wrap;
70 | }
71 |
72 | .box img {
73 | position: absolute;
74 | width: 100%;
75 | }
76 |
77 | .picture-box {
78 | font-size: 28px;
79 | z-index: 2;
80 | position: absolute;
81 | padding: 30px;
82 | height: 100%;
83 | width: 100%;
84 | box-sizing: border-box;
85 | background: rgba(20,20,20,0.8);
86 | opacity: 0;
87 | }
88 |
89 | .picture-box:hover {
90 | opacity: 1.0;
91 | }
--------------------------------------------------------------------------------
/site/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | verb - Open-source, cross-platform NURBS
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
verb2.1.0
16 | Open-source, cross-platform NURBS
17 |
18 |
19 |
25 |
31 |
38 |
44 |
48 |
55 |
59 |
63 |
67 |
71 |
78 |
82 |
86 |
90 |
94 |
98 |
102 |
106 |
110 |
114 |
118 |
122 |
126 |
127 |
128 |
129 |
139 |
140 |
141 |
142 |
143 |
--------------------------------------------------------------------------------
/site/pictures/conics.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pboyer/verb/f3ba23cdccbab77102b686021460cf9779df240f/site/pictures/conics.png
--------------------------------------------------------------------------------
/site/pictures/curveByPointInterpolation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pboyer/verb/f3ba23cdccbab77102b686021460cf9779df240f/site/pictures/curveByPointInterpolation.png
--------------------------------------------------------------------------------
/site/pictures/curveClosestPoint.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pboyer/verb/f3ba23cdccbab77102b686021460cf9779df240f/site/pictures/curveClosestPoint.png
--------------------------------------------------------------------------------
/site/pictures/curveDivide.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pboyer/verb/f3ba23cdccbab77102b686021460cf9779df240f/site/pictures/curveDivide.png
--------------------------------------------------------------------------------
/site/pictures/curveIntersection.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pboyer/verb/f3ba23cdccbab77102b686021460cf9779df240f/site/pictures/curveIntersection.png
--------------------------------------------------------------------------------
/site/pictures/curveSplit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pboyer/verb/f3ba23cdccbab77102b686021460cf9779df240f/site/pictures/curveSplit.png
--------------------------------------------------------------------------------
/site/pictures/cylindricalSurface.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pboyer/verb/f3ba23cdccbab77102b686021460cf9779df240f/site/pictures/cylindricalSurface.png
--------------------------------------------------------------------------------
/site/pictures/extrudedSurface.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pboyer/verb/f3ba23cdccbab77102b686021460cf9779df240f/site/pictures/extrudedSurface.png
--------------------------------------------------------------------------------
/site/pictures/loftedSurface.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pboyer/verb/f3ba23cdccbab77102b686021460cf9779df240f/site/pictures/loftedSurface.png
--------------------------------------------------------------------------------
/site/pictures/meshIntersection.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pboyer/verb/f3ba23cdccbab77102b686021460cf9779df240f/site/pictures/meshIntersection.png
--------------------------------------------------------------------------------
/site/pictures/meshSlicing.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pboyer/verb/f3ba23cdccbab77102b686021460cf9779df240f/site/pictures/meshSlicing.png
--------------------------------------------------------------------------------
/site/pictures/revolvedSurface.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pboyer/verb/f3ba23cdccbab77102b686021460cf9779df240f/site/pictures/revolvedSurface.png
--------------------------------------------------------------------------------
/site/pictures/surface.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pboyer/verb/f3ba23cdccbab77102b686021460cf9779df240f/site/pictures/surface.png
--------------------------------------------------------------------------------
/site/pictures/surfaceAdaptiveTessellation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pboyer/verb/f3ba23cdccbab77102b686021460cf9779df240f/site/pictures/surfaceAdaptiveTessellation.png
--------------------------------------------------------------------------------
/site/pictures/surfaceBoundaries.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pboyer/verb/f3ba23cdccbab77102b686021460cf9779df240f/site/pictures/surfaceBoundaries.png
--------------------------------------------------------------------------------
/site/pictures/surfaceClosestPoint.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pboyer/verb/f3ba23cdccbab77102b686021460cf9779df240f/site/pictures/surfaceClosestPoint.png
--------------------------------------------------------------------------------
/site/pictures/surfaceIntersection.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pboyer/verb/f3ba23cdccbab77102b686021460cf9779df240f/site/pictures/surfaceIntersection.png
--------------------------------------------------------------------------------
/site/pictures/surfaceIsocurves.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pboyer/verb/f3ba23cdccbab77102b686021460cf9779df240f/site/pictures/surfaceIsocurves.png
--------------------------------------------------------------------------------
/site/pictures/surfaceSplit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pboyer/verb/f3ba23cdccbab77102b686021460cf9779df240f/site/pictures/surfaceSplit.png
--------------------------------------------------------------------------------
/site/pictures/sweptSurface.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pboyer/verb/f3ba23cdccbab77102b686021460cf9779df240f/site/pictures/sweptSurface.png
--------------------------------------------------------------------------------
/src/support/footer.js:
--------------------------------------------------------------------------------
1 |
2 | return verb;
3 |
4 | });
--------------------------------------------------------------------------------
/src/support/header.js:
--------------------------------------------------------------------------------
1 | // Header for verb for JavaScript
2 | // Borrowed from browserify, this header supports AMD (define) and common js (require) style modules
3 |
4 | (function(f){
5 | if(typeof exports==="object"&&typeof module!=="undefined"){
6 | module.exports=f()
7 | } else if(typeof define==="function"&&define.amd){
8 | define([],f)
9 | } else {
10 | var g;
11 | if(typeof window!=="undefined"){
12 | g=window
13 | } else if(typeof global!=="undefined"){
14 | g=global
15 | } else if(typeof self!=="undefined"){
16 | g=self
17 | } else{
18 | g=this
19 | }
20 |
21 | g.verb = f()
22 | }
23 | })(function(){
24 | var verb = {};
25 |
26 | var global = this;
27 |
28 | var isBrowser = new Function("try {return this===window;}catch(e){ return false;}");
29 | var isNode=new Function("try {return this===global;}catch(e){return false;}");
30 | var isWebworker=new Function("try {return typeof importScripts === 'function';}catch(e){return false;}");
31 |
32 | // node.js context, but not WebWorker
33 | if ( isNode() && !isWebworker() ){
34 | Worker = require('webworker-threads').Worker;
35 | }
36 |
37 | // WebWorker or node.js context
38 | if ( isNode() || isWebworker() ){
39 |
40 | var window = global; // required for promhx
41 |
42 | // WebWorker
43 | if ( isWebworker() ){
44 |
45 | var lookup = function(className, methodName){
46 |
47 | var obj = global;
48 |
49 | className.split(".").forEach(function(x){
50 | if (obj) obj = obj[ x ];
51 | });
52 |
53 | if (!obj) return null;
54 |
55 | return obj[ methodName ];
56 | }
57 |
58 | onmessage = function( e ){
59 |
60 | if (!e.data.className || !e.data.methodName) return;
61 |
62 | var method = lookup( e.data.className, e.data.methodName );
63 |
64 | if (!method){
65 | return console.error("could not find " + e.data.className + "." + e.data.methodName)
66 | }
67 |
68 | postMessage( { result: method.apply( null, e.data.args ), id: e.data.id } );
69 |
70 | };
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/src/verb/Verb.hx:
--------------------------------------------------------------------------------
1 | package verb;
2 |
3 | // constants
4 | import verb.core.Constants;
5 |
6 | // geom
7 |
8 | import verb.geom.NurbsCurve;
9 | import verb.geom.Arc;
10 | import verb.geom.Line;
11 | import verb.geom.BezierCurve;
12 | import verb.geom.Circle;
13 | import verb.geom.Ellipse;
14 | import verb.geom.EllipseArc;
15 | import verb.geom.NurbsSurface;
16 | import verb.geom.SphericalSurface;
17 | import verb.geom.RevolvedSurface;
18 | import verb.geom.ExtrudedSurface;
19 | import verb.geom.CylindricalSurface;
20 | import verb.geom.ConicalSurface;
21 | import verb.geom.SweptSurface;
22 | import verb.geom.Intersect;
23 |
24 | // core
25 |
26 | import verb.core.Serialization;
27 | import verb.core.BoundingBox;
28 | import verb.core.Constants;
29 | import verb.core.Trig;
30 | import verb.core.Minimizer;
31 | import verb.core.ArrayExtensions;
32 | import verb.core.Mesh;
33 | import verb.core.KdTree;
34 |
35 | // eval
36 |
37 | import verb.eval.Eval;
38 | import verb.eval.Intersect;
39 | import verb.eval.Tess;
40 | import verb.eval.Make;
41 | import verb.eval.Modify;
42 | import verb.eval.Analyze;
43 | import verb.eval.Divide;
44 | import verb.eval.Check;
45 |
46 | class Verb {
47 | public static function main():Void {
48 | trace(Constants.VERSION);
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/verb/core/ArrayExtensions.hx:
--------------------------------------------------------------------------------
1 | package verb.core;
2 |
3 | class ArrayExtensions {
4 |
5 | //Fill an array with n copies of null by mutation
6 | //
7 | //**params**
8 | //
9 | //* the array to fill
10 | //* the number of null's to add to the array
11 | //
12 | //**returns**
13 | //
14 | //* nothing, just mutates the given array
15 |
16 | public static function alloc( a : Array, n : Int ){
17 | if (n < 0) return;
18 | while (a.length < n) {
19 | a.push(null);
20 | }
21 | }
22 |
23 | //Obtain a reversed copy of an array
24 | //
25 | //**params**
26 | //
27 | //* array of stuff
28 | //
29 | //**returns**
30 | //
31 | //* a reversed copy of the array
32 |
33 | public static function reversed(a : Array) : Array {
34 | var ac = a.copy();
35 | ac.reverse();
36 | return ac;
37 | }
38 |
39 | //Get the last element of an array
40 | //
41 | //**params**
42 | //
43 | //* array of stuff
44 | //
45 | //**returns**
46 | //
47 | //* the last element of the array
48 |
49 | public static function last(a : Array) : T {
50 | return a[a.length-1];
51 | }
52 |
53 | //Get the first element of an array
54 | //
55 | //**params**
56 | //
57 | //* array of stuff
58 | //
59 | //**returns**
60 | //
61 | //* the last element of the array
62 |
63 | public static function first(a : Array) : T {
64 | return a[0];
65 | }
66 |
67 | public static function spliceAndInsert(a : Array, start : Int, end : Int, ele : T) : Void {
68 | a.splice(start, end);
69 | a.insert(start, ele);
70 | }
71 |
72 | //Get the first half of an array including the pivot
73 | //
74 | //**params**
75 | //
76 | //* array of stuff
77 | //
78 | //**returns**
79 | //
80 | //* the left half
81 |
82 | public static function left(arr : Array) : Array{
83 | if (arr.length == 0) return [];
84 | var len = Math.ceil( arr.length / 2 );
85 | return arr.slice( 0, len );
86 | }
87 |
88 | //Get the second half of an array, not including the pivot
89 | //
90 | //**params**
91 | //
92 | //* array of stuff
93 | //
94 | //**returns**
95 | //
96 | //* the right half
97 |
98 | public static function right(arr : Array) : Array{
99 | if (arr.length == 0) return [];
100 | var len = Math.ceil( arr.length / 2 );
101 | return arr.slice( len );
102 | }
103 |
104 | //Get the second half of an array including the pivot
105 | //
106 | //**params**
107 | //
108 | //* array of stuff
109 | //
110 | //**returns**
111 | //
112 | //* the right half
113 |
114 | public static function rightWithPivot(arr : Array) : Array{
115 | if (arr.length == 0) return [];
116 | var len = Math.ceil( arr.length / 2 );
117 | return arr.slice( len-1 );
118 | }
119 |
120 | //Obtain the unique set of elements in an array
121 | //
122 | //**params**
123 | //
124 | //* array of stuff
125 | //* *Function*, a function that receives two arguments (two objects from the array). Returning true indicates
126 | //the objects are equal.
127 | //
128 | //**returns**
129 | //
130 | //* array of unique elements
131 |
132 | public static function unique( arr : Array, comp : T -> T -> Bool ){
133 |
134 | if (arr.length == 0) return [];
135 |
136 | var uniques = [ arr.pop() ];
137 |
138 | while (arr.length > 0){
139 |
140 | var ele = arr.pop();
141 | var isUnique = true;
142 |
143 | for (unique in uniques){
144 | if ( comp( ele, unique ) ){
145 | isUnique = false;
146 | break;
147 | }
148 | }
149 |
150 | if ( isUnique ){
151 | uniques.push( ele );
152 | }
153 | }
154 |
155 | return uniques;
156 | }
157 |
158 | }
159 |
--------------------------------------------------------------------------------
/src/verb/core/Binomial.hx:
--------------------------------------------------------------------------------
1 | package verb.core;
2 |
3 | import haxe.ds.IntMap;
4 |
5 | class Binomial {
6 |
7 | static var memo = new IntMap>();
8 |
9 | public static function get(n : Int, k : Int) : Float {
10 | if (k == 0.0) {
11 | return 1.0;
12 | }
13 |
14 | if (n == 0 || k > n) {
15 | return 0.0;
16 | }
17 |
18 | if (k > n - k) {
19 | k = n - k;
20 | }
21 |
22 | if ( memo_exists(n,k) ) {
23 | return get_memo(n,k);
24 | }
25 |
26 | var r : Float = 1,
27 | n_o = n;
28 |
29 | for (d in 1...k+1){
30 |
31 | if ( memo_exists(n_o, d) ) {
32 | n--;
33 | r = get_memo(n_o, d);
34 | continue;
35 | }
36 |
37 | r *= n--;
38 | r /= d;
39 |
40 | memoize(n_o, d, r);
41 |
42 | }
43 |
44 | return r;
45 | }
46 |
47 | public static function get_no_memo(n : Int, k : Int) : Float {
48 | if (k == 0) {
49 | return 1;
50 | }
51 |
52 | if (n == 0 || k > n) {
53 | return 0;
54 | }
55 |
56 | if (k > n - k) {
57 | k = n - k;
58 | }
59 |
60 | var r : Float = 1,
61 | n_o = n;
62 |
63 | for (d in 1...k+1){
64 | r *= n--;
65 | r /= d;
66 | }
67 |
68 | return r;
69 | }
70 |
71 | private static function memo_exists(n : Int, k : Int) : Bool {
72 | return ( memo.exists(n) && memo.get(n).exists(k) );
73 | }
74 |
75 | private static function get_memo(n : Int, k : Int) : Float {
76 | return memo.get(n).get(k);
77 | }
78 |
79 | private static function memoize(n, k, val) {
80 | if ( !memo.exists(n) ) {
81 | memo.set( n, new IntMap() );
82 | }
83 |
84 | memo.get( n ).set( k, val );
85 | }
86 | }
--------------------------------------------------------------------------------
/src/verb/core/BoundingBox.hx:
--------------------------------------------------------------------------------
1 | package verb.core;
2 |
3 | import verb.core.Data;
4 |
5 | using Lambda;
6 |
7 | // `BoundingBox` is an n-dimensional bounding box implementation. It is used by many of verb's intersection algorithms.
8 | //
9 | // The first point added to the `BoundingBox` using `BoundingBox.add` will be used to define the dimensionality of the
10 | // bounding box.
11 |
12 | @:expose("core.BoundingBox")
13 | class BoundingBox {
14 |
15 | var initialized : Bool = false;
16 | var dim : Int = 3;
17 |
18 | //BoundingBox Constructor
19 | //
20 | //**params**
21 | //
22 | //* Points to add, if desired. Otherwise, will not be initialized until add is called.
23 |
24 | public function new( pts : Array = null ) {
25 | if ( pts != null ) {
26 | this.addRange( pts );
27 | }
28 | }
29 |
30 | // The minimum point of the BoundingBox - the coordinates of this point are always <= max.
31 | public var min : Point = null;
32 |
33 | // The maximum point of the BoundingBox. The coordinates of this point are always >= min.
34 | public var max : Point = null;
35 |
36 | //Create a bounding box initialized with a single element
37 | //
38 | //**params**
39 | //
40 | //* A array of numbers
41 | //
42 | //**returns**
43 | //
44 | //* This BoundingBox for chaining
45 |
46 | public function fromPoint( pt ){
47 | return new BoundingBox( [ pt ] );
48 | }
49 |
50 | //Adds a point to the bounding box, expanding the bounding box if the point is outside of it.
51 | //If the bounding box is not initialized, this method has that side effect.
52 | //
53 | //**params**
54 | //
55 | //* A length-n array of numbers
56 | //
57 | //**returns**
58 | //
59 | //* This BoundingBox for chaining
60 |
61 | public function add( point : Point ) : BoundingBox
62 | {
63 | if ( !this.initialized )
64 | {
65 | this.dim = point.length;
66 | this.min = point.slice(0);
67 | this.max = point.slice(0);
68 | this.initialized = true;
69 |
70 | return this;
71 | }
72 |
73 | for (i in 0...this.dim){
74 | if (point[i] > this.max[i] ) this.max[i] = point[i];
75 | if (point[i] < this.min[i] ) this.min[i] = point[i];
76 | }
77 |
78 | return this;
79 |
80 | }
81 |
82 | //Asynchronously add an array of points to the bounding box
83 | //
84 | //**params**
85 | //
86 | //* An array of length-n array of numbers
87 | //
88 | //**returns**
89 | //
90 | //* this BoundingBox for chaining
91 |
92 | public function addRange( points : Array ) : BoundingBox
93 | {
94 | var l = points.length;
95 |
96 | for (i in 0...l){
97 | this.add(points[i]);
98 | }
99 |
100 | return this;
101 | }
102 |
103 | //Determines if point is contained in the bounding box
104 | //
105 | //**params**
106 | //
107 | //* the point
108 | //* the tolerance
109 | //
110 | //**returns**
111 | //
112 | //* true if the two intervals overlap, otherwise false
113 |
114 | public function contains(point : Point, tol : Float = -1) : Bool {
115 |
116 | if ( !this.initialized )
117 | {
118 | return false;
119 | }
120 |
121 | return this.intersects( new BoundingBox([point]), tol );
122 | }
123 |
124 | //Determines if two intervals on the real number line intersect
125 | //
126 | //**params**
127 | //
128 | //* Beginning of first interval
129 | //* End of first interval
130 | //* Beginning of second interval
131 | //* End of second interval
132 | //
133 | //**returns**
134 | //
135 | //* true if the two intervals overlap, otherwise false
136 |
137 | public static function intervalsOverlap( a1 : Float, a2: Float, b1: Float, b2: Float, tol : Float = -1 ) : Bool {
138 |
139 | var tol = tol < -0.5 ? Constants.TOLERANCE : tol
140 | , x1 = Math.min(a1, a2) - tol
141 | , x2 = Math.max(a1, a2) + tol
142 | , y1 = Math.min(b1, b2) - tol
143 | , y2 = Math.max(b1, b2) + tol;
144 |
145 | return (x1 >= y1 && x1 <= y2) || (x2 >= y1 && x2 <= y2) || (y1 >= x1 && y1 <= x2) || (y2 >= x1 && y2 <= x2) ;
146 | }
147 |
148 | //Determines if this bounding box intersects with another
149 | //
150 | //**params**
151 | //
152 | //* BoundingBox to check for intersection with this one
153 | //
154 | //**returns**
155 | //
156 | //* true if the two bounding boxes intersect, otherwise false
157 |
158 | public function intersects( bb : BoundingBox, tol : Float = -1 ) : Bool {
159 |
160 | if ( !this.initialized || !bb.initialized ) return false;
161 |
162 | var a1 = min
163 | , a2 = max
164 | , b1 = bb.min
165 | , b2 = bb.max;
166 |
167 | for (i in 0...dim){
168 | if (!intervalsOverlap(a1[i], a2[i], b1[i], b2[i], tol )) return false;
169 | }
170 |
171 | return true;
172 | }
173 |
174 | //Clear the bounding box, leaving it in an uninitialized state. Call add, addRange in order to
175 | //initialize
176 | //
177 | //**returns**
178 | //
179 | //* this BoundingBox for chaining
180 |
181 | public function clear() : BoundingBox {
182 | this.initialized = false;
183 | return this;
184 | }
185 |
186 | //Get longest axis of bounding box
187 | //
188 | //**returns**
189 | //
190 | //* Index of longest axis
191 |
192 | public function getLongestAxis() : Int {
193 |
194 | var max = 0.0;
195 | var id = 0;
196 |
197 | for ( i in 0...dim ){
198 | var l = this.getAxisLength(i);
199 | if (l > max) {
200 | max = l;
201 | id = i;
202 | }
203 | }
204 |
205 | return id;
206 | }
207 |
208 | //Get length of given axis.
209 | //
210 | //**params**
211 | //
212 | //* Index of axis to inspect (between 0 and 2)
213 | //
214 | //**returns**
215 | //
216 | //* Length of the given axis. If axis is out of bounds, returns 0.
217 |
218 | public function getAxisLength( i : Int ) : Float {
219 | if (i < 0 || i > this.dim-1) return 0.0;
220 | return Math.abs( this.min[i] - this.max[i] );
221 | }
222 |
223 | //Compute the boolean intersection of this with another axis-aligned bounding box. If the two
224 | //bounding boxes do not intersect, returns null.
225 | //
226 | //**params**
227 | //
228 | //* BoundingBox to intersect with
229 | //
230 | //**returns**
231 | //
232 | //* The bounding box formed by the intersection or null if there is no intersection.
233 |
234 | public function intersect( bb : BoundingBox, tol : Float ) : BoundingBox {
235 |
236 | if ( !this.initialized ) return null;
237 |
238 | var a1 = min
239 | , a2 = max
240 | , b1 = bb.min
241 | , b2 = bb.max;
242 |
243 | if ( !this.intersects( bb, tol ) ) return null;
244 |
245 | var maxbb = []
246 | , minbb = [];
247 |
248 | for (i in 0...dim){
249 | maxbb.push( Math.min( a2[i], b2[i] ) );
250 | minbb.push( Math.max( a1[i], b1[i] ) );
251 | }
252 |
253 | return new BoundingBox([minbb, maxbb]);
254 | }
255 |
256 | }
--------------------------------------------------------------------------------
/src/verb/core/Constants.hx:
--------------------------------------------------------------------------------
1 | package verb.core;
2 |
3 | // `Constants` contains a collection of default constants used throughout the library. These can be set to adjust verb's
4 | // defaults.
5 |
6 | @:expose("core.Constants")
7 | class Constants {
8 | //The default euclidean distance that identifies whether two points are coincident
9 | @:expose("TOLERANCE")
10 | public static var TOLERANCE : Float = 1e-6;
11 |
12 | //The minimum value to determine whether two floating point numbers are the same
13 | @:expose("EPSILON")
14 | public static var EPSILON : Float = 1e-10;
15 |
16 | //The current version of verb
17 | @:expose("VERSION")
18 | public static var VERSION : String = "3.0.3";
19 | }
20 |
--------------------------------------------------------------------------------
/src/verb/core/Data.hx:
--------------------------------------------------------------------------------
1 | package verb.core;
2 |
3 | import verb.core.Serialization;
4 |
5 | // A `Point` in verb is represented simply by an array of floating point numbers.
6 | //
7 | // So, in JavaScript, one would write simply `[0,0,0]` to create a Point at the origin.
8 |
9 | typedef Point = Array;
10 |
11 | // Like a `Point`, a `Vector` is simply an array of floating point numbers
12 | //
13 | // So, in JavaScript, one would write simply `[1,0,0]` to create the a unit vector in the x direction
14 |
15 | typedef Vector = Array
16 |
17 | // `Matrix` is represented by a nested array of floating point number arrays
18 | //
19 | // So, in JavaScript, one would write simply `[[1,0],[0,1]]` to create a 2x2 identity matrix
20 |
21 | typedef Matrix = Array>
22 |
23 | // A `KnotArray` is a non-decreasing sequence of floating point . Use the methods in `Check` to validate `KnotArray`'s
24 |
25 | typedef KnotArray = Array;
26 |
27 | // A `Plane` is simply an origin point and normal
28 |
29 | @:expose("core.Plane")
30 | class Plane extends SerializableBase {
31 |
32 | public var normal : Vector;
33 | public var origin : Point;
34 |
35 | public function new(origin, normal){
36 | this.origin = origin;
37 | this.normal = normal;
38 | }
39 | }
40 |
41 | // A `Ray` is simply an origin point and a direction
42 |
43 | @:expose("core.Ray")
44 | class Ray extends SerializableBase {
45 |
46 | public var dir : Vector;
47 | public var origin : Point;
48 |
49 | public function new(origin, dir){
50 | this.origin = origin;
51 | this.dir = dir;
52 | }
53 | }
54 |
55 | // A simple data structure representing a NURBS curve. `NurbsCurveData` does no checks for legality. You can use
56 | // `verb.eval.Check` for that.
57 |
58 | @:expose("core.NurbsCurveData")
59 | class NurbsCurveData extends SerializableBase {
60 |
61 | public function new(degree, knots, controlPoints){
62 | this.degree = degree;
63 | this.controlPoints = controlPoints;
64 | this.knots = knots;
65 | }
66 |
67 | //integer degree of curve
68 | public var degree : Int;
69 |
70 | // 2d array of control points, where each control point is an array of length (dim)
71 | public var controlPoints : Array;
72 |
73 | //array of nondecreasing knot values
74 | public var knots : Array;
75 |
76 | }
77 |
78 | // A simple data structure representing a NURBS surface. `NurbsSurfaceData` does no checks for legality. You can use
79 | // `verb.eval.Check` for that.
80 |
81 | @:expose("core.NurbsSurfaceData")
82 | class NurbsSurfaceData extends SerializableBase {
83 |
84 | public function new(degreeU, degreeV, knotsU, knotsV, controlPoints){
85 | this.degreeU = degreeU;
86 | this.degreeV = degreeV;
87 | this.knotsU = knotsU;
88 | this.knotsV = knotsV;
89 | this.controlPoints = controlPoints;
90 | }
91 |
92 | //integer degree of surface in u direction
93 | public var degreeU : Int;
94 |
95 | //integer degree of surface in v direction
96 | public var degreeV : Int;
97 |
98 | //array of nondecreasing knot values in u direction
99 | public var knotsU : KnotArray;
100 |
101 | //array of nondecreasing knot values in v direction
102 | public var knotsV : KnotArray;
103 |
104 | // 2d array of control points, the vertical direction (u) increases from top to bottom, the v direction from left to right,
105 | //and where each control point is an array of length (dim)
106 | public var controlPoints : Array>;
107 |
108 | }
109 |
110 | // A triangular face of a mesh
111 |
112 | typedef Tri = Array;
113 |
114 | // A `UV` is simply an array of floating point numbers.
115 | //
116 | // So, in JavaScript, one would write simply `[1,0]` to create a UV
117 |
118 | typedef UV = Array;
119 |
120 | // A simple data structure representing a mesh. `MeshData` does not check for legality.
121 |
122 | @:expose("core.MeshData")
123 | class MeshData extends SerializableBase {
124 |
125 | public var faces : Array;
126 | public var points : Array;
127 | public var normals : Array;
128 | public var uvs : Array;
129 |
130 | public function new(faces : Array, points : Array, normals : Array, uvs : Array ) {
131 | this.faces = faces;
132 | this.points = points;
133 | this.normals = normals;
134 | this.uvs = uvs;
135 | }
136 |
137 | public static function empty() : MeshData {
138 | return new MeshData([],[],[],[]);
139 | }
140 | }
141 |
142 | // A simple data structure representing a polyline. `PolylineData` is useful, for example, as the result of a curve tessellation.
143 |
144 | @:expose("core.PolylineData")
145 | class PolylineData extends SerializableBase {
146 |
147 | // The points in the polyline
148 | public var points : Array;
149 |
150 | // The parameters of the individual points
151 | public var params : Array;
152 |
153 | public function new(points, params){
154 | this.points = points;
155 | this.params = params;
156 | }
157 | }
158 |
159 | // A simple data structure representing a NURBS volume. This data structure is largely experimental in intent. Like CurveData
160 | // and SurfaceData, this data structure does no legality checks.
161 |
162 | @:expose("core.VolumeData")
163 | class VolumeData extends SerializableBase {
164 |
165 | public function new(degreeU, degreeV, degreeW, knotsU, knotsV, knotsW, controlPoints){
166 | this.degreeU = degreeU;
167 | this.degreeV = degreeV;
168 | this.degreeW = degreeW;
169 | this.knotsU = knotsU;
170 | this.knotsV = knotsV;
171 | this.knotsW = knotsW;
172 | this.controlPoints = controlPoints;
173 | }
174 |
175 | //integer degree in u direction
176 | public var degreeU : Int;
177 |
178 | //integer degree in v direction
179 | public var degreeV : Int;
180 |
181 | //integer degree in w direction
182 | public var degreeW : Int;
183 |
184 | //array of nondecreasing knot values in u direction
185 | public var knotsU : KnotArray;
186 |
187 | //array of nondecreasing knot values in v direction
188 | public var knotsV : KnotArray;
189 |
190 | //array of nondecreasing knot values in w direction
191 | public var knotsW : KnotArray;
192 |
193 | // 3d array of control points, where rows are the u dir, and columns run along the positive v direction,
194 | //and where each control point is an array of length (dim)
195 | public var controlPoints : Array>>;
196 |
197 | }
198 |
199 | // A simple parametric data type representing a pair of two objects
200 |
201 | @:expose("core.Pair")
202 | class Pair {
203 | public var item0 : T1;
204 | public var item1 : T2;
205 |
206 | public function new(item1 : T1, item2 : T2) {
207 | this.item0 = item1;
208 | this.item1 = item2;
209 | }
210 | }
211 |
212 | // A simple parametric data type representing an "interval" between two numbers. This data structure does no legality checks.
213 |
214 | @:expose("core.Interval")
215 | class Interval {
216 | public var min : T;
217 | public var max : T;
218 |
219 | public function new(min, max){
220 | this.min = min;
221 | this.max = max;
222 | }
223 | }
--------------------------------------------------------------------------------
/src/verb/core/Intersections.hx:
--------------------------------------------------------------------------------
1 | package verb.core;
2 |
3 | import verb.core.Data;
4 |
5 | @:expose("core.CurveCurveIntersection")
6 | class CurveCurveIntersection {
7 |
8 | //where the intersection took place
9 | public var point0 : Point;
10 |
11 | //where the intersection took place on the second curve
12 | public var point1 : Point;
13 |
14 | //the parameter on the first curve
15 | public var u0 : Float;
16 |
17 | //the parameter on the second curve
18 | public var u1 : Float;
19 |
20 | public function new(point0, point1, u0, u1){
21 | this.point0 = point0;
22 | this.point1 = point1;
23 | this.u0 = u0;
24 | this.u1 = u1;
25 | }
26 | }
27 |
28 | @:expose("core.CurveSurfaceIntersection")
29 | class CurveSurfaceIntersection {
30 |
31 | public var u : Float;
32 | public var uv : UV;
33 | public var curvePoint : Point;
34 | public var surfacePoint : Point;
35 |
36 | public function new( u, uv, curvePoint, surfacePoint ){
37 | this.u = u;
38 | this.uv = uv;
39 | this.curvePoint = curvePoint;
40 | this.surfacePoint = surfacePoint;
41 | }
42 | }
43 |
44 | @:expose("core.MeshIntersectionPoint")
45 | class MeshIntersectionPoint {
46 |
47 | public var uv0 : UV;
48 | public var uv1 : UV;
49 | public var point : Point;
50 |
51 | public var faceIndex0 : Int;
52 | public var faceIndex1 : Int;
53 |
54 | //tags to navigate a segment structure
55 | public var opp : MeshIntersectionPoint = null;
56 | public var adj : MeshIntersectionPoint = null;
57 | public var visited : Bool = false;
58 |
59 | public function new(uv0, uv1, point, faceIndex0, faceIndex1){
60 | this.uv0 = uv0;
61 | this.uv1 = uv1;
62 | this.point = point;
63 | this.faceIndex0;
64 | this.faceIndex1;
65 | }
66 | }
67 |
68 | @:expose("core.PolylineMeshIntersection")
69 | class PolylineMeshIntersection {
70 |
71 | public var point : Point;
72 | public var u : Float;
73 | public var uv : UV;
74 | public var polylineIndex : Int;
75 | public var faceIndex : Int;
76 |
77 | public function new(point, u, uv, polylineIndex, faceIndex){
78 | this.point = point;
79 | this.u = u;
80 | this.uv = uv;
81 | this.polylineIndex = polylineIndex;
82 | this.faceIndex = faceIndex;
83 | }
84 | }
85 |
86 | @:expose("core.SurfaceSurfaceIntersectionPoint")
87 | class SurfaceSurfaceIntersectionPoint {
88 |
89 | public var uv0 : UV;
90 | public var uv1 : UV;
91 | public var point : Point;
92 | public var dist : Float;
93 |
94 | public function new( uv0, uv1, point, dist ){
95 | this.uv0 = uv0;
96 | this.uv1 = uv1;
97 | this.point = point;
98 | this.dist = dist;
99 | }
100 | }
101 |
102 | @:expose("core.TriSegmentIntersection")
103 | class TriSegmentIntersection {
104 |
105 | //where the intersection took place
106 | public var point : Point;
107 |
108 | //the u param where u is the axis from v0 to v1
109 | public var s : Float;
110 |
111 | //the v param where v is the axis from v0 to v2
112 | public var t : Float;
113 |
114 | //the parameter along the segment
115 | public var p : Float;
116 |
117 | public function new(point, s, t, r){
118 | this.point = point;
119 | this.s = s;
120 | this.t = t;
121 | this.p = r;
122 | }
123 | }
124 |
125 | @:expose("core.CurveTriPoint")
126 | class CurveTriPoint {
127 | public var u : Float;
128 | public var uv : UV;
129 | public var point : Point;
130 |
131 | public function new(u : Float, point : Point, uv : UV){
132 | this.u = u;
133 | this.point = point;
134 | this.uv = uv;
135 | }
136 | }
137 |
138 | class SurfacePoint {
139 |
140 | public var uv : UV;
141 | public var point : Point;
142 | public var normal : Point;
143 | public var id : Int;
144 | public var degen : Bool;
145 |
146 | public function new(point : Point, normal : Point, uv : UV, id : Int = -1, degen : Bool = false) {
147 | this.uv = uv;
148 | this.point = point;
149 | this.normal = normal;
150 | this.id = id;
151 | this.degen = degen;
152 | }
153 |
154 | public static function fromUv(u,v){
155 | return new SurfacePoint(null, null, [u,v] );
156 | }
157 | }
158 |
159 | @:expose("core.CurvePoint")
160 | class CurvePoint {
161 | public var u : Float;
162 | public var pt : Point;
163 |
164 | public function new(u, pt) {
165 | this.u = u;
166 | this.pt = pt;
167 | }
168 | }
169 |
--------------------------------------------------------------------------------
/src/verb/core/LazyCurveBoundingBoxTree.hx:
--------------------------------------------------------------------------------
1 | package verb.core;
2 |
3 | using verb.core.ArrayExtensions;
4 | using verb.core.Vec;
5 | import verb.core.Data;
6 |
7 | import verb.eval.Eval;
8 | import verb.eval.Divide;
9 | import verb.eval.Intersect;
10 |
11 | class LazyCurveBoundingBoxTree implements IBoundingBoxTree {
12 |
13 | var _curve : NurbsCurveData;
14 | var _boundingBox : BoundingBox = null;
15 | var _knotTol : Float;
16 |
17 | public function new(curve, knotTol : Float = null){
18 | _curve = curve;
19 | if (knotTol == null){
20 | knotTol = _curve.knots.domain() / 64;
21 | }
22 | _knotTol = knotTol;
23 | }
24 |
25 | public function split() : Pair, IBoundingBoxTree> {
26 | var min = _curve.knots.first();
27 | var max = _curve.knots.last();
28 | var dom = max - min;
29 |
30 | var crvs = Divide.curveSplit( _curve, (max + min) / 2.0 + dom * 0.1 * Math.random());
31 |
32 | return new Pair, IBoundingBoxTree>(
33 | new LazyCurveBoundingBoxTree( crvs[0], _knotTol ),
34 | new LazyCurveBoundingBoxTree( crvs[1], _knotTol ));
35 | }
36 |
37 | public function boundingBox(){
38 | if (_boundingBox == null){
39 | _boundingBox = new BoundingBox( Eval.dehomogenize1d(_curve.controlPoints) );
40 | }
41 | return _boundingBox;
42 | }
43 |
44 | public function yield(){
45 | return _curve;
46 | }
47 |
48 | public function indivisible( tolerance : Float ){
49 | return _curve.knots.domain() < _knotTol;
50 | }
51 |
52 | public function empty(){
53 | return false;
54 | }
55 | }
--------------------------------------------------------------------------------
/src/verb/core/LazyMeshBoundingBoxTree.hx:
--------------------------------------------------------------------------------
1 | package verb.core;
2 |
3 | import verb.core.Data;
4 | import verb.eval.Intersect;
5 |
6 | using verb.core.ArrayExtensions;
7 |
8 | class LazyMeshBoundingBoxTree implements IBoundingBoxTree {
9 | var _mesh : MeshData;
10 | var _faceIndices : Array;
11 | var _boundingBox : BoundingBox = null;
12 |
13 | public function new(mesh, faceIndices = null){
14 | _mesh = mesh;
15 | if (faceIndices == null) {
16 | faceIndices = [ for (i in 0...mesh.faces.length) i ];
17 | }
18 | _faceIndices = faceIndices;
19 | }
20 |
21 | public function split() : Pair, IBoundingBoxTree> {
22 | var as = Mesh.sortTrianglesOnLongestAxis( boundingBox(), _mesh, _faceIndices )
23 | , l = as.left()
24 | , r = as.right();
25 |
26 | return new Pair, IBoundingBoxTree>(
27 | new LazyMeshBoundingBoxTree( _mesh, l),
28 | new LazyMeshBoundingBoxTree( _mesh, r ));
29 | }
30 |
31 | public function boundingBox(){
32 | if (_boundingBox == null){
33 | _boundingBox = Mesh.makeMeshAabb( _mesh, _faceIndices );
34 | }
35 | return _boundingBox;
36 | }
37 |
38 | public function yield(){
39 | return _faceIndices[0];
40 | }
41 |
42 | public function indivisible( tolerance : Float ){
43 | return _faceIndices.length == 1;
44 | }
45 |
46 | public function empty(){
47 | return _faceIndices.length == 0;
48 | }
49 | }
--------------------------------------------------------------------------------
/src/verb/core/LazyPolylineBoundingBoxTree.hx:
--------------------------------------------------------------------------------
1 | package verb.core;
2 |
3 | import verb.core.Data;
4 | import verb.eval.Intersect;
5 |
6 | class LazyPolylineBoundingBoxTree implements IBoundingBoxTree {
7 |
8 | var _interval : Interval;
9 | var _polyline : PolylineData;
10 | var _boundingBox : BoundingBox = null;
11 |
12 | public function new(polyline, interval = null){
13 | _polyline = polyline;
14 |
15 | if (interval == null) {
16 | interval = new Interval(0, polyline.points.length != 0 ? polyline.points.length-1 : 0);
17 | }
18 | _interval = interval;
19 | }
20 |
21 | public function split() : Pair, IBoundingBoxTree> {
22 | var min = _interval.min;
23 | var max = _interval.max;
24 |
25 | var pivot = min + Math.ceil( (max-min) / 2 );
26 |
27 | var l = new Interval( min, pivot )
28 | , r = new Interval( pivot, max );
29 |
30 | return new Pair, IBoundingBoxTree>(
31 | new LazyPolylineBoundingBoxTree( _polyline, l ),
32 | new LazyPolylineBoundingBoxTree( _polyline, r ));
33 |
34 | }
35 |
36 | public function boundingBox(){
37 | if (_boundingBox == null){
38 | _boundingBox = new BoundingBox( _polyline.points );
39 | }
40 |
41 | return _boundingBox;
42 | }
43 |
44 | public function yield(){
45 | return _interval.min;
46 | }
47 |
48 | public function indivisible( tolerance : Float ){
49 | return _interval.max - _interval.min == 1;
50 | }
51 |
52 | public function empty(){
53 | return _interval.max - _interval.min == 0;
54 | }
55 | }
--------------------------------------------------------------------------------
/src/verb/core/LazySurfaceBoundingBoxTree.hx:
--------------------------------------------------------------------------------
1 | package verb.core;
2 |
3 | using verb.core.ArrayExtensions;
4 | using verb.core.Vec;
5 |
6 | import verb.eval.Eval;
7 | import verb.eval.Divide;
8 | import verb.core.Data;
9 | import verb.eval.Intersect;
10 |
11 | class LazySurfaceBoundingBoxTree implements IBoundingBoxTree {
12 |
13 | var _surface : NurbsSurfaceData;
14 | var _boundingBox : BoundingBox = null;
15 | var _splitV : Bool;
16 | var _knotTolU : Float;
17 | var _knotTolV : Float;
18 |
19 | public function new(surface, splitV = false, knotTolU = null, knotTolV = null){
20 | _surface = surface;
21 | _splitV = splitV;
22 |
23 | if (knotTolU == null){
24 | knotTolU = (surface.knotsU.domain()) / 16;
25 | }
26 |
27 | if (knotTolV == null){
28 | knotTolV = (surface.knotsV.domain()) / 16;
29 | }
30 |
31 | _knotTolU = knotTolU;
32 | _knotTolV = knotTolV;
33 | }
34 |
35 | public function split() : Pair, IBoundingBoxTree> {
36 | var min : Float;
37 | var max : Float;
38 |
39 | if (_splitV){
40 | min = _surface.knotsV.first();
41 | max = _surface.knotsV.last();
42 | } else {
43 | min = _surface.knotsU.first();
44 | max = _surface.knotsU.last();
45 | }
46 |
47 | var dom = max - min;
48 | var pivot = (min + max) / 2.0; //* dom * 0.01 * Math.random();
49 |
50 | var srfs = Divide.surfaceSplit( _surface, pivot, _splitV );
51 |
52 | return new Pair, IBoundingBoxTree>(
53 | new LazySurfaceBoundingBoxTree( srfs[0], !_splitV, _knotTolU, _knotTolV ),
54 | new LazySurfaceBoundingBoxTree( srfs[1], !_splitV, _knotTolU, _knotTolV ));
55 | }
56 |
57 | public function boundingBox(){
58 | if (_boundingBox == null){
59 | _boundingBox = new BoundingBox();
60 | for (row in _surface.controlPoints){
61 | _boundingBox.addRange( Eval.dehomogenize1d(row) );
62 | }
63 | }
64 | return _boundingBox;
65 | }
66 |
67 | public function yield(){
68 | return _surface;
69 | }
70 |
71 | public function indivisible( tolerance : Float ){
72 | return _surface.knotsV.domain() < _knotTolV && _surface.knotsU.domain() < _knotTolU;
73 | }
74 |
75 | public function empty(){
76 | return false;
77 | }
78 | }
--------------------------------------------------------------------------------
/src/verb/core/Mat.hx:
--------------------------------------------------------------------------------
1 | package verb.core;
2 |
3 | import verb.core.Vec;
4 | import verb.core.Data;
5 |
6 | // Tools for working with matrices
7 |
8 | @:expose("core.Mat")
9 | class Mat {
10 |
11 | // Multiply a `Matrix` by a constant
12 |
13 | public static function mul(a : Float, b : Matrix ) : Matrix {
14 | return [ for (i in 0...b.length) Vec.mul(a, b[i]) ];
15 | }
16 |
17 | // Multiply two matrices assuming they are of compatible dimensions.
18 | //
19 | // Based on the numeric.js routine - `numeric.dotMMsmall`
20 |
21 | public static function mult(x : Matrix, y : Matrix) : Matrix {
22 |
23 | var p,q,r,ret,foo,bar,woo,i0,k0,p0,r0;
24 |
25 | p = x.length; q = y.length; r = y[0].length;
26 | ret = new Matrix();
27 |
28 | var i = p-1;
29 | var j = 0;
30 | var k = 0;
31 |
32 | while (i>=0){
33 | foo = new Vector();
34 | bar = x[i];
35 |
36 | k = r-1;
37 | while( k >= 0 ){
38 | woo = bar[q-1]*y[q-1][k];
39 |
40 | j = q-2;
41 | while ( j >= 1 ){
42 | i0 = j-1;
43 | woo += bar[j]*y[j][k] + bar[i0]*y[i0][k];
44 | j -= 2;
45 | }
46 | if(j==0) { woo += bar[0]*y[0][k]; }
47 | foo[k] = woo;
48 | k--;
49 | }
50 | ret[i] = foo;
51 | i--;
52 | }
53 | return ret;
54 | }
55 |
56 | // Add two matrices
57 |
58 | public static function add(a : Matrix, b : Matrix ) : Matrix {
59 | return [ for (i in 0...a.length) Vec.add(a[i], b[i]) ];
60 | }
61 |
62 | // Divide each of entry of a Matrix by a constant
63 |
64 | public static function div(a : Matrix, b : Float ) : Matrix {
65 | return [ for (i in 0...a.length) Vec.div(a[i], b) ];
66 | }
67 |
68 | // Subtract two matrices
69 |
70 | public static function sub(a : Matrix, b : Matrix ) : Matrix {
71 | return [ for (i in 0...a.length) Vec.sub(a[i], b[i]) ];
72 | }
73 |
74 | // Multiply a `Matrix` by a `Vector`
75 |
76 | public static function dot(a : Matrix, b : Vector ) : Vector {
77 | return [ for (i in 0...a.length) Vec.dot(a[i], b) ];
78 | }
79 |
80 | // Build an identity matrix of a given size
81 |
82 | public static function identity(n : Int) : Matrix {
83 | var zeros = Vec.zeros2d(n, n);
84 | for (i in 0...n){ zeros[i][i] = 1.0; }
85 | return zeros;
86 | }
87 |
88 | // Transpose a matrix
89 |
90 | public static function transpose(a : Array>) : Array> {
91 | if (a.length == 0) return [];
92 | return [ for (i in 0...a[0].length) [for (j in 0...a.length) a[j][i] ] ];
93 | }
94 |
95 | // Solve a system of equations
96 |
97 | public static function solve(A : Matrix, b : Vector) : Vector {
98 | return LUsolve( LU(A), b );
99 | }
100 |
101 | // Based on methods from numeric.js
102 |
103 | private static function LUsolve(LUP : LUDecomp, b : Vector) : Vector {
104 | var i, j;
105 | var LU = LUP.LU;
106 | var n = LU.length;
107 | var x = b.copy();
108 | var P = LUP.P;
109 | var Pi, LUi, LUii, tmp;
110 |
111 | i = n-1;
112 | while ( i != -1 ){
113 | x[i] = b[i];
114 | --i;
115 | }
116 |
117 | i = 0;
118 | while (i < n){
119 | Pi = P[i];
120 | if (P[i] != i) {
121 | tmp = x[i];
122 | x[i] = x[Pi];
123 | x[Pi] = tmp;
124 | }
125 |
126 | LUi = LU[i];
127 | j = 0;
128 | while (j < i){
129 | x[i] -= x[j] * LUi[j];
130 | ++j;
131 | }
132 | ++i;
133 | }
134 |
135 | i = n-1;
136 | while (i >= 0){
137 | LUi = LU[i];
138 | j = i+1;
139 | while (j < n){
140 | x[i] -= x[j] * LUi[j];
141 | ++j;
142 | }
143 |
144 | x[i] /= LUi[i];
145 | --i;
146 | }
147 |
148 | return x;
149 | }
150 |
151 | // Based on methods from numeric.js
152 |
153 | private static function LU( A : Matrix ) : LUDecomp {
154 |
155 | var abs = Math.abs;
156 | var i, j, k, absAjk, Akk, Ak, Pk, Ai;
157 | var max;
158 | //copy A
159 | A = [ for (i in 0...A.length) A[i].copy() ];
160 | var n = A.length, n1 = n-1;
161 | var P = new Array(); //new Array(n);
162 |
163 | k = 0;
164 | while (k < n){
165 | Pk = k;
166 | Ak = A[k];
167 | max = Math.abs(Ak[k]);
168 |
169 | j = k+1;
170 | while (j < n){
171 | absAjk = Math.abs(A[j][k]);
172 | if (max < absAjk) {
173 | max = absAjk;
174 | Pk = j;
175 | }
176 | ++j;
177 | }
178 | P[k] = Pk;
179 |
180 | if (Pk != k) {
181 | A[k] = A[Pk];
182 | A[Pk] = Ak;
183 | Ak = A[k];
184 | }
185 |
186 | Akk = Ak[k];
187 |
188 | i = k+1;
189 | while (i < n){
190 | A[i][k] /= Akk;
191 | ++i;
192 | }
193 |
194 | i = k+1;
195 | while (i < n){
196 | Ai = A[i];
197 | j = k+1;
198 | while (j < n1){
199 | Ai[j] -= Ai[k] * Ak[j];
200 | ++j;
201 | Ai[j] -= Ai[k] * Ak[j];
202 | ++j;
203 | }
204 | if(j==n1) Ai[j] -= Ai[k] * Ak[j];
205 | ++i;
206 | }
207 |
208 | ++k;
209 | }
210 |
211 | return new LUDecomp(A, P);
212 | }
213 |
214 | }
215 |
216 | // Based on methods from numeric.js
217 |
218 | private class LUDecomp {
219 |
220 | public var LU : Matrix;
221 | public var P : Array;
222 | public function new( lu : Matrix, p : Array ){
223 | this.LU = lu;
224 | this.P = p;
225 | }
226 |
227 | }
228 |
--------------------------------------------------------------------------------
/src/verb/core/Mesh.hx:
--------------------------------------------------------------------------------
1 | package verb.core;
2 |
3 | import verb.core.BoundingBox;
4 | import verb.core.Data;
5 |
6 | using verb.core.ArrayExtensions;
7 |
8 | // `Mesh` provides various convenience methods for working with meshes.
9 |
10 | @:expose("core.Mesh")
11 | class Mesh {
12 |
13 | //Get triangle normal
14 | //
15 | //**params**
16 | //
17 | //* array of length 3 arrays of numbers representing the points
18 | //* length 3 array of point indices for the triangle
19 | //
20 | //**returns**
21 | //
22 | //* a normal vector represented by an array of length 3
23 | //
24 |
25 | public static function getTriangleNorm( points : Array, tri : Tri ) : Point {
26 |
27 | var v0 = points[ tri[0] ]
28 | , v1 = points[ tri[1] ]
29 | , v2 = points[ tri[2] ]
30 | , u = Vec.sub( v1, v0 )
31 | , v = Vec.sub( v2, v0 )
32 | , n = Vec.cross( u, v );
33 |
34 | return Vec.mul( 1 / Vec.norm( n ), n );
35 |
36 | }
37 |
38 | //Form axis-aligned bounding box from triangles of mesh
39 | //
40 | //**params**
41 | //
42 | //* a mesh
43 | //* face indices of the mesh to include in the bounding box
44 | //
45 | //**returns**
46 | //
47 | //* a BoundingBox containing the mesh
48 | //
49 |
50 | public static function makeMeshAabb( mesh : MeshData, faceIndices : Array ) : BoundingBox {
51 |
52 | var bb = new verb.core.BoundingBox();
53 |
54 | for ( x in faceIndices ){
55 | bb.add( mesh.points[ mesh.faces[ x ][0] ] );
56 | bb.add( mesh.points[ mesh.faces[ x ][1] ] );
57 | bb.add( mesh.points[ mesh.faces[ x ][2] ] );
58 | }
59 |
60 | return bb;
61 | }
62 |
63 | //Sort particular faces of a mesh on the longest axis
64 | //
65 | //**params**
66 | //
67 | //* bounding box containing the faces
68 | //* the mesh it self
69 | //* the indices of the mesh faces to inspect
70 | //
71 | //**returns**
72 | //
73 | //* a point represented by an array of length (dim)
74 | //
75 |
76 | public static function sortTrianglesOnLongestAxis( bb : BoundingBox, mesh : MeshData, faceIndices : Array ) : Array {
77 |
78 | var longAxis = bb.getLongestAxis();
79 |
80 | var minCoordFaceMap = new Array>();
81 | for ( faceIndex in faceIndices){
82 | var tri_min = getMinCoordOnAxis( mesh.points, mesh.faces[ faceIndex ], longAxis );
83 | minCoordFaceMap.push( new Pair(tri_min, faceIndex) );
84 | }
85 |
86 | minCoordFaceMap.sort(function(a : Pair, b : Pair):Int {
87 | var a0 = a.item0;
88 | var b0 = b.item0;
89 |
90 | if (a0 == b0) return 0 else if (a0 > b0) return 1 else return -1;
91 | });
92 |
93 | var sortedFaceIndices = new Array();
94 | for ( i in 0...minCoordFaceMap.length){
95 | sortedFaceIndices.push( minCoordFaceMap[i].item1 );
96 | }
97 |
98 | return sortedFaceIndices;
99 | }
100 |
101 | //Get min coordinate on an axis
102 | //
103 | //**params**
104 | //
105 | //* array of length 3 arrays of numbers representing the points
106 | //* length 3 array of point indices for the triangle
107 | //* index of the axis to test - 0 for x, 1 for y, 2 for z
108 | //
109 | //**returns**
110 | //
111 | //* the minimum coordinate
112 |
113 | private static function getMinCoordOnAxis( points : Array, tri : Tri, axis : Int ) : Float {
114 |
115 | var min = Math.POSITIVE_INFINITY;
116 |
117 | for (i in 0...3){
118 | var coord = points[ tri[i] ][ axis ];
119 | if (coord < min) min = coord;
120 | }
121 |
122 | return min;
123 | }
124 |
125 | //Get triangle centroid
126 | //
127 | //**params**
128 | //
129 | //* array of length 3 arrays of numbers representing the points
130 | //* length 3 array of point indices for the triangle
131 | //
132 | //**returns**
133 | //
134 | //* a point represented by an array of length 3
135 | //
136 |
137 | public static function getTriangleCentroid( points : Array, tri : Tri ) : Point {
138 |
139 | var centroid = [0.0,0.0,0.0];
140 |
141 | for (i in 0...3){
142 | for (j in 0...3){
143 | centroid[j] += points[ tri[i] ][j];
144 | }
145 | }
146 |
147 | for (i in 0...3){
148 | centroid[i] /= 3;
149 | }
150 |
151 | return centroid;
152 |
153 | }
154 |
155 | //Given a point on a mesh triangle, obtain the UV on the triangle
156 | //
157 | //**params**
158 | //
159 | //* the mesh
160 | //* index of the face to test
161 | //
162 | //**returns**
163 | //
164 | //* the UV on the face
165 |
166 | public static function triangleUVFromPoint( mesh : MeshData, faceIndex : Int, f : Point ) : UV {
167 |
168 | var tri = mesh.faces[faceIndex];
169 |
170 | var p1 = mesh.points[ tri[0] ];
171 | var p2 = mesh.points[ tri[1] ];
172 | var p3 = mesh.points[ tri[2] ];
173 |
174 | var uv1 = mesh.uvs[ tri[0] ];
175 | var uv2 = mesh.uvs[ tri[1] ];
176 | var uv3 = mesh.uvs[ tri[2] ];
177 |
178 | var f1 = Vec.sub(p1, f);
179 | var f2 = Vec.sub(p2, f);
180 | var f3 = Vec.sub(p3, f);
181 |
182 | //calculate the areas and factors (order of parameters doesn't matter):
183 | var a = Vec.norm( Vec.cross( Vec.sub(p1, p2), Vec.sub(p1, p3) ) ); //main triangle area a
184 | var a1 = Vec.norm( Vec.cross(f2, f3) ) / a; //p1's triangle area / a
185 | var a2 = Vec.norm( Vec.cross(f3, f1) ) / a; //p2's triangle area / a
186 | var a3 = Vec.norm( Vec.cross(f1, f2) ) / a; //p3's triangle area / a
187 |
188 | //find the uv corresponding to point f (uv1/uv2/uv3 are associated to p1/p2/p3):
189 | return Vec.add( Vec.mul( a1, uv1), Vec.add( Vec.mul( a2, uv2), Vec.mul( a3, uv3)));
190 | }
191 | }
192 |
--------------------------------------------------------------------------------
/src/verb/core/MeshBoundingBoxTree.hx:
--------------------------------------------------------------------------------
1 | package verb.core;
2 |
3 | using verb.core.ArrayExtensions;
4 |
5 | import verb.core.Data;
6 | import verb.eval.Intersect;
7 |
8 | class MeshBoundingBoxTree implements IBoundingBoxTree {
9 |
10 | var _children : Pair, IBoundingBoxTree>;
11 | var _boundingBox : BoundingBox;
12 | var _face : Int = -1;
13 | var _empty : Bool = false;
14 |
15 | public function new(mesh : MeshData, faceIndices : Array = null){
16 |
17 | if (faceIndices == null) {
18 | faceIndices = [ for (i in 0...mesh.faces.length) i ];
19 | }
20 |
21 | _boundingBox = Mesh.makeMeshAabb( mesh, faceIndices );
22 |
23 | if (faceIndices.length < 1) {
24 | _empty = true;
25 | return;
26 | } else if (faceIndices.length < 2){
27 | _face = faceIndices[0];
28 | return;
29 | }
30 |
31 | var as = Mesh.sortTrianglesOnLongestAxis( _boundingBox, mesh, faceIndices );
32 | var l = as.left();
33 | var r = as.right();
34 |
35 | _children = new Pair, IBoundingBoxTree>(
36 | new MeshBoundingBoxTree(mesh, l),
37 | new MeshBoundingBoxTree(mesh, r)
38 | );
39 | }
40 |
41 | public function split() : Pair, IBoundingBoxTree> {
42 | return _children;
43 | }
44 |
45 | public function boundingBox(){
46 | return _boundingBox;
47 | }
48 |
49 | public function yield(){
50 | return _face;
51 | }
52 |
53 | public function indivisible( tolerance : Float ){
54 | return _children == null;
55 | }
56 |
57 | public function empty(){
58 | return _empty;
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/verb/core/Minimizer.hx:
--------------------------------------------------------------------------------
1 | package verb.core;
2 | import verb.core.Mat;
3 |
4 | import verb.core.Vec;
5 | import verb.core.Data;
6 |
7 | @:expose("core.Minimizer")
8 | class Minimizer {
9 |
10 | public static function uncmin(f : Vector -> Float, x0 : Vector, tol : Float = null, gradient : Vector -> Vector= null, maxit : Int = null) : MinimizationResult {
11 |
12 | if(tol == null) { tol = 1e-8; }
13 | if(gradient == null) { gradient = function(x) { return numericalGradient(f,x); }; }
14 | if(maxit == null) maxit = 1000;
15 |
16 | x0 = x0.slice(0);
17 | var n = x0.length;
18 | var f0 = f(x0),f1 = f0, df0;
19 |
20 | if(Math.isNaN(f0)) throw 'uncmin: f(x0) is a NaN!';
21 |
22 | tol = Math.max(tol, Constants.EPSILON);
23 | var step,g0,g1,H1 = Mat.identity(n);
24 | var it=0,i,s =[],x1,y,Hy,Hs,ys,i0,t,nstep,t1,t2;
25 | var msg = "";
26 | g0 = gradient( x0 );
27 |
28 | while(it < maxit) {
29 |
30 | if(!Vec.all(Vec.finite(g0))) { msg = "Gradient has Infinity or NaN"; break; }
31 | step = Vec.neg(Mat.dot(H1,g0));
32 |
33 | if(!Vec.all(Vec.finite(step))) { msg = "Search direction has Infinity or NaN"; break; }
34 |
35 | nstep = Vec.norm(step);
36 | if(nstep < tol) { msg= "Newton step smaller than tol"; break; }
37 |
38 | t = 1.0;
39 | df0 = Vec.dot(g0,step);
40 |
41 | //line search
42 | x1 = x0;
43 | while(it < maxit) {
44 | if(t*nstep < tol) { break; }
45 | s = Vec.mul(t, step);
46 | x1 = Vec.add(x0,s);
47 | f1 = f(x1);
48 | if(f1-f0 >= 0.1*t*df0 || Math.isNaN(f1)) {
49 | t *= 0.5;
50 | ++it;
51 | continue;
52 | }
53 | break;
54 | }
55 |
56 | if(t*nstep < tol) { msg = "Line search step size smaller than tol"; break; }
57 | if(it == maxit) { msg = "maxit reached during line search"; break; }
58 |
59 | g1 = gradient(x1);
60 | y = Vec.sub(g1,g0);
61 | ys = Vec.dot(y,s);
62 | Hy = Mat.dot(H1,y);
63 | H1 = Mat.sub(
64 | Mat.add(H1, Mat.mul( (ys+Vec.dot(y,Hy))/(ys*ys), tensor(s,s) )),
65 | Mat.div(Mat.add(tensor(Hy,s),tensor(s,Hy)),ys));
66 | x0 = x1;
67 | f0 = f1;
68 | g0 = g1;
69 | ++it;
70 | }
71 |
72 | return new MinimizationResult( x0, f0, g0, H1, it, msg);
73 | }
74 |
75 | private static function numericalGradient(f : Vector -> Float, x : Vector) : Vector {
76 |
77 | var n = x.length;
78 | var f0 = f(x);
79 |
80 | if(f0 == Math.NaN) throw 'gradient: f(x) is a NaN!';
81 |
82 | var i, x0 = x.slice(0),f1,f2, J = [];
83 |
84 | var errest,roundoff,eps = 1e-3;
85 | var t0,t1,t2,it=0,d1,d2,N;
86 |
87 | for (i in 0...n){
88 |
89 | var h = Math.max(1e-6 * f0, 1e-8);
90 |
91 | while(true) {
92 | ++it;
93 | if( it>20 ) { throw "Numerical gradient fails"; }
94 | x0[i] = x[i]+h;
95 | f1 = f(x0);
96 | x0[i] = x[i]-h;
97 | f2 = f(x0);
98 | x0[i] = x[i];
99 |
100 | if(Math.isNaN(f1) || Math.isNaN(f2)) { h/=16; continue; }
101 |
102 | J[i] = (f1-f2)/(2*h);
103 | t0 = x[i]-h;
104 | t1 = x[i];
105 | t2 = x[i]+h;
106 | d1 = (f1-f0)/h;
107 | d2 = (f0-f2)/h;
108 | N = Vec.max([ Math.abs(J[i]), Math.abs(f0), Math.abs(f1), Math.abs(f2), Math.abs(t0), Math.abs(t1), Math.abs(t2), 1e-8 ]);
109 |
110 | errest = Math.min( Vec.max([Math.abs(d1-J[i]), Math.abs(d2-J[i]), Math.abs(d1-d2)])/N, h/N);
111 |
112 | if(errest>eps) { h/=16; } else break;
113 | }
114 | }
115 |
116 | return J;
117 | }
118 |
119 | private static function tensor(x : Vector, y : Vector) : Matrix {
120 |
121 | var m = x.length, n = y.length, A = [], Ai, xi;
122 |
123 | var i = m-1;
124 | while (i >= 0){
125 | Ai = [];
126 | xi = x[i];
127 | var j = n-1;
128 | while(j >= 3){
129 | Ai[j] = xi * y[j];
130 | --j;
131 | Ai[j] = xi * y[j];
132 | --j;
133 | Ai[j] = xi * y[j];
134 | --j;
135 | Ai[j] = xi * y[j];
136 | --j;
137 | }
138 | while(j>=0) { Ai[j] = xi * y[j]; --j; }
139 | A[i] = Ai;
140 | i--;
141 | }
142 | return A;
143 | }
144 |
145 | }
146 |
147 | class MinimizationResult {
148 |
149 | public var solution : Vector;
150 | public var value : Float;
151 | public var gradient : Vector;
152 | public var invHessian : Matrix;
153 | public var iterations : Int;
154 | public var message : String;
155 |
156 | public function new(solution, value, gradient, invHessian, iterations, message){
157 | this.solution = solution;
158 | this.value = value;
159 | this.gradient = gradient;
160 | this.invHessian = invHessian;
161 | this.iterations = iterations;
162 | this.message = message;
163 | }
164 | }
165 |
--------------------------------------------------------------------------------
/src/verb/core/Serialization.hx:
--------------------------------------------------------------------------------
1 | package verb.core;
2 |
3 | import haxe.Serializer;
4 | import haxe.Unserializer;
5 |
6 | // An interface describing a type that can be serialized as a
7 | // string. Use verb.core.Deserializer to construct an instance of the
8 | // the type from the resultant string. The string is the serialized representation of a haxe
9 | // object and is strongly typed. For details, see
10 | // [http://haxe.org/manual/std-serialization.html](http://haxe.org/manual/std-serialization.html) for details.
11 |
12 | interface ISerializable {
13 | function serialize() : String;
14 | }
15 |
16 | // Forms a base class for serializable data types
17 |
18 | @:expose("core.SerializableBase")
19 | class SerializableBase {
20 | public function serialize() : String {
21 | var serializer = new Serializer();
22 | serializer.serialize(this);
23 | return serializer.toString();
24 | }
25 | }
26 |
27 | // Deserializes strings for types implementing ISerializable
28 |
29 | @:expose("core.Deserializer")
30 | class Deserializer {
31 |
32 | //Construct an ISerializable from its string representation, given a parameter T. You can
33 | //use this to deserialize almost any type in verb.geom or verb.core.*Data types.
34 | //
35 | //**params**
36 | //
37 | //* A string representing something implementing ISerializable
38 | //
39 | //**returns**
40 | //
41 | //* A new T from the string
42 |
43 | public static function deserialize(s : String) : T {
44 | var unserializer = new Unserializer(s);
45 | var r : T = unserializer.unserialize();
46 | return r;
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/verb/core/SurfaceBoundingBoxTree.hx:
--------------------------------------------------------------------------------
1 | package verb.core;
2 |
3 | import verb.core.Data;
4 | using verb.core.ArrayExtensions;
5 | using verb.core.Vec;
6 | import verb.eval.Divide;
7 | import verb.eval.Eval;
8 | import verb.eval.Intersect;
9 |
10 | class SurfaceBoundingBoxTree implements IBoundingBoxTree {
11 |
12 | var _children : Pair, IBoundingBoxTree>;
13 | var _surface : NurbsSurfaceData;
14 | var _boundingBox : BoundingBox = null;
15 |
16 | public function new(surface, splitV = false, knotTolU = null, knotTolV = null){
17 | _surface = surface;
18 |
19 | if (knotTolU == null){
20 | knotTolU = (surface.knotsU.domain()) / 16;
21 | }
22 |
23 | if (knotTolV == null){
24 | knotTolV = (surface.knotsV.domain()) / 16;
25 | }
26 |
27 | var divisible = false;
28 |
29 | if (splitV){
30 | divisible = _surface.knotsV.domain() > knotTolV;
31 | } else {
32 | divisible = _surface.knotsU.domain() > knotTolU;
33 | }
34 |
35 | if ( !divisible ) return;
36 |
37 | var min : Float;
38 | var max : Float;
39 |
40 | if (splitV){
41 | min = _surface.knotsV.first();
42 | max = _surface.knotsV.last();
43 | } else {
44 | min = _surface.knotsU.first();
45 | max = _surface.knotsU.last();
46 | }
47 |
48 | var dom = max - min;
49 | var pivot = (min + max) / 2.0 + dom * 0.1 * Math.random();
50 |
51 | var srfs = Divide.surfaceSplit( _surface, pivot, splitV );
52 |
53 | _children = new Pair, IBoundingBoxTree>(
54 | new SurfaceBoundingBoxTree( srfs[0], !splitV, knotTolU, knotTolV ),
55 | new SurfaceBoundingBoxTree( srfs[1], !splitV, knotTolU, knotTolV ));
56 |
57 | }
58 |
59 | public function split() : Pair, IBoundingBoxTree> {
60 | return _children;
61 | }
62 |
63 | public function boundingBox(){
64 | if (_boundingBox == null){
65 | _boundingBox = new BoundingBox();
66 | for (row in _surface.controlPoints){
67 | _boundingBox.addRange( Eval.dehomogenize1d(row) );
68 | }
69 | }
70 | return _boundingBox;
71 | }
72 |
73 | public function yield(){
74 | return _surface;
75 | }
76 |
77 | public function indivisible( tolerance : Float ){
78 | return _children == null;
79 | }
80 |
81 | public function empty(){
82 | return false;
83 | }
84 | }
--------------------------------------------------------------------------------
/src/verb/core/Trig.hx:
--------------------------------------------------------------------------------
1 | package verb.core;
2 |
3 | import verb.core.Vec;
4 | import verb.core.Data;
5 | import verb.core.Intersections;
6 | using verb.core.Vec;
7 |
8 | // `Trig` provides various convenient methods for trigonometry
9 |
10 | @:expose("core.Trig")
11 | class Trig {
12 |
13 | public static function isPointInPlane( pt : Point, p : Plane, tol : Float ) : Bool{
14 | return Math.abs( pt.sub( p.origin ).dot( p.normal ) ) < tol;
15 | }
16 |
17 | public static function distToSegment(a : Point, b : Point, c : Point){
18 | var res = segmentClosestPoint( b, a, c, 0.0, 1.0 );
19 | return Vec.dist( b, res.pt );
20 | }
21 |
22 | //Find the closest point on a ray
23 | //
24 | //**params**
25 | //
26 | //* point to project
27 | //* origin for ray
28 | //* direction of ray 1, assumed normalized
29 | //
30 | //**returns**
31 | //
32 | //* pt
33 |
34 | public static function rayClosestPoint( pt, o, r ) {
35 | var o2pt = Vec.sub(pt,o)
36 | , do2ptr = Vec.dot(o2pt, r)
37 | , proj = Vec.add(o, Vec.mul(do2ptr, r));
38 |
39 | return proj;
40 | }
41 |
42 | //Find the distance of a point to a ray
43 | //
44 | //**params**
45 | //
46 | //* point to project
47 | //* origin for ray
48 | //* direction of ray 1, assumed normalized
49 | //
50 | //**returns**
51 | //
52 | //* the distance
53 |
54 | public static function distToRay( pt, o, r ) {
55 | var d = rayClosestPoint( pt, o, r );
56 | var dif = Vec.sub( d, pt );
57 |
58 | return Vec.norm( dif );
59 |
60 | }
61 |
62 | //Determine if three points form a straight line within a given tolerance for their 2 * squared area
63 | //
64 | // * p2
65 | // / \
66 | // / \
67 | // / \
68 | // / \
69 | // * p1 ---- * p3
70 | //
71 | //The area metric is 2 * the squared norm of the cross product of two edges, requiring no square roots and no divisions
72 | //
73 | //**params**
74 | //
75 | //* p1
76 | //* p2
77 | //* p3
78 | //* The tolerance
79 | //
80 | //**returns**
81 | //
82 | //* Whether the triangle passes the test
83 |
84 | public static function threePointsAreFlat( p1, p2, p3, tol ) {
85 |
86 | //find the area of the triangle without using a square root
87 | var p2mp1 = Vec.sub( p2, p1 )
88 | , p3mp1 = Vec.sub( p3, p1 )
89 | , norm = Vec.cross( p2mp1, p3mp1 )
90 | , area = Vec.dot( norm, norm );
91 |
92 | return area < tol;
93 |
94 | }
95 |
96 | //Find the closest point on a segment
97 | //
98 | //**params**
99 | //
100 | //* point to project
101 | //* first point of segment
102 | //* second point of segment
103 | //* first param of segment
104 | //* second param of segment
105 | //
106 | //**returns**
107 | //
108 | //* *Object* with u and pt properties
109 |
110 | public static function segmentClosestPoint( pt : Point, segpt0 : Point, segpt1 : Point, u0 : Float, u1 : Float ) {
111 |
112 | var dif = Vec.sub( segpt1, segpt0 )
113 | , l = Vec.norm( dif );
114 |
115 | if (l < Constants.EPSILON ) {
116 | return { u: u0, pt : segpt0 };
117 | }
118 |
119 | var o = segpt0
120 | , r = Vec.mul( 1 / l, dif )
121 | , o2pt = Vec.sub(pt, o)
122 | , do2ptr = Vec.dot(o2pt, r);
123 |
124 | if (do2ptr < 0){
125 | return { u: u0, pt : segpt0 };
126 | } else if (do2ptr > l){
127 | return { u: u1, pt : segpt1 };
128 | }
129 |
130 | return { u: u0 + (u1 - u0) * do2ptr / l, pt : Vec.add(o, Vec.mul( do2ptr, r ) ) };
131 |
132 | }
133 |
134 | }
135 |
--------------------------------------------------------------------------------
/src/verb/eval/Check.hx:
--------------------------------------------------------------------------------
1 | package verb.eval;
2 |
3 | import verb.core.Data;
4 |
5 | import verb.core.Constants;
6 |
7 | import verb.core.ArrayExtensions;
8 | using verb.core.ArrayExtensions;
9 |
10 | // `Check` includes various tools for checking the validity of various NURBS data structures. This is important because it is
11 | // very easy to construct such data structures with incorrect structure. This class contains static, immutable functions for
12 | // doing those checks.
13 | //
14 | // **Note that the classes in verb.eval are very tolerant of incorrect NURBS data structures for performance reasons.** You should
15 | // perform these checks before using these classes.
16 |
17 | @:expose("eval.Check")
18 | class Check {
19 |
20 | //Check whether a given array is a valid NURBS knot vector. This also checks the validity of the end points.
21 | //More specifically, this method checks if the knot vector is of the following structure:
22 | //
23 | // The knot vector must be non-decreasing and of length (degree + 1) * 2 or greater
24 | //
25 | // [ (degree + 1 copies of the first knot), internal non-decreasing knots, (degree + 1 copies of the last knot) ]
26 | //
27 | //**params**
28 | //
29 | //* The knot vector to test
30 | //* The degree
31 | //
32 | //**returns**
33 | //
34 | //* Whether the array is a valid knot vector or knot
35 |
36 | public static function isValidKnotVector(vec : Array, degree : Int) : Bool {
37 |
38 | if (vec.length == 0) return false;
39 | if (vec.length < (degree + 1) * 2 ) return false;
40 |
41 | var rep = vec.first();
42 |
43 | for (i in 0...degree+1){
44 | if (Math.abs(vec[i]-rep) > Constants.EPSILON) return false;
45 | }
46 |
47 | rep = vec.last();
48 |
49 | for (i in vec.length-degree-1...vec.length){
50 | if (Math.abs(vec[i]-rep) > Constants.EPSILON) return false;
51 | }
52 |
53 | return isNonDecreasing( vec );
54 | }
55 |
56 | //Check if an array of floating point numbers is non-decreasing, although there may be repeats. This is an important
57 | //validation step for NURBS knot vectors.
58 | //
59 | //**params**
60 | //
61 | //* The data object
62 | //
63 | //**returns**
64 | //
65 | //* Whether the array is non-decreasing
66 |
67 | public static function isNonDecreasing(vec : Array){
68 | var rep = vec.first();
69 | for ( i in 0...vec.length ){
70 | if (vec[i] < rep - Constants.EPSILON ) return false;
71 | rep = vec[i];
72 | }
73 | return true;
74 | }
75 |
76 | //Validate a NurbsCurveData object
77 | //
78 | //**params**
79 | //
80 | //* The data object
81 | //
82 | //**returns**
83 | //
84 | //* The original, unmodified data
85 |
86 | public static function isValidNurbsCurveData( data : NurbsCurveData ) : NurbsCurveData {
87 | if ( data.controlPoints == null ) throw "Control points array cannot be null!";
88 | #if (!cpp && !cs && !java)
89 | if ( data.degree == null ) throw "Degree cannot be null!";
90 | #end
91 | if ( data.degree < 1 ) throw "Degree must be greater than 1!";
92 | if ( data.knots == null ) throw "Knots cannot be null!";
93 |
94 | if ( data.knots.length != data.controlPoints.length + data.degree + 1 ){
95 | throw "controlPoints.length + degree + 1 must equal knots.length!";
96 | }
97 |
98 | if (!Check.isValidKnotVector( data.knots, data.degree )){
99 | throw "Invalid knot vector format! Should begin with degree + 1 repeats and end with degree + 1 repeats!";
100 | }
101 |
102 | return data;
103 | }
104 |
105 | //Validate a NurbsSurfaceData object
106 | //
107 | //**params**
108 | //
109 | //* The data object
110 | //
111 | //**returns**
112 | //
113 | //* The original, unmodified data
114 |
115 | public static function isValidNurbsSurfaceData( data : NurbsSurfaceData ) : NurbsSurfaceData {
116 | if ( data.controlPoints == null ) throw "Control points array cannot be null!";
117 | #if (!cpp && !cs && !java)
118 | if ( data.degreeU == null ) throw "DegreeU cannot be null!";
119 | if ( data.degreeV == null ) throw "DegreeV cannot be null!";
120 | #end
121 | if ( data.degreeU < 1 ) throw "DegreeU must be greater than 1!";
122 | if ( data.degreeV < 1 ) throw "DegreeV must be greater than 1!";
123 | if ( data.knotsU == null ) throw "KnotsU cannot be null!";
124 | if ( data.knotsV == null ) throw "KnotsV cannot be null!";
125 |
126 | if ( data.knotsU.length != data.controlPoints.length + data.degreeU + 1 ){
127 | throw "controlPointsU.length + degreeU + 1 must equal knotsU.length!";
128 | }
129 |
130 | if ( data.knotsV.length != data.controlPoints[0].length + data.degreeV + 1 ){
131 | throw "controlPointsV.length + degreeV + 1 must equal knotsV.length!";
132 | }
133 |
134 | if (!Check.isValidKnotVector( data.knotsU, data.degreeU ) || !Check.isValidKnotVector( data.knotsV, data.degreeV )){
135 | throw "Invalid knot vector format! Should begin with degree + 1 repeats and end with degree + 1 repeats!";
136 | }
137 |
138 | return data;
139 | }
140 | }
141 |
--------------------------------------------------------------------------------
/src/verb/eval/Divide.hx:
--------------------------------------------------------------------------------
1 | package verb.eval;
2 |
3 | import verb.core.Mat;
4 | import verb.core.Data;
5 | import verb.core.Vec;
6 | import verb.core.Constants;
7 |
8 | using Lambda;
9 |
10 | // Divide provides various tools for dividing and splitting NURBS geometry.
11 |
12 | @:expose("eval.Divide")
13 | class Divide {
14 |
15 | //Split a NURBS surface in two at a given parameter
16 | //
17 | //**params**
18 | //
19 | //* The surface to split
20 | //* The parameter at which to split the surface
21 | //* Whether to split in the U direction or V direction of the surface
22 | //
23 | //**returns**
24 | //
25 | //* A length two array of new surfaces
26 |
27 | public static function surfaceSplit( surface : NurbsSurfaceData, u : Float, useV : Bool = false) : Array {
28 |
29 | var knots
30 | , degree
31 | , controlPoints;
32 |
33 | if (!useV) {
34 | controlPoints = Mat.transpose( surface.controlPoints );
35 | knots = surface.knotsU;
36 | degree = surface.degreeU;
37 | } else {
38 | controlPoints = surface.controlPoints;
39 | knots = surface.knotsV;
40 | degree = surface.degreeV;
41 | }
42 |
43 | var knots_to_insert = [ for (i in 0...degree+1) u ];
44 |
45 | var newpts0 = new Array>()
46 | , newpts1 = new Array>();
47 |
48 | var s = Eval.knotSpan( degree, u, knots );
49 | var res : NurbsCurveData = null;
50 |
51 | for (cps in controlPoints){
52 | res = Modify.curveKnotRefine( new NurbsCurveData(degree, knots, cps), knots_to_insert );
53 |
54 | newpts0.push( res.controlPoints.slice( 0, s + 1 ) );
55 | newpts1.push( res.controlPoints.slice( s + 1 ) );
56 | }
57 |
58 | var knots0 = res.knots.slice(0, s + degree + 2);
59 | var knots1 = res.knots.slice( s + 1 );
60 |
61 | if (!useV){
62 | newpts0 = Mat.transpose( newpts0 );
63 | newpts1 = Mat.transpose( newpts1 );
64 |
65 | return [ new NurbsSurfaceData(degree, surface.degreeV, knots0, surface.knotsV.copy(), newpts0 ),
66 | new NurbsSurfaceData(degree, surface.degreeV, knots1, surface.knotsV.copy(), newpts1 ) ];
67 | }
68 |
69 | //v dir
70 | return [ new NurbsSurfaceData(surface.degreeU, degree, surface.knotsU.copy(), knots0, newpts0 ),
71 | new NurbsSurfaceData(surface.degreeU, degree, surface.knotsU.copy(), knots1, newpts1 ) ];
72 | }
73 |
74 | //Split a NURBS curve into two parts at a given parameter
75 | //
76 | //**params**
77 | //
78 | //* NurbsCurveData object representing the curve
79 | //* location to split the curve
80 | //
81 | //**returns**
82 | //
83 | //* *Array* two new curves, defined by degree, knots, and control points
84 |
85 | public static function curveSplit( curve : NurbsCurveData, u : Float ) : Array {
86 |
87 | var degree = curve.degree
88 | , controlPoints = curve.controlPoints
89 | , knots = curve.knots;
90 |
91 | var knots_to_insert = [for (i in 0...degree+1) u];
92 | var res = Modify.curveKnotRefine( curve, knots_to_insert );
93 |
94 | var s = Eval.knotSpan( degree, u, knots );
95 |
96 | var knots0 = res.knots.slice(0, s + degree + 2);
97 | var knots1 = res.knots.slice( s + 1 );
98 |
99 | var cpts0 = res.controlPoints.slice( 0, s + 1 );
100 | var cpts1 = res.controlPoints.slice( s + 1 );
101 |
102 | return [
103 | new NurbsCurveData( degree, knots0, cpts0 ),
104 | new NurbsCurveData( degree, knots1, cpts1 )
105 | ];
106 |
107 | }
108 |
109 | //Divide a NURBS curve given a given number of times, including the end points. The result is not split curves
110 | //but a collection of `CurveLengthSample` objects that can be used for splitting. As with all arc length methods,
111 | //the result is an approximation.
112 | //
113 | //**params**
114 | //
115 | //* NurbsCurveData object representing the curve
116 | //* The number of parts to split the curve into
117 | //
118 | //**returns**
119 | //
120 | //* An array of `CurveLengthSample` objects
121 |
122 | public static function rationalCurveByEqualArcLength(curve : NurbsCurveData, num : Int) : Array {
123 |
124 | var tlen = Analyze.rationalCurveArcLength( curve );
125 | var inc = tlen / num;
126 |
127 | return Divide.rationalCurveByArcLength(curve, inc);
128 |
129 | }
130 |
131 | //Divide a NURBS curve given a given number of times, including the end points.
132 | //
133 | //**params**
134 | //
135 | //* NurbsCurveData object representing the curve
136 | //* The arc length separating the resultant samples
137 | //
138 | //**returns**
139 | //
140 | //* A sequence of `CurveLengthSample` objects
141 |
142 | public static function rationalCurveByArcLength(curve : NurbsCurveData, l : Float) : Array {
143 |
144 | var crvs = Modify.decomposeCurveIntoBeziers( curve )
145 | , crvlens = crvs.map(function(x){ return Analyze.rationalBezierCurveArcLength(x); })
146 | , totlen = Vec.sum(crvlens)
147 | , pts = [ new CurveLengthSample( curve.knots[0], 0.0 ) ];
148 |
149 | if (l > totlen) return pts;
150 |
151 | var inc = l
152 | , i = 0
153 | , lc = inc
154 | , runsum = 0.0
155 | , runsum1 = 0.0
156 | , u;
157 |
158 | while ( i < crvs.length ){
159 |
160 | runsum += crvlens[i];
161 |
162 | while ( lc < runsum + Constants.EPSILON ){
163 |
164 | u = Analyze.rationalBezierCurveParamAtArcLength( crvs[i], lc - runsum1, Constants.TOLERANCE, crvlens[i] );
165 |
166 | pts.push( new CurveLengthSample( u, lc ) );
167 | lc += inc;
168 |
169 | }
170 |
171 | runsum1 += crvlens[i];
172 |
173 | i++;
174 |
175 | }
176 |
177 | return pts;
178 |
179 | }
180 |
181 | }
182 |
183 |
184 | @:expose("eval.CurveLengthSample")
185 | class CurveLengthSample {
186 | public var u : Float;
187 | public var len : Float;
188 |
189 | public function new(u, len) {
190 | this.u = u;
191 | this.len = len;
192 | }
193 | }
194 |
195 |
--------------------------------------------------------------------------------
/src/verb/exe/Dispatcher.hx:
--------------------------------------------------------------------------------
1 | package verb.exe;
2 |
3 | #if js
4 | import verb.exe.WorkerPool;
5 | #else
6 | import verb.exe.ThreadPool;
7 | #end
8 |
9 | import promhx.Deferred;
10 | import promhx.Promise;
11 |
12 | @:expose("exe.Dispatcher")
13 | class Dispatcher {
14 |
15 | public static var THREADS : Int = 1;
16 |
17 | #if js
18 | private static var _workerPool : WorkerPool;
19 | #else
20 | private static var _threadPool : ThreadPool;
21 | #end
22 |
23 | private static var _init : Bool = false;
24 |
25 | private static function init() : Void {
26 |
27 | if (_init) return;
28 |
29 | #if js
30 | _workerPool = new WorkerPool( THREADS );
31 | #else
32 | _threadPool = new ThreadPool( THREADS );
33 | #end
34 |
35 | _init = true;
36 | }
37 |
38 | public static function dispatchMethod( classType : Class, methodName : String, args : Array ) : Promise {
39 |
40 | init();
41 |
42 | var def = new Deferred();
43 |
44 | var callback = function(x){
45 | def.resolve( x );
46 | };
47 |
48 | #if js
49 | _workerPool.addWork( Type.getClassName( classType ), methodName, args, callback );
50 | #else
51 | _threadPool.addTask(function(_ : Dynamic){ var r : Dynamic = Reflect.callMethod(classType, Reflect.field(classType, methodName), args ); return r; }, null, callback);
52 | #end
53 |
54 | return new Promise( def );
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/verb/exe/ThreadPool.hx:
--------------------------------------------------------------------------------
1 | package verb.exe;
2 |
3 | #if neko
4 | import neko.vm.Thread;
5 | import neko.vm.Mutex;
6 | #elseif cpp
7 | import cpp.vm.Thread;
8 | import cpp.vm.Mutex;
9 | #end
10 |
11 | #if (neko || cpp)
12 | private class PoolThread
13 | {
14 | private var thread:Thread;
15 | private var task:Dynamic->Dynamic;
16 | private var mutex:Mutex;
17 | public var started:Bool;
18 | private var _done:Bool;
19 | public var done(get, never):Bool;
20 | private function get_done():Bool
21 | {
22 | mutex.acquire();
23 | var d:Bool = _done;
24 | mutex.release();
25 | return d;
26 | }
27 | private var _result:Dynamic;
28 | public var result(get, never):Dynamic;
29 | private function get_result():Dynamic
30 | {
31 | mutex.acquire();
32 | var r:Dynamic = _result;
33 | mutex.release();
34 | return r;
35 | }
36 |
37 | public function new()
38 | {
39 | mutex = new Mutex();
40 | }
41 |
42 | public function start(task:Dynamic->Dynamic, arg:Dynamic):Void
43 | {
44 | this.task = task;
45 | started = true;
46 | _done = false;
47 | thread = Thread.create(doWork);
48 | thread.sendMessage(arg);
49 | }
50 |
51 | private function doWork():Void
52 | {
53 | var arg:Dynamic = Thread.readMessage(true);
54 | var ret:Dynamic = task(arg);
55 | mutex.acquire();
56 | _result = ret;
57 | _done = true;
58 | mutex.release();
59 | }
60 | }
61 | #end
62 |
63 | private typedef Task =
64 | {
65 | var id:Int;
66 | var task:Dynamic->Dynamic;
67 | var done:Bool;
68 | var arg:Dynamic;
69 | #if (neko || cpp)
70 | var thread:PoolThread;
71 | #end
72 | var onFinish:Dynamic->Void;
73 | }
74 |
75 | /**
76 | * ...
77 | * @author Kenton Hamaluik
78 | */
79 | class ThreadPool
80 | {
81 | #if (neko || cpp)
82 | private var numThreads:Int = 1;
83 | private var threads:Array;
84 | #end
85 | private var tasks:Array;
86 | private var nextID:Int = 0;
87 |
88 | public function new(numThreads:Int)
89 | {
90 | tasks = new Array ();
91 | #if (neko || cpp)
92 | this.numThreads = numThreads;
93 | threads = new Array();
94 | for (i in 0...this.numThreads)
95 | {
96 | threads.push(new PoolThread());
97 | }
98 | #end
99 | }
100 |
101 | public function addTask(task:Dynamic->Dynamic, arg:Dynamic, onFinish:Dynamic->Void):Void
102 | {
103 | tasks.push( { id: nextID, task: task, done: false, arg: arg, #if (neko || cpp) thread: null, #end onFinish: onFinish } );
104 | nextID++;
105 | }
106 |
107 | #if (neko || cpp)
108 | private function allTasksAreDone():Bool
109 | {
110 | for (task in tasks)
111 | if (!task.done)
112 | return false;
113 | return true;
114 | }
115 |
116 | private function getNextFreeThread():PoolThread
117 | {
118 | for (thread in threads)
119 | if (!thread.started)
120 | return thread;
121 | return null;
122 | }
123 | #end
124 |
125 | public function blockRunAllTasks():Void
126 | {
127 | #if (neko || cpp)
128 | while (!allTasksAreDone())
129 | {
130 | //get a free thread
131 | var thread:PoolThread = getNextFreeThread();
132 | //but if it doesn't exist, try again
133 | if (thread == null)
134 | continue;
135 |
136 | for (task in tasks)
137 | {
138 | //skip any tasks that are done
139 | if (task.done)
140 | continue;
141 |
142 | //if this task is currently being run, see if it's done yet
143 | if (task.thread != null && task.thread.started)
144 | {
145 | if (task.thread.done)
146 | {
147 | //yay, it finished!
148 | task.done = true;
149 | //reset the thread
150 | task.thread.started = false;
151 | //call the on finish function
152 | if (task.onFinish != null)
153 | task.onFinish(task.thread.result);
154 | }
155 | continue;
156 | }
157 |
158 | //ok, we have a task that needs running
159 | //and a thread to run it
160 | //combine forces!
161 | task.thread = thread;
162 | thread.start(task.task, task.arg);
163 |
164 | //break to try to assign the next thread
165 | break;
166 | }
167 | }
168 | #else
169 | for (task in tasks)
170 | {
171 | if (task.onFinish != null)
172 | task.onFinish(task.task(task.arg));
173 | }
174 | #end
175 |
176 | //clear the old tasks
177 | tasks = new Array();
178 | }
179 | }
180 |
--------------------------------------------------------------------------------
/src/verb/exe/WorkerPool.hx:
--------------------------------------------------------------------------------
1 | package verb.exe;
2 |
3 | #if js
4 |
5 | import haxe.ds.IntMap;
6 |
7 | import js.html.Worker;
8 |
9 | // `WorkerPool` provides a pool of WebWorker objects for concurrent evaluation in JavaScript
10 |
11 | @:expose("exe.WorkerPool")
12 | class WorkerPool {
13 |
14 | private var _queue : Array = [];
15 | private var _pool : Array = [];
16 | private var _working = new IntMap();
17 | private var _callbacks = new IntMap();
18 |
19 | // Create a new `WorkerPool`
20 | //
21 | //**params**
22 | //
23 | //* the number of `Worker` threads to form
24 | //* the filename of verb's javascript file - defaults to "verb.js". The final path is formed by concatenating `WorkerPool.basePath` and this.
25 |
26 | public function new( numThreads : Int = 1, fileName : String = "verb.js" ) {
27 |
28 | for (i in 0...numThreads){
29 | var w : Worker;
30 | try {
31 | w = new Worker( basePath + fileName );
32 | } catch (e : Dynamic ) {
33 | w = new Worker( basePath + fileName.substring(0,-3) + ".min.js" );
34 | }
35 |
36 | _pool.push( w );
37 | }
38 | }
39 |
40 | // The base path to look for verb's source code
41 |
42 | public static var basePath = "";
43 |
44 | // Add work to perform to the queue
45 |
46 | public function addWork( className : String,
47 | methodName : String,
48 | args : Array,
49 | callback : Dynamic ) : Void {
50 |
51 | var work = new Work( className, methodName, args );
52 | _callbacks.set(work.id, callback);
53 | _queue.push( work );
54 |
55 | processQueue();
56 | }
57 |
58 | private function processQueue() {
59 |
60 | while (_queue.length > 0 && _pool.length > 0) {
61 |
62 | var work = _queue.shift();
63 | var workId = work.id;
64 |
65 | var worker = _pool.shift();
66 |
67 | _working.set(workId, worker);
68 |
69 | //upon completing your task...
70 | worker.onmessage = function( e ){
71 |
72 | _working.remove( workId );
73 | _pool.push( worker );
74 |
75 | try {
76 | if ( _callbacks.exists( workId ) )
77 | {
78 | _callbacks.get( workId )( e.data.result );
79 | _callbacks.remove( workId );
80 | }
81 | } catch(error : Dynamic) {
82 | trace( error );
83 | }
84 |
85 | processQueue();
86 | };
87 |
88 | worker.postMessage( work );
89 | }
90 | }
91 |
92 | }
93 |
94 | private class Work {
95 |
96 | private static var uuid : Int = 0;
97 |
98 | public var className : String;
99 | public var methodName : String;
100 | public var args : Array;
101 | public var id : Int;
102 |
103 | public function new(className, methodName, args){
104 | this.className = className;
105 | this.methodName = methodName;
106 | this.args = args;
107 | this.id = uuid++;
108 | }
109 | }
110 |
111 | #end
112 |
113 |
--------------------------------------------------------------------------------
/src/verb/geom/Arc.hx:
--------------------------------------------------------------------------------
1 | package verb.geom;
2 |
3 | import verb.eval.Eval;
4 | import verb.eval.Make;
5 | import verb.core.Vec;
6 | import verb.core.Data;
7 |
8 | import haxe.Serializer;
9 | import haxe.Unserializer;
10 |
11 | // An Arc is a three dimensional curve representing a subset of a full Circle
12 |
13 | @:expose("geom.Arc")
14 | class Arc extends NurbsCurve {
15 |
16 | //Constructor for Arc
17 | //
18 | //**params**
19 | //
20 | //* Length 3 array representing the center of the arc
21 | //* Length 3 array representing the xaxis
22 | //* Length 3 array representing the perpendicular yaxis
23 | //* Radius of the arc arc
24 | //* Start angle in radians
25 | //* End angle in radians
26 |
27 | public function new( center : Point,
28 | xaxis : Vector,
29 | yaxis : Vector,
30 | radius : Float,
31 | minAngle : Float,
32 | maxAngle : Float ) {
33 | super( Make.arc(center, xaxis, yaxis, radius, minAngle, maxAngle ) );
34 |
35 | _center = center;
36 | _xaxis = xaxis;
37 | _yaxis = yaxis;
38 | _radius = radius;
39 | _minAngle = minAngle;
40 | _maxAngle = maxAngle;
41 | }
42 |
43 | private var _center : Point;
44 | private var _xaxis : Vector;
45 | private var _yaxis : Vector;
46 | private var _radius : Float;
47 | private var _minAngle : Float;
48 | private var _maxAngle : Float;
49 |
50 | //Length 3 array representing the center of the arc
51 | public function center() : Point { return _center; }
52 |
53 | //Length 3 array representing the xaxis
54 | public function xaxis() : Vector { return _xaxis; }
55 |
56 | //Length 3 array representing the perpendicular yaxis
57 | public function yaxis() : Vector { return _yaxis; }
58 |
59 | //Radius of the arc
60 | public function radius() : Float { return _radius; }
61 |
62 | //Start angle in radians
63 | public function minAngle() : Float { return _minAngle; }
64 |
65 | //End angle in radians
66 | public function maxAngle() : Float { return _maxAngle; }
67 |
68 | }
--------------------------------------------------------------------------------
/src/verb/geom/BezierCurve.hx:
--------------------------------------------------------------------------------
1 | package verb.geom;
2 |
3 | import haxe.io.Error;
4 | import verb.eval.Eval;
5 | import verb.eval.Make;
6 | import verb.core.Vec;
7 | import verb.core.Data;
8 |
9 | //A Bezier curve is a common spline curve
10 | @:expose("geom.BezierCurve")
11 | class BezierCurve extends NurbsCurve {
12 |
13 | //Create a bezier curve
14 | //
15 | //**params**
16 | //
17 | //* Array of control points
18 | //* Array of control point weights (optional)
19 |
20 | public function new( points : Array, weights : Array = null ) {
21 | super( Make.rationalBezierCurve( points, weights ) );
22 | }
23 | }
--------------------------------------------------------------------------------
/src/verb/geom/Circle.hx:
--------------------------------------------------------------------------------
1 | package verb.geom;
2 |
3 | import verb.core.Data;
4 | import verb.core.Vec;
5 |
6 | import verb.eval.Make;
7 |
8 | // A Circle is a three dimensional curve representing the points that are equidistant from a point in a particular plane
9 |
10 | @:expose("geom.Circle")
11 | class Circle extends Arc {
12 |
13 | //Create a circle
14 | //
15 | //**params**
16 | //
17 | //* Length 3 array representing the center of the circle
18 | //* Length 3 array representing the xaxis
19 | //* Length 3 array representing the perpendicular yaxis
20 | //* Radius of the circle
21 |
22 | public function new( center : Point,
23 | xaxis : Vector,
24 | yaxis : Vector,
25 | radius : Float ) {
26 | super( center, xaxis, yaxis, radius, 0, Math.PI * 2 );
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/verb/geom/ConicalSurface.hx:
--------------------------------------------------------------------------------
1 | package verb.geom;
2 |
3 | import verb.eval.Make;
4 | import verb.core.Data;
5 | import verb.core.Vec;
6 |
7 | // A ConicalSurface is a surface making up the curve surface of a cone
8 |
9 | @:expose("geom.ConicalSurface")
10 | class ConicalSurface extends NurbsSurface {
11 |
12 | //Make a conical surface
13 | //
14 | //**params**
15 | //
16 | //* Length 3 array representing the axis of the cone
17 | //* Length 3 array representing the x axis, perpendicular to the axis
18 | //* Length 3 array representing the base of the cone
19 | //* Height of the cone
20 | //* Radius of the cone
21 |
22 | public function new(axis : Vector, xaxis : Vector, base : Point, height : Float, radius : Float ) {
23 | super( Make.conicalSurface(axis, xaxis, base, height, radius ));
24 |
25 | _axis = axis;
26 | _xaxis = xaxis;
27 | _base = base;
28 | _height = height;
29 | _radius = radius;
30 | }
31 |
32 | private var _axis : Vector;
33 | private var _xaxis : Vector;
34 | private var _base : Point;
35 | private var _height : Float;
36 | private var _radius : Float;
37 |
38 | //Length 3 array representing the axis of the cone
39 | public function axis(){ return _axis; }
40 |
41 | //Length 3 array representing the x axis, perpendicular to the axis
42 | public function xaxis(){ return _xaxis; }
43 |
44 | //Length 3 array representing the base of the cone
45 | public function base(){ return _base; }
46 |
47 | //Height of the cone
48 | public function height(){ return _height; }
49 |
50 | //Radius of the cone
51 | public function radius(){ return _radius; }
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/src/verb/geom/CylindricalSurface.hx:
--------------------------------------------------------------------------------
1 | package verb.geom;
2 |
3 |
4 | import verb.eval.Make;
5 | import verb.core.Mat;
6 | import verb.core.Vec;
7 | import verb.core.Data;
8 |
9 | // A CylindricalSurface is a surface making up the curve surface of a cylinder
10 |
11 | @:expose("geom.CylindricalSurface")
12 | class CylindricalSurface extends NurbsSurface {
13 |
14 | //Constructor for Cylinder
15 | //
16 | //**params**
17 | //
18 | //* Length 3 array representing the axis of the cylinder
19 | //* Length 3 array representing the x axis, perpendicular to the axis
20 | //* Length 3 array representing the base of the cylinder
21 | //* Height of the cylinder
22 | //* Radius of the cylinder
23 |
24 | public function new(axis : Vector, xaxis : Vector, base : Point, height : Float, radius : Float) {
25 | super(Make.cylindricalSurface(axis, xaxis, base, height, radius));
26 |
27 | _axis = axis;
28 | _xaxis = xaxis;
29 | _base = base;
30 | _height = height;
31 | _radius = radius;
32 | }
33 |
34 | private var _axis : Vector;
35 | private var _xaxis : Vector;
36 | private var _base : Point;
37 | private var _height : Float;
38 | private var _radius : Float;
39 |
40 | //Length 3 array representing the axis of the cylinder
41 | public function axis(){ return _axis; }
42 |
43 | //Length 3 array representing the x axis, perpendicular to the axis
44 | public function xaxis(){ return _xaxis; }
45 |
46 | //Length 3 array representing the base of the cylinder
47 | public function base(){ return _base; }
48 |
49 | //Height of the cylinder
50 | public function height(){ return _height; }
51 |
52 | //Radius of the cylinder
53 | public function radius(){ return _radius; }
54 | }
55 |
--------------------------------------------------------------------------------
/src/verb/geom/Ellipse.hx:
--------------------------------------------------------------------------------
1 | package verb.geom;
2 |
3 | import verb.core.Vec;
4 | import verb.core.Data;
5 |
6 | // A CylindricalSurface is a surface making up part of a cylinder.
7 |
8 | @:expose("geom.Ellipse")
9 | class Ellipse extends EllipseArc {
10 |
11 | //Create an ellipse
12 | //
13 | //**params**
14 | //
15 | //
16 | //* Length 3 array representing the center of the circle
17 | //* Length 3 array representing the xaxis
18 | //* Length 3 array representing the perpendicular yaxis
19 |
20 | public function new( center : Point,
21 | xaxis : Vector,
22 | yaxis : Vector ) {
23 | super( center, xaxis, yaxis, 0, Math.PI * 2 );
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/verb/geom/EllipseArc.hx:
--------------------------------------------------------------------------------
1 | package verb.geom;
2 |
3 | import verb.eval.Eval;
4 | import verb.eval.Make;
5 | import verb.core.Vec;
6 | import verb.core.Data;
7 |
8 | // An EllipseArc is a subset of an Ellipse
9 |
10 | @:expose("geom.EllipseArc")
11 | class EllipseArc extends NurbsCurve {
12 |
13 | //Create an EllipseArc
14 | //
15 | //**params**
16 | //
17 | //* Length 3 array representing the center of the arc
18 | //* Length 3 array representing the xaxis
19 | //* Length 3 array representing the perpendicular yaxis
20 | //* Minimum angle of the EllipseArc
21 | //* Maximum angle of the EllipseArc
22 |
23 | public function new( center : Point,
24 | xaxis : Vector,
25 | yaxis : Vector,
26 | minAngle : Float,
27 | maxAngle : Float ) {
28 | super( Make.ellipseArc(center, xaxis, yaxis, minAngle, maxAngle) );
29 |
30 | _center = center;
31 | _xaxis = xaxis;
32 | _yaxis = yaxis;
33 | _minAngle = minAngle;
34 | _maxAngle = maxAngle;
35 | }
36 |
37 | private var _center : Point;
38 | private var _xaxis : Vector;
39 | private var _yaxis : Vector;
40 | private var _minAngle : Float;
41 | private var _maxAngle : Float;
42 |
43 | //Length 3 array representing the center of the arc
44 | public function center(){ return _center; }
45 |
46 | //Length 3 array representing the xaxis
47 | public function xaxis(){ return _xaxis; }
48 |
49 | //Length 3 array representing the perpendicular yaxis
50 | public function yaxis(){ return _yaxis; }
51 |
52 | //Minimum angle of the EllipseArc
53 | public function minAngle(){ return _minAngle; }
54 |
55 | //Maximum angle of the EllipseArc
56 | public function maxAngle(){ return _maxAngle; }
57 |
58 |
59 | }
--------------------------------------------------------------------------------
/src/verb/geom/ExtrudedSurface.hx:
--------------------------------------------------------------------------------
1 | package verb.geom;
2 | import verb.eval.Make;
3 | import verb.core.Vec;
4 | import verb.core.Data;
5 |
6 | // Form a Surface by extruding a curve along a vector
7 |
8 | @:expose("geom.ExtrudedSurface")
9 | class ExtrudedSurface extends NurbsSurface {
10 |
11 | //Construct a Surface by extruding a curve
12 | //
13 | //**params**
14 | //
15 | //* The profile curve
16 | //* The direction and magnitude of the extrusion
17 |
18 | public function new( profile : ICurve, direction : Vector ) {
19 | super( Make.extrudedSurface( Vec.normalized( direction ), Vec.norm( direction ), profile.asNurbs() ));
20 |
21 | _profile = profile;
22 | _direction = direction;
23 | }
24 |
25 | private var _profile : ICurve;
26 | private var _direction : Vector;
27 |
28 | //The profile curve
29 |
30 | public function profile() : ICurve { return _profile; }
31 |
32 | //The direction and magnitude of the extrusion
33 |
34 | public function direction() : Vector { return _direction; }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/src/verb/geom/ICurve.hx:
--------------------------------------------------------------------------------
1 | package verb.geom;
2 |
3 | import verb.core.Data;
4 | import verb.core.Vec;
5 | import verb.core.Mat;
6 | import verb.core.Serialization;
7 |
8 | //An interface representing a Curve
9 |
10 | interface ICurve extends ISerializable {
11 |
12 | //Provide the NURBS representation of the curve
13 | //
14 | //**returns**
15 | //
16 | //* A NurbsCurveData object representing the curve
17 |
18 | function asNurbs() : NurbsCurveData;
19 |
20 | //Obtain the parametric domain of the curve
21 | //
22 | //**returns**
23 | //
24 | //* An Interval object containing the min and max of the domain
25 |
26 | function domain() : Interval;
27 |
28 | //Evaluate a point on the curve
29 | //
30 | //**params**
31 | //
32 | //* The parameter on the curve
33 | //
34 | //**returns**
35 | //
36 | //* The evaluated point
37 |
38 | function point(u : Float) : Point;
39 |
40 | //Evaluate the derivatives at a point on a curve
41 | //
42 | //**params**
43 | //
44 | //* The parameter on the curve
45 | //* The number of derivatives to evaluate on the curve
46 | //
47 | //**returns**
48 | //
49 | //* An array of derivative vectors
50 |
51 | function derivatives(u : Float, numDerivs : Int = 1) : Array;
52 | }
53 |
--------------------------------------------------------------------------------
/src/verb/geom/ISurface.hx:
--------------------------------------------------------------------------------
1 | package verb.geom;
2 |
3 | import verb.core.Data;
4 | import verb.core.Vec;
5 | import verb.core.Serialization;
6 |
7 | import verb.core.Mat;
8 |
9 | // An interface representing a Surface
10 |
11 | interface ISurface extends ISerializable {
12 |
13 | //Provide the NURBS representation of the curve
14 | //
15 | //**returns**
16 | //
17 | //* A NurbsCurveData object representing the curve
18 |
19 | function asNurbs() : NurbsSurfaceData;
20 |
21 | //Provide the domain of the surface in the U direction
22 | //
23 | //**returns**
24 | //
25 | //* An interval object with min and max properties
26 |
27 | function domainU() : Interval;
28 |
29 | //Provide the domain of the surface in the V direction
30 | //
31 | //**returns**
32 | //
33 | //* An interval object with min and max properties
34 |
35 | function domainV() : Interval;
36 |
37 | //Obtain a point on the surface at the given parameter
38 | //
39 | //**params**
40 | //
41 | //* The u parameter
42 | //* The v parameter
43 | //
44 | //**returns**
45 | //
46 | //* A point on the surface
47 |
48 | function point(u : Float, v : Float) : Point;
49 |
50 | //Obtain the derivatives of the NurbsSurface. Returns a two dimensional array
51 | //containing the derivative vectors. Increasing U partial derivatives are increasing
52 | //row-wise. Increasing V partial derivatives are increasing column-wise. Therefore,
53 | //the [0][0] position is a point on the surface, [n][0] is the nth V partial derivative,
54 | //the [1][1] position is twist vector or mixed partial derivative Puv.
55 | //
56 | //**params**
57 | //
58 | //* The u parameter
59 | //* The v parameter
60 | //* Number of derivatives to evaluate
61 | //
62 | //**returns**
63 | //
64 | //* A two dimensional array of vectors
65 |
66 | function derivatives(u : Float, v : Float, numDerivs : Int = 1) : Array>;
67 |
68 | }
69 |
--------------------------------------------------------------------------------
/src/verb/geom/Intersect.hx:
--------------------------------------------------------------------------------
1 | package verb.geom;
2 |
3 | import promhx.Promise;
4 |
5 | import verb.core.Vec;
6 | import verb.core.Data;
7 | import verb.exe.Dispatcher;
8 | import verb.core.Intersections;
9 |
10 | using verb.core.Vec;
11 |
12 | // A class providing simplified access to verb's intersection tools. Intersect contains only static methods.
13 | //
14 | // Similar to `NurbsCurve` and `NurbsSurface`, `Intersect` provides asynchronous versions of all of its methods.
15 |
16 | @:expose("geom.Intersect")
17 | class Intersect {
18 |
19 | //Determine the intersection of two curves
20 | //
21 | //**params**
22 | //
23 | //* ICurve object
24 | //* ICurve object
25 | //* tolerance for the intersection
26 | //
27 | //**returns**
28 | //
29 | //* a possibly empty array of CurveCurveIntersection objects
30 |
31 | public static function curves( first : ICurve, second : ICurve, tol : Float = 1e-3 ) : Array {
32 | return verb.eval.Intersect.curves( first.asNurbs(), second.asNurbs(), tol );
33 | }
34 |
35 | // The async version of `curves`
36 |
37 | public static function curvesAsync( first : ICurve, second : ICurve, tol : Float = 1e-3 ) : Promise> {
38 | return Dispatcher.dispatchMethod( verb.eval.Intersect, "curves", [first.asNurbs(), second.asNurbs(), tol ]);
39 | }
40 |
41 | //Determine the intersection of a curve and a surface
42 | //
43 | //**params**
44 | //
45 | //* ICurve
46 | //* ISurface
47 | //* tolerance for the curve intersection
48 | //
49 | //**returns**
50 | //
51 | //* array of CurveSurfaceIntersection objects
52 |
53 | public static function curveAndSurface( curve : ICurve, surface : ISurface, tol : Float = 1e-3 ) : Array {
54 | return verb.eval.Intersect.curveAndSurface( curve.asNurbs(), surface.asNurbs(), tol);
55 | }
56 |
57 | // The async version of `curveAndSurface`
58 |
59 | public static function curveAndSurfaceAsync( curve : ICurve, surface : ISurface, tol : Float = 1e-3 ) : Promise> {
60 | return Dispatcher.dispatchMethod( verb.eval.Intersect, "curveAndSurface", [curve.asNurbs(), surface.asNurbs(), tol ]);
61 | }
62 |
63 | //Determine the intersection of two surfaces
64 | //
65 | //**params**
66 | //
67 | //* ISurface
68 | //* ISurface
69 | //
70 | //**returns**
71 | //
72 | //* array of NurbsCurveData objects
73 |
74 | public static function surfaces( first : ISurface, second : ISurface, tol : Float = 1e-3 ) : Array {
75 | return verb.eval.Intersect.surfaces( first.asNurbs(), second.asNurbs(), tol )
76 | .map(function(cd){ return new NurbsCurve(cd); });
77 | }
78 |
79 | // The async version of `surfaces`
80 |
81 | public static function surfacesAsync( first : ISurface, second : ISurface, tol : Float = 1e-3 ) : Promise> {
82 | return Dispatcher.dispatchMethod( verb.eval.Intersect, "surfaces", [first.asNurbs(), second.asNurbs(), tol])
83 | .then(function(cds){
84 | return cds.map(function(cd){ return new NurbsCurve(cd); });
85 | });
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/src/verb/geom/Line.hx:
--------------------------------------------------------------------------------
1 | package verb.geom;
2 |
3 | import verb.eval.Eval;
4 | import verb.eval.Make;
5 | import verb.core.Vec;
6 | import verb.core.Data;
7 |
8 |
9 | // A curve representing a straight line
10 | @:expose("geom.Line")
11 | class Line extends NurbsCurve {
12 |
13 | //Create a line
14 | //
15 | //**params**
16 | //
17 | //* Length 3 array representing the start point
18 | //* Length 3 array representing the end point
19 |
20 | public function new( start : Point, end : Point ) {
21 | super( Make.polyline( [ start, end ] ) );
22 |
23 | _start = start;
24 | _end = end;
25 | }
26 |
27 | private var _start : Point;
28 | private var _end : Point;
29 |
30 | //Length 3 array representing the start point
31 | public function start(){ return _start; }
32 |
33 | //Length 3 array representing the end point
34 | public function end(){ return _end; }
35 |
36 | }
--------------------------------------------------------------------------------
/src/verb/geom/RevolvedSurface.hx:
--------------------------------------------------------------------------------
1 | package verb.geom;
2 |
3 | import verb.core.Data;
4 | import verb.core.Vec;
5 | import verb.eval.Make;
6 |
7 | // A surface formed by revolving a profile curve around a given axis line
8 |
9 | @:expose("geom.RevolvedSurface")
10 | class RevolvedSurface extends NurbsSurface {
11 |
12 | //Construct a revolved surface
13 | //
14 | //**params**
15 | //
16 | //* The profile curve
17 | //* A point on the axis of revolution
18 | //* The direction of the axis of revolution
19 | //* The angle to revolve around. 2 * Math.PI corresponds to a complete revolution
20 |
21 | public function new( profile : NurbsCurve, center : Point, axis : Vector, angle : Float ) {
22 | super( Make.revolvedSurface( profile.asNurbs(), center, axis, angle ) );
23 |
24 | _profile = profile;
25 | _center = center;
26 | _axis = axis;
27 | _angle = angle;
28 | }
29 |
30 | private var _profile : ICurve;
31 | private var _center : Point;
32 | private var _axis : Vector;
33 | private var _angle : Float;
34 |
35 | //The profile curve
36 |
37 | public function profile() : ICurve { return _profile; }
38 |
39 | //A point on the axis of revolution
40 |
41 | public function center() : Point { return _center; }
42 |
43 | //The direction of the axis of revolution
44 |
45 | public function axis() : Vector { return _center; }
46 |
47 | //The angle to revolve around. 2 * Math.PI corresponds to a complete revolution
48 |
49 | public function angle() : Float { return _angle; }
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/src/verb/geom/SphericalSurface.hx:
--------------------------------------------------------------------------------
1 | package verb.geom;
2 |
3 | import verb.eval.Make;
4 | import verb.core.Vec;
5 | import verb.core.Data;
6 | import verb.core.Mat;
7 |
8 | // A surface representing the doubly curved surface of a sphere
9 |
10 | @:expose("geom.SphericalSurface")
11 | class SphericalSurface extends NurbsSurface {
12 |
13 | //Create a spherical surface
14 | //
15 | //**params**
16 | //
17 | //* Length 3 array representing the center of the circle
18 | //* Radius of the circle
19 |
20 | public function new( center : Point,
21 | radius : Float ) {
22 | super( Make.sphericalSurface( center, [0,0,1], [1,0,0], radius ));
23 |
24 | _center = center;
25 | _radius = radius;
26 | }
27 |
28 | private var _center : Point;
29 | private var _radius : Float;
30 |
31 | //Length 3 array representing the center of the circle
32 |
33 | public function center() : Point{ return _center; }
34 |
35 | //Radius of the circle
36 |
37 | public function radius() : Float{ return _radius; }
38 |
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/src/verb/geom/SweptSurface.hx:
--------------------------------------------------------------------------------
1 | package verb.geom;
2 |
3 | import verb.eval.Make;
4 | import verb.core.Vec;
5 | import verb.core.Data;
6 |
7 | // A SweptSurface uses a profile curve and a guide rail to form a surface. The profile curve is "swept" along the guide
8 | // rail by a lofting operation.
9 |
10 | @:expose("geom.SweptSurface")
11 | class SweptSurface extends NurbsSurface {
12 |
13 | //Construct a Surface by translating along a rail curve
14 | //
15 | //**params**
16 | //
17 | //* The profile curve
18 | //* The rail curve
19 |
20 | public function new( profile : ICurve, rail : ICurve ) {
21 | super( Make.rationalTranslationalSurface( profile.asNurbs(), rail.asNurbs() ));
22 |
23 | _profile = profile;
24 | _rail = rail;
25 | }
26 |
27 | private var _profile : ICurve;
28 | private var _rail : ICurve;
29 |
30 | //The profile curve
31 |
32 | public function profile() : ICurve { return _profile; }
33 |
34 | //The rail curve
35 |
36 | public function rail() : ICurve { return _rail; }
37 |
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/todo:
--------------------------------------------------------------------------------
1 | Documentation generation - docco no longer works, always sucked anyways
2 | Update website
3 |
4 | Split
5 | Holes are not recognized
6 |
7 | SweptSurface
8 | More efficient representation for surface tessellation, don't use 2d arrays
9 | More exact srf-srf intersection
10 | Marching surface-Surface intersection
11 | SurfaceClosestPoint occasionally fails when point is far from surface - need to check for wild derivatives
12 | Curve interpolation with sparse matrices
13 | Curve approximation
14 | verb.eval.Make.interpCurve with tangents is numerically unstable, implementation likely wrong
--------------------------------------------------------------------------------
/verb.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------