mirror of
https://git.datalinker.icu/kijai/ComfyUI-KJNodes.git
synced 2026-05-24 10:35:41 +08:00
sync multiple splines in speed mode
This commit is contained in:
parent
ed8294d7fb
commit
aeab1a7de5
@ -1222,8 +1222,8 @@ this.lastMousePosition = { x: this.width/2, y: this.height/2 };
|
|||||||
// Sort positions along path
|
// Sort positions along path
|
||||||
pathPositions.sort((a, b) => a - b);
|
pathPositions.sort((a, b) => a - b);
|
||||||
|
|
||||||
// Create a smooth speed mapping function using cubic spline interpolation
|
// Create a smooth speed mapping function with synchronization
|
||||||
const createSmoothMapping = () => {
|
const createSynchronizedMapping = () => {
|
||||||
// Calculate segment lengths and densities
|
// Calculate segment lengths and densities
|
||||||
const segments = [];
|
const segments = [];
|
||||||
let totalLength = pathPositions[pathPositions.length - 1] - pathPositions[0];
|
let totalLength = pathPositions[pathPositions.length - 1] - pathPositions[0];
|
||||||
@ -1239,72 +1239,63 @@ this.lastMousePosition = { x: this.width/2, y: this.height/2 };
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create cubic spline interpolation of densities
|
// Create mapping function with forced synchronization at endpoints
|
||||||
const positions = segments.map(seg => seg.position / totalLength);
|
return t => {
|
||||||
const densities = segments.map(seg => seg.density);
|
// Force synchronization at t=0 and t=1
|
||||||
|
if (t === 0) return 0;
|
||||||
// Add control points at beginning and end with gradual transition
|
if (t === 1) return pathLength;
|
||||||
positions.unshift(0);
|
|
||||||
positions.push(1);
|
|
||||||
densities.unshift(densities[0]);
|
|
||||||
densities.push(densities[densities.length - 1]);
|
|
||||||
|
|
||||||
// Smooth the density curve by applying a moving average
|
|
||||||
const smoothedDensities = [];
|
|
||||||
const windowSize = 3;
|
|
||||||
|
|
||||||
for (let i = 0; i < densities.length; i++) {
|
|
||||||
let sum = 0;
|
|
||||||
let count = 0;
|
|
||||||
|
|
||||||
for (let j = Math.max(0, i - windowSize); j <= Math.min(densities.length - 1, i + windowSize); j++) {
|
// For intermediate points, use the speed control
|
||||||
// Apply a triangular window weight based on distance
|
// Scale t to fit between first and last control points
|
||||||
const weight = 1 - Math.abs(i - j) / (windowSize + 1);
|
const firstPos = pathPositions[0];
|
||||||
sum += densities[j] * weight;
|
const lastPos = pathPositions[pathPositions.length - 1];
|
||||||
count += weight;
|
|
||||||
|
// Create a density-weighted position mapping
|
||||||
|
let totalWeight = 0;
|
||||||
|
let weights = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < segments.length; i++) {
|
||||||
|
totalWeight += segments[i].density;
|
||||||
|
weights.push(segments[i].density);
|
||||||
}
|
}
|
||||||
|
|
||||||
smoothedDensities.push(sum / count);
|
// Normalize weights
|
||||||
}
|
const normalizedWeights = weights.map(w => w / totalWeight);
|
||||||
|
|
||||||
// Calculate cumulative density function
|
|
||||||
let totalDensity = 0;
|
|
||||||
const cumulativeDensities = smoothedDensities.map(density => {
|
|
||||||
totalDensity += density;
|
|
||||||
return totalDensity;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Normalize to [0,1] range
|
|
||||||
const normalizedCumulative = cumulativeDensities.map(cd => cd / totalDensity);
|
|
||||||
|
|
||||||
// Create mapping function
|
|
||||||
return t => {
|
|
||||||
// Find the segment containing t using binary search
|
|
||||||
let low = 0;
|
|
||||||
let high = normalizedCumulative.length - 1;
|
|
||||||
|
|
||||||
while (low < high) {
|
// Calculate cumulative weights
|
||||||
const mid = Math.floor((low + high) / 2);
|
let cumulativeWeight = 0;
|
||||||
if (normalizedCumulative[mid] < t) {
|
const cumulativeWeights = normalizedWeights.map(w => {
|
||||||
low = mid + 1;
|
cumulativeWeight += w;
|
||||||
} else {
|
return cumulativeWeight;
|
||||||
high = mid;
|
});
|
||||||
|
|
||||||
|
// Find the segment for this t value
|
||||||
|
let segmentIndex = 0;
|
||||||
|
for (let i = 0; i < cumulativeWeights.length; i++) {
|
||||||
|
if (t <= cumulativeWeights[i]) {
|
||||||
|
segmentIndex = i;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Interpolate within the segment
|
// Calculate position within segment
|
||||||
const i = Math.max(0, low - 1);
|
const segmentStart = segmentIndex > 0 ? cumulativeWeights[segmentIndex - 1] : 0;
|
||||||
const segT = (t - (i > 0 ? normalizedCumulative[i] : 0)) /
|
const segmentEnd = cumulativeWeights[segmentIndex];
|
||||||
(normalizedCumulative[i+1] - (i > 0 ? normalizedCumulative[i] : 0));
|
const segmentT = (t - segmentStart) / (segmentEnd - segmentStart);
|
||||||
|
|
||||||
const pos = positions[i] + segT * (positions[i+1] - positions[i]);
|
// Map to path position
|
||||||
return pos * totalLength + pathPositions[0];
|
const pathStart = pathPositions[segmentIndex];
|
||||||
|
const pathEnd = pathPositions[segmentIndex + 1];
|
||||||
|
const pos = pathStart + segmentT * (pathEnd - pathStart);
|
||||||
|
|
||||||
|
// Scale to fill entire path
|
||||||
|
return pos;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const mapToPath = createSmoothMapping();
|
const mapToPath = createSynchronizedMapping();
|
||||||
|
|
||||||
// Sample using the smooth mapping function
|
// Sample using the synchronized mapping function
|
||||||
for (let i = 0; i < numSamples; i++) {
|
for (let i = 0; i < numSamples; i++) {
|
||||||
const t = i / (numSamples - 1);
|
const t = i / (numSamples - 1);
|
||||||
const pathPos = mapToPath(t);
|
const pathPos = mapToPath(t);
|
||||||
@ -1313,6 +1304,7 @@ this.lastMousePosition = { x: this.width/2, y: this.height/2 };
|
|||||||
}
|
}
|
||||||
|
|
||||||
return points;
|
return points;
|
||||||
|
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
for (var i = 0; i < numSamples; i++) {
|
for (var i = 0; i < numSamples; i++) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user