subdivide = function (positions,faces, catmull = true) {
let ds = HalfedgeDS.fromFaces(faces);
let sum = pts => pts.reduce((p,q) => [p[0]+q[0],p[1]+q[1],p[2]+q[2]]);
let avg = pts => {
return sum(pts).map (x => x / pts.length);
}
let scale = (v,s) => v.map(x => x * s);
let facePoints = ds.face.map(
(he,iface) => avg ([...ds.faceCirculator(iface)].map(he => positions[he.v]))
);
let edgeToMidpoint = (he,twin) => avg([positions[he.v],positions[twin.v]]);
let edgeToSubdivisionPoint =
(he,twin) => avg([positions[he.v],positions[twin.v],facePoints[he.f],facePoints[twin.f]]);
let edgePoints = [];
let edgeMidPoints = []
ds.halfedge.forEach (
he => {
let twin = ds.halfedge[he.twin]
if (he.v < twin.v) { // Process each edge only once
he.iEdgePoint = twin.iEdgePoint = edgePoints.length;
let midpoint = edgeToMidpoint(he,twin)
edgeMidPoints.push (midpoint)
if (catmull) edgePoints.push (edgeToSubdivisionPoint(he,twin));
else edgePoints.push(midpoint)
}
});
// Compute the new position of vertex v in a Catmull-Clark subdivision
let newPosition = ivertex => {
let incidentHalfedges = [...ds.vertexCirculator(ivertex)];
let incidentFacePoints = incidentHalfedges.map(he=>facePoints[he.f]);
let incidentEdgePoints = incidentHalfedges.map(he=>edgeMidPoints[he.iEdgePoint]);
if (ivertex==0) console.log (incidentHalfedges, incidentFacePoints, incidentEdgePoints)
let n = incidentHalfedges.length;
return sum ([scale(positions[ivertex], (n-3)/n),
scale(avg(incidentFacePoints), 1/n),
scale(avg(incidentEdgePoints), 2/n)])
}
// Array with the new positions of the original vertices
let newPositions = (catmull ? positions.map((d,i) => newPosition(i)) : positions);
// Compute the new face circulations
let n = positions.length;
let m = edgePoints.length;
newPositions = newPositions.concat(edgePoints).concat(facePoints);
let newFaces = [];
ds.face.forEach((he,i) => {
let edgeIndices = []
for (let he of ds.faceCirculator(i)) edgeIndices.push(he.iEdgePoint+n, he.v,);
let ne = edgeIndices.length;
for (let k = 0; k < edgeIndices.length; k+= 2) {
newFaces.push([i+n+m,edgeIndices[k],edgeIndices[(k+1)%ne],edgeIndices[(k+2)%ne]]);
}
})
return {positions:newPositions, cells:newFaces}
}