修复机械事件力曲线并对齐气动孔口端口显示

This commit is contained in:
huojiarong committed 2026-08-20 05:59:04 +00:00
1 parent e18399c022
commit 408b4ecb22
11 files changed
+697 -43

No files matched your search

+190
View File
@@ -0,0 +1,190 @@
export type StateTransitionDiagnostics = {
integration?: {
segments?: Array<{
stateTransitionTimes?: number[];
}>;
};
};
type EventSeriesVariable = {
scope: "component" | "port";
portName: string | null;
quantity: string;
category: string;
};
type EventSeriesComponent = {
data: {
ports: Array<{
name: string;
domain: string;
}>;
};
};
const ISOLATED_EVENT_FORCE_RATIO = 100;
export function resultStateTransitionSampleIndices(
time: number[],
diagnostics: StateTransitionDiagnostics,
) {
const indices = new Set<number>();
for (const segment of diagnostics.integration?.segments ?? []) {
for (const eventTime of segment.stateTransitionTimes ?? []) {
if (!Number.isFinite(eventTime)) {
continue;
}
let index = time.indexOf(eventTime);
if (index < 0) {
const tolerance = 1e-12 * Math.max(Math.abs(eventTime), 1);
index = time.findIndex(
(sampleTime) => Math.abs(sampleTime - eventTime) <= tolerance,
);
}
if (index >= 0) {
indices.add(index);
}
}
}
return indices;
}
export function continuousMechanicalForceChartValues(
variable: EventSeriesVariable,
component: EventSeriesComponent | undefined,
values: number[],
stateTransitionSampleIndices: ReadonlySet<number>,
) {
const componentHasMechanicalPort = Boolean(
component?.data.ports.some((port) => port.domain === "mechanical"),
);
const forceBelongsToMechanicalDomain =
variable.scope === "component"
? variable.category === "derived" && componentHasMechanicalPort
: variable.portName !== null &&
Boolean(
component?.data.ports.some(
(port) =>
port.name === variable.portName &&
port.domain === "mechanical",
),
);
if (variable.quantity !== "force" || !forceBelongsToMechanicalDomain) {
return { values, separatedEventSampleCount: 0 };
}
const isolatedEventIndices: number[] = [];
for (const index of stateTransitionSampleIndices) {
if (
index < 0 ||
index >= values.length ||
!isolatedEventForceSample(
values,
index,
stateTransitionSampleIndices,
)
) {
continue;
}
isolatedEventIndices.push(index);
}
if (isolatedEventIndices.length === 0) {
return { values, separatedEventSampleCount: 0 };
}
const displayValues = values.slice();
for (const index of isolatedEventIndices) {
displayValues[index] = Number.NaN;
}
return {
values: displayValues,
separatedEventSampleCount: isolatedEventIndices.length,
};
}
function isolatedEventForceSample(
values: number[],
index: number,
stateTransitionSampleIndices: ReadonlySet<number>,
) {
const value = Number(values[index]);
if (!Number.isFinite(value)) {
return false;
}
const previous = finiteNonEventNeighbor(
values,
index - 1,
-1,
stateTransitionSampleIndices,
);
const next = finiteNonEventNeighbor(
values,
index + 1,
1,
stateTransitionSampleIndices,
);
if (previous === null || next === null) {
return false;
}
const localScale = Math.max(
Math.abs(previous),
Math.abs(next),
Math.abs(next - previous),
1e-9,
);
const localEstimate = (previous + next) / 2;
return (
Math.abs(value) > ISOLATED_EVENT_FORCE_RATIO * localScale &&
Math.abs(value - localEstimate) >
ISOLATED_EVENT_FORCE_RATIO * localScale
);
}
function finiteNonEventNeighbor(
values: number[],
startIndex: number,
direction: -1 | 1,
stateTransitionSampleIndices: ReadonlySet<number>,
) {
for (
let index = startIndex;
index >= 0 && index < values.length;
index += direction
) {
if (stateTransitionSampleIndices.has(index)) {
continue;
}
const value = Number(values[index]);
if (Number.isFinite(value)) {
return value;
}
}
return null;
}
export function segmentedChartPath(
time: number[],
values: number[],
xPosition: (value: number) => number,
yPosition: (value: number) => number,
) {
const commands: string[] = [];
let continuesSegment = false;
for (let index = 0; index < time.length; index += 1) {
const x = Number(time[index]);
const y = Number(values[index]);
if (!Number.isFinite(x)) {
continuesSegment = false;
continue;
}
if (!Number.isFinite(y)) {
continue;
}
commands.push(
`${continuesSegment ? "L" : "M"} ${xPosition(x).toFixed(2)} ${yPosition(y).toFixed(2)}`,
);
continuesSegment = true;
}
return commands.join(" ");
}