diff --git a/README.md b/README.md index ef1903e5..592ba043 100644 --- a/README.md +++ b/README.md @@ -144,7 +144,7 @@ These examples incubate dotSCAD and dotSCAD refactors these examples. See [examp - [util/fibseq](https://openhome.cc/eGossip/OpenSCAD/lib2x-fibseq.html) - [util/bsearch](https://openhome.cc/eGossip/OpenSCAD/lib3x-bsearch.html) - [util/has](https://openhome.cc/eGossip/OpenSCAD/lib2x-has.html) -- [util/dedup](https://openhome.cc/eGossip/OpenSCAD/lib2x-dedup.html) +- [util/dedup](https://openhome.cc/eGossip/OpenSCAD/lib3x-dedup.html) - [util/flat](https://openhome.cc/eGossip/OpenSCAD/lib2x-flat.html) - [util/sum](https://openhome.cc/eGossip/OpenSCAD/lib2x-sum.html) - [util/zip](https://openhome.cc/eGossip/OpenSCAD/lib2x-zip.html) diff --git a/docs/images/lib2x-dedup-1.JPG b/docs/images/lib2x-dedup-1.JPG deleted file mode 100644 index 9664cf48..00000000 Binary files a/docs/images/lib2x-dedup-1.JPG and /dev/null differ diff --git a/docs/images/lib2x-dedup-2.JPG b/docs/images/lib2x-dedup-2.JPG deleted file mode 100644 index c33b9c64..00000000 Binary files a/docs/images/lib2x-dedup-2.JPG and /dev/null differ diff --git a/docs/lib2x-dedup.md b/docs/lib2x-dedup.md deleted file mode 100644 index c9b1b7eb..00000000 --- a/docs/lib2x-dedup.md +++ /dev/null @@ -1,45 +0,0 @@ -# dedup - -Eliminating duplicate copies of repeating vectors. If `lt` has a large number of elements, sorting `lt` first and setting `sorted` to `true` will be faster. - -**Since:** 2.3 - -## Parameters - -- `lt` : A list of vectors. -- `sorted` : If `false` (default), use native `search`. If `true`, `lt` must be sorted by zyx (from the last index to the first one) and `dedup` will use binary search internally. - -## Examples - - use ; - use ; - - pts1 = vx_circle(10, filled = true); - pts2 = [for(p = vx_circle(5, filled = true)) p + [10, 0]]; - - // simple union - pts3 = dedup(concat(pts1, pts2)); - for(p = pts3) { - translate(p) - square(1, center = true); - } - -![dedup](images/lib2x-dedup-1.JPG) - - use ; - use ; - use ; - - pts1 = vx_circle(20, filled = true); - pts2 = [for(p = vx_circle(10, filled = true)) p + [20, 0]]; - - sorted_pts = sort(concat(pts1, pts2), by = "vt"); - - // simple union - pts3 = dedup(sorted_pts, sorted = true); - for(p = pts3) { - translate(p) - square(1, center = true); - } - -![dedup](images/lib2x-dedup-2.JPG) \ No newline at end of file diff --git a/docs/lib3x-dedup.md b/docs/lib3x-dedup.md new file mode 100644 index 00000000..44481888 --- /dev/null +++ b/docs/lib3x-dedup.md @@ -0,0 +1,36 @@ +# dedup + +Eliminating duplicate copies of repeating vectors. If `lt` has a large number of elements, sorting `lt` first and setting `sorted` to `true` will be faster. + +**Since:** 2.3 + +## Parameters + +- `lt` : A list of vectors. +- `sorted` : If `false` (default), use native `search`. If `true`, `lt` must be sorted by zyx (from the last index to the first one) and `dedup` will use binary search internally. +- `eq` : A equality function. If it's ignored, use `==` to compare elements. **Since: ** 3.0 + +## Examples + + eq = function(e1, e2) e1[0] == e2[0] && e1[1] == e2[1] && e1[2] == e2[2]; + + points = [[1, 1, 2], [3, 4, 2], [7, 2, 2], [3, 4, 2], [1, 2, 3]]; + assert( + dedup([[1, 1, 2], [3, 4, 2], [7, 2, 2], [3, 4, 2], [1, 2, 3]]) + == [[1, 1, 2], [3, 4, 2], [7, 2, 2], [1, 2, 3]] + ); + + assert( + dedup([[1, 1, 2], [3, 4, 2], [7, 2, 2], [3, 4, 2], [1, 2, 3]], eq = eq) + == [[1, 1, 2], [3, 4, 2], [7, 2, 2], [1, 2, 3]] + ); + + sorted = sort([[1, 1, 2], [3, 4, 2], [7, 2, 2], [3, 4, 2], [1, 2, 3]]); + + assert( + dedup(sorted, sorted = true) == [[1, 1, 2], [1, 2, 3], [3, 4, 2], [7, 2, 2]] + ); + + assert( + dedup(sorted, sorted = true, eq = eq) == [[1, 1, 2], [1, 2, 3], [3, 4, 2], [7, 2, 2]] + ); \ No newline at end of file diff --git a/src/experimental/note.md b/src/experimental/note.md index cb749749..dc13b94b 100644 --- a/src/experimental/note.md +++ b/src/experimental/note.md @@ -5,4 +5,5 @@ to_do: dotSCAD 3.0 Dev - `util/sort`: `by` accepts a function literal. -- `util/bsearch`: only supports `sorted` and `target` parameters. I view it as a new function. \ No newline at end of file +- `util/bsearch`: only supports `sorted` and `target` parameters. I view it as a new function. +- `util/dedup`: add the `eq` parameter. \ No newline at end of file diff --git a/src/util/_impl/_dedup_impl.scad b/src/util/_impl/_dedup_impl.scad index 65f9f0d9..425ba329 100644 --- a/src/util/_impl/_dedup_impl.scad +++ b/src/util/_impl/_dedup_impl.scad @@ -1,13 +1,31 @@ -use <../has.scad>; - -function _dedup_sorted(lt, leng) = +function _dedup_sorted(lt, leng, eq) = leng == 0 ? lt : - concat( - [lt[0]], - [for(i = [1:leng - 1]) if(lt[i] != lt[i - 1]) lt[i]] - ); + is_function(eq) ? + concat( + [lt[0]], + [for(i = [1:leng - 1]) if(!eq(lt[i], lt[i - 1])) lt[i]] + ) : + concat( + [lt[0]], + [for(i = [1:leng - 1]) if(lt[i] != lt[i - 1]) lt[i]] + ); -function _dedup(src, dest, leng, i = 0) = +function _some(dest, assert_func, leng, i = 0) = + i == leng ? false : + assert_func(dest[i]) ? true : _some(dest, assert_func, leng, i + 1); + +function some(dest, assert_func) = _some(dest, assert_func, len(dest)); + +function _dedup_vt(src, dest, leng, i = 0) = i == leng ? dest : - has(dest, src[i]) ? _dedup(src, dest, leng, i + 1) : - _dedup(src, concat(dest, [src[i]]), leng, i + 1); \ No newline at end of file + // src[i] in dest ? + search([src[i]], dest) != [[]] ? _dedup_vt(src, dest, leng, i + 1) : + _dedup_vt(src, concat(dest, [src[i]]), leng, i + 1); + +function _dedup_eq(src, dest, eq, leng, i = 0) = + i == leng ? dest : + some(dest, function(el) eq(el, src[i])) ? _dedup_eq(src, dest, eq, leng, i + 1) : + _dedup_eq(src, concat(dest, [src[i]]), eq, leng, i + 1); + +function _dedup(src, dest, leng, eq) = + is_function(eq) ? _dedup_eq(src, dest, eq, leng) : _dedup_vt(src, dest, leng); \ No newline at end of file diff --git a/src/util/dedup.scad b/src/util/dedup.scad index f6f4d800..bfb9a50e 100644 --- a/src/util/dedup.scad +++ b/src/util/dedup.scad @@ -4,12 +4,11 @@ * @copyright Justin Lin, 2020 * @license https://opensource.org/licenses/lgpl-3.0.html * -* @see https://openhome.cc/eGossip/OpenSCAD/lib2x-dedup.html +* @see https://openhome.cc/eGossip/OpenSCAD/lib3x-dedup.html * **/ use <_impl/_dedup_impl.scad>; -function dedup(lt, sorted = false) = - sorted ? _dedup_sorted(lt, len(lt)) : - _dedup(lt, [], len(lt)); \ No newline at end of file +function dedup(lt, sorted = false, eq) = + sorted ? _dedup_sorted(lt, len(lt), eq) : _dedup(lt, [], len(lt), eq); \ No newline at end of file diff --git a/test/util/test_dedup.scad b/test/util/test_dedup.scad index 8ebd9160..798c6811 100644 --- a/test/util/test_dedup.scad +++ b/test/util/test_dedup.scad @@ -4,15 +4,27 @@ use ; module test_dedup() { echo("==== test_dedup ===="); + eq = function(e1, e2) e1[0] == e2[0] && e1[1] == e2[1] && e1[2] == e2[2]; + points = [[1, 1, 2], [3, 4, 2], [7, 2, 2], [3, 4, 2], [1, 2, 3]]; assert( dedup([[1, 1, 2], [3, 4, 2], [7, 2, 2], [3, 4, 2], [1, 2, 3]]) == [[1, 1, 2], [3, 4, 2], [7, 2, 2], [1, 2, 3]] ); - + assert( - dedup(sort([[1, 1, 2], [3, 4, 2], [7, 2, 2], [3, 4, 2], [1, 2, 3]]), sorted = true) - == [[1, 1, 2], [1, 2, 3], [3, 4, 2], [7, 2, 2]] + dedup([[1, 1, 2], [3, 4, 2], [7, 2, 2], [3, 4, 2], [1, 2, 3]], eq = eq) + == [[1, 1, 2], [3, 4, 2], [7, 2, 2], [1, 2, 3]] + ); + + sorted = sort([[1, 1, 2], [3, 4, 2], [7, 2, 2], [3, 4, 2], [1, 2, 3]]); + + assert( + dedup(sorted, sorted = true) == [[1, 1, 2], [1, 2, 3], [3, 4, 2], [7, 2, 2]] + ); + + assert( + dedup(sorted, sorted = true, eq = eq) == [[1, 1, 2], [1, 2, 3], [3, 4, 2], [7, 2, 2]] ); }