Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

split the input polyline into multiple polylines when there is Nan/Nu… #49

Merged
merged 9 commits into from
Dec 26, 2020
60 changes: 54 additions & 6 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const normalize = require('array-normalize')
const { float32, fract32 } = require('to-float32')
const WeakMap = require('es6-weak-map')
const parseRect = require('parse-rect')
const findIndex = require('array-find-index');


module.exports = Line2D
Expand Down Expand Up @@ -399,7 +400,8 @@ Line2D.prototype.update = function (options) {
close: 'closed close closed-path closePath',
range: 'range dataBox',
viewport: 'viewport viewBox',
hole: 'holes hole hollow'
hole: 'holes hole hollow',
splitNull: 'splitNull'
})

// init state
Expand Down Expand Up @@ -516,13 +518,60 @@ Line2D.prototype.update = function (options) {
pos[ptr++] = y
}

let triangles = triangulate(pos, state.hole || [])
// split the input into multiple polygon at Null/NaN
if(o.splitNull){
// use "ids" to track the boundary of segment
// the keys in "ids" is the end boundary of a segment, or split point

for (let i = 0, l = triangles.length; i < l; i++) {
if (ids[triangles[i]] != null) triangles[i] = ids[triangles[i]]
// make sure there is at least one segment
if(!(state.count-1 in ids)) ids[state.count] = state.count-1

let splits = Object.keys(ids).map(Number).sort((a, b) => a - b)

let split_triangles = []
let base = 0

// do not split holes
let hole_base = state.hole != null ? state.hole[0] : null
if(hole_base != null){
let last_id = findIndex(splits, (e)=>e>=hole_base)
splits = splits.slice(0,last_id)
splits.push(hole_base)
}

for (let i = 0; i < splits.length; i++)
{
// create temporary pos array with only one segment and all the holes
let seg_pos = pos.slice(base*2, splits[i]*2).concat(
hole_base ? pos.slice(hole_base*2) : []
)
let hole = (state.hole || []).map((e) => e-hole_base+(splits[i]-base) )
let triangles = triangulate(seg_pos, hole)
// map triangle index back to the original pos buffer
triangles = triangles.map(
(e)=> e + base + ((e + base < splits[i]) ? 0 : hole_base - splits[i])
)
split_triangles.push(...triangles)

// skip split point
base = splits[i] + 1
}
for (let i = 0, l = split_triangles.length; i < l; i++) {
if (ids[split_triangles[i]] != null) split_triangles[i] = ids[split_triangles[i]]
}

state.triangles = split_triangles
}
else {
// treat the wholw input as a single polygon
let triangles = triangulate(pos, state.hole || [])

for (let i = 0, l = triangles.length; i < l; i++) {
if (ids[triangles[i]] != null) triangles[i] = ids[triangles[i]]
}

state.triangles = triangles
state.triangles = triangles
}
}

// update position buffers
Expand Down Expand Up @@ -709,4 +758,3 @@ Line2D.prototype.destroy = function () {

return this
}

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@
"object-assign": "^4.1.1",
"parse-rect": "^1.2.0",
"pick-by-alias": "^1.2.0",
"to-float32": "^1.0.1"
"to-float32": "^1.0.1",
"array-find-index": "^1.0.2"
},
"devDependencies": {
"adaptive-bezier-curve": "^1.0.3",
Expand Down
28 changes: 27 additions & 1 deletion test.js
Original file line number Diff line number Diff line change
Expand Up @@ -177,13 +177,39 @@ t('fill', t => {
strokeWidth: 6,
stroke: '#D07735',
close: false,
positions: translate(scale([0,40, 40,40, 40,80, 80,80, 80,120, 120,120, 120,160],.015,.015), 2, -1.5),
positions: translate(scale([0,40, 40,40, 40,80, 80,80, 80,120, 120,120, 120,160],.015,.015), 1.5, -1.5),
range
})

t.end()
})

t('fill segment', t => {
batch.push({
fill: '#F9F38C',
thickness: 0,
close: false,
splitNull: true,
positions: translate(scale([0,40, 40,40, 40,80, NaN, NaN, 40,100, 80,100, 80,140, NaN, NaN, 80,150, 120,140, 120,160],.015,.015), 2.5, -1.5),
range
})
t.end()
})

t('fill segment with hole', t => {
batch.push({
fill: '#F9F38C',
thickness: 0,
close: false,
splitNull: true,
positions: translate(scale([0,40, 40,40, 40,80, NaN, NaN, 40,100, 80,100, 80,140, 20,50, 30,50, 30,55, NaN, NaN, 80,150, 120,140, 120,160],.015,.015), 3.5, -1.5),
hole: [7,11],
range
})

t.end()
})

t('colorscale', t => {
let positions = translate(scale(flatten(curve([4, 4], [7, 10], [12, 2], [20, 4], 5)), .25, .25), -3, -1)
let colors = arrFrom({ length: positions.length / 2 }).map(x => palette[Math.floor(Math.random() * palette.length)])
Expand Down