diff --git a/src/util/worker.js b/src/util/worker.js index 9ca462de1c0e246c9fa36df94b315c742d78d373..fcb83f3fb035c7408bce6ff9d9f63e70a798e988 100644 --- a/src/util/worker.js +++ b/src/util/worker.js @@ -47,7 +47,7 @@ const getIcoVertex = (pos, scale) => `-525731.0 0.0 850651.0 850651.0 -525731.0 0.0 -850651.0 -525731.0 0.0` .split('\n') - .map(line => + .map(line => line .split(' ') .map((string, idx) => (Number(string) * (scale ? scale : 1) + pos[idx]).toString() ) @@ -77,7 +77,7 @@ const getIcoPoly = (startingIdx) => `3 1 4 0 3 5 2 9 3 11 2 7` .split('\n') - .map((line) => + .map((line) => line .split(' ') .map((v,idx) => idx === 0 ? v : (Number(v) + startingIdx).toString() ) @@ -86,8 +86,8 @@ const getIcoPoly = (startingIdx) => `3 1 4 0 .join('\n') const getMeshVertex = (vertices) => vertices.map(vertex => vertex.join(' ')).join('\n') -const getMeshPoly = (polyIndices, currentIdx) => polyIndices.map(triplet => - '3 '.concat(triplet.map(index => +const getMeshPoly = (polyIndices, currentIdx) => polyIndices.map(triplet => + '3 '.concat(triplet.map(index => index + currentIdx ).join(' ')) ).join('\n') @@ -114,7 +114,7 @@ const parseLmToVtk = (landmarks, scale) => { else{ //curr[0] : [number,number,number][] vertices //curr[1] : [number,number,number][] indices for the vertices that poly forms - + /** * poly primitive */ @@ -137,7 +137,7 @@ const parseLmToVtk = (landmarks, scale) => { labelString : [], }) - // if no vertices are been rendered, do not replace old + // if no vertices are been rendered, do not replace old if(reduce.currentVertexIndex === 0) return false @@ -168,7 +168,7 @@ const getLandmarksVtk = (action) => { : 2.8 const vtk = parseLmToVtk(landmarks, scale) - + if(!vtk) return // when new set of landmarks are to be displayed, the old landmarks will be discarded @@ -228,7 +228,7 @@ const rebuildSelectedRegion = (payload) => { const activeTreeBranch = [] const isRegionActive = (region) => selectedRegions.some(r => r.name === region.name) || region.children && region.children.length > 0 && region.children.every(isRegionActive) - + /** * some active tree branch * branch is active if SOME children are active @@ -240,7 +240,7 @@ const rebuildSelectedRegion = (payload) => { const handleRegion = (r) => { isRegionActive(r) ? activeTreeBranch.push(r) : {} isSomeRegionActive(r) ? someActiveTreeBranch.push(r) : {} - if (r.children && r.children.length > 0) + if (r.children && r.children.length > 0) r.children.forEach(handleRegion) } regions.forEach(handleRegion) @@ -292,6 +292,146 @@ const processParcRegionAttr = (payload) => { }) } +const parseLineDataToVtk = (data, scale= 1, plotyMultiple) => { + const lineCoordinates = [] + + for (let i = 1; i < data.x.length; i++) { + + // ToDo use neuron colors + // if (i+1 === data.x.length) { + // colors.push(data.marker.color[lineDataIndex-1]) + // break; + // } + + if (data.x[i] !== null && data.x[i-1] !== null) { + lineCoordinates.push([[ + data.x[i-1] * plotyMultiple, + data.y[i-1] * plotyMultiple, + data.z[i-1] * plotyMultiple, + ], [ + data.x[i] * plotyMultiple, + data.y[i] * plotyMultiple, + data.z[i] * plotyMultiple, + ]]) + } + } + + const coordinateLength = lineCoordinates.length + + const lineCoordinatesArrayToString = (() => { + let returnString = '' + lineCoordinates.forEach(lc => { + returnString += getPerpendicularPointsForLine(lc[0], lc[1], scale) + }) + return returnString + })() + + const vtk = `${vtkHeader}\n` + + `POINTS ${coordinateLength*8} float\n` + + lineCoordinatesArrayToString + + `POLYGONS ${coordinateLength*12} ${coordinateLength*48}\n` + + getLineDataVtkPolygonStringWithNumber(coordinateLength) + + `POINT_DATA ${coordinateLength*8}\n` + + 'SCALARS label unsigned_char 1\n' + + 'LOOKUP_TABLE none\n' + + getColorIds(coordinateLength*8) + + return vtk +} + +const getColorIds = (n) => { + let returnString = '' + for (let i=0; i<n-1; i++){ + returnString += '0\n' + } + returnString += '0' + return returnString +} + +const getLineDataVtkPolygonStringWithNumber = (neuronCoordinateLength) => { + let returnString = '' + for (let i = 0; i < neuronCoordinateLength; i++) { + const neuronNumber = 8*i + returnString += + `3 ${0 + neuronNumber} ${1 + neuronNumber} ${3 + neuronNumber}\n` + + `3 ${0 + neuronNumber} ${2 + neuronNumber} ${3 + neuronNumber}\n` + + `3 ${4 + neuronNumber} ${5 + neuronNumber} ${7 + neuronNumber}\n` + + `3 ${4 + neuronNumber} ${6 + neuronNumber} ${7 + neuronNumber}\n` + + `3 ${2 + neuronNumber} ${6 + neuronNumber} ${7 + neuronNumber}\n` + + `3 ${2 + neuronNumber} ${3 + neuronNumber} ${7 + neuronNumber}\n` + + `3 ${3 + neuronNumber} ${1 + neuronNumber} ${7 + neuronNumber}\n` + + `3 ${1 + neuronNumber} ${5 + neuronNumber} ${7 + neuronNumber}\n` + + `3 ${2 + neuronNumber} ${0 + neuronNumber} ${6 + neuronNumber}\n` + + `3 ${0 + neuronNumber} ${4 + neuronNumber} ${6 + neuronNumber}\n` + + `3 ${1 + neuronNumber} ${0 + neuronNumber} ${4 + neuronNumber}\n` + + `3 ${1 + neuronNumber} ${4 + neuronNumber} ${5 + neuronNumber}\n` + } + return returnString +} + +const getPerpendicularPointsForLine = (A, B, scale) => { + + const lineWeight = 1e6 + const lineWidth = scale * lineWeight + const lineHeight = scale * lineWeight + + let u = A.map((item, index) => { + return item - B[index]; + }) + const uLength = Math.sqrt((u[0] * u[0]) + (u[1] * u[1]) + (u[2] * u[2])) + u = u.map((item, index) => { + return item/uLength + }) + + const n = [] + if(Math.abs(u[0]) <= Math.abs(u[1]) && Math.abs(u[0]) <= Math.abs(u[2])) { + n[0] = u[1] * u[1] + u[2] * u[2] + n[1] = -u[1] * u[0] + n[2] = -u[2] * u[0] + } + else if(Math.abs(u[1])<=Math.abs(u[0])&&Math.abs(u[1])<=Math.abs(u[2])) + { + n[0] = -u[0] * u[2] + n[1] = u[0] * u[0] + u[2] * u[2] + n[2] = -u[2] * u[1] + } + else if(Math.abs(u[2])<=Math.abs(u[0])&&Math.abs(u[2])<=Math.abs(u[1])) + { + n[0] = -u[0] * u[2] + n[1] = -u[1] * u[2] + n[2] = u[0] * u[0] + u[1] * u[1] + } + + const v = [ u[1] * n[2] - u[2] * n[1], u[2] * n[0] - u[0] * n[2], u[0] * n[1] - u[1] * n[0] ] + + const RMul = (k) => { + const res = [] + res[0] = v[0]*k[0] + n[0]*k[1] + u[0]*k[2] + res[1] = v[1]*k[0] + n[1]*k[1] + u[1]*k[2] + res[2] = v[2]*k[0] + n[2]*k[1] + u[2]*k[2] + return res + } + + const sumArrays = (a1, a2) => { + return a1.map((item, index) => { + return item + a2[index]; + }) + } + + const a = sumArrays(A, RMul([lineWidth,lineHeight,0])) + const b = sumArrays(A, RMul([-lineWidth,lineHeight,0])) + const c = sumArrays(A, RMul([lineWidth,-lineHeight,0])) + const d = sumArrays(A, RMul([-lineWidth,-lineHeight,0])) + + const e = sumArrays(B, RMul([lineWidth,lineHeight,0])) + const f = sumArrays(B, RMul([-lineWidth,lineHeight,0])) + const g = sumArrays(B, RMul([lineWidth,-lineHeight,0])) + const h = sumArrays(B, RMul([-lineWidth,-lineHeight,0])) + + return `${a.join(' ')}\n ${b.join(' ')}\n ${c.join(' ')}\n ${d.join(' ')}\n ${e.join(' ')}\n ${f.join(' ')}\n ${g.join(' ')}\n ${h.join(' ')}\n ` +} + + let plotyVtkUrl onmessage = (message) => { @@ -312,7 +452,8 @@ onmessage = (message) => { } } if (plotyVtkUrl) URL.revokeObjectURL(plotyVtkUrl) - const vtkString = parseLmToVtk(lm, 3e-2) + const vtkString = parseLineDataToVtk(plotlyData.traces[0], 5e-3, plotyMultiple) + plotyVtkUrl = URL.createObjectURL( new Blob([ encoder.encode(vtkString) ], { type: 'application/octet-stream' }) ) @@ -341,7 +482,7 @@ onmessage = (message) => { }) return } - + if(validTypes.findIndex(type => type === message.data.type) >= 0){ switch(message.data.type){ case 'GET_LANDMARKS_VTK':