Skip to content

Commit f663ddb

Browse files
mmAnimCurveDiffStatistics - add flags for python value lists
1 parent 19a0bae commit f663ddb

3 files changed

Lines changed: 322 additions & 85 deletions

File tree

src/mmSolver/cmd/MMAnimCurveDiffStatisticsCmd.cpp

Lines changed: 219 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747

4848
// MM Solver
4949
#include "mmSolver/cmd/anim_curve_cmd_utils.h"
50+
#include "mmSolver/core/types.h"
5051
#include "mmSolver/utilities/assert_utils.h"
5152
#include "mmSolver/utilities/debug_utils.h"
5253

@@ -84,6 +85,15 @@
8485
#define SIGNAL_TO_NOISE_RATIO_FLAG_SHORT "-snr"
8586
#define SIGNAL_TO_NOISE_RATIO_FLAG_LONG "-signalToNoiseRatio"
8687

88+
#define X_VALUES_FLAG_SHORT "-xv"
89+
#define X_VALUES_FLAG_LONG "-xValues"
90+
91+
#define Y_VALUES_A_FLAG_SHORT "-yva"
92+
#define Y_VALUES_A_FLAG_LONG "-yValuesA"
93+
94+
#define Y_VALUES_B_FLAG_SHORT "-yvb"
95+
#define Y_VALUES_B_FLAG_LONG "-yValuesB"
96+
8797
#define CMD_NAME "mmAnimCurveDiffStatistics"
8898

8999
// Statistic type identifiers for output
@@ -141,8 +151,18 @@ MSyntax MMAnimCurveDiffStatisticsCmd::newSyntax() {
141151
syntax.addFlag(SIGNAL_TO_NOISE_RATIO_FLAG_SHORT,
142152
SIGNAL_TO_NOISE_RATIO_FLAG_LONG, MSyntax::kBoolean);
143153

144-
// Require exactly 2 animation curves
145-
const unsigned int min_curves = 2;
154+
// List input flags
155+
syntax.addFlag(X_VALUES_FLAG_SHORT, X_VALUES_FLAG_LONG, MSyntax::kDouble);
156+
syntax.addFlag(Y_VALUES_A_FLAG_SHORT, Y_VALUES_A_FLAG_LONG,
157+
MSyntax::kDouble);
158+
syntax.addFlag(Y_VALUES_B_FLAG_SHORT, Y_VALUES_B_FLAG_LONG,
159+
MSyntax::kDouble);
160+
syntax.makeFlagMultiUse(X_VALUES_FLAG_SHORT);
161+
syntax.makeFlagMultiUse(Y_VALUES_A_FLAG_SHORT);
162+
syntax.makeFlagMultiUse(Y_VALUES_B_FLAG_SHORT);
163+
164+
// Require 0 to 2 animation curves (0 when using list inputs)
165+
const unsigned int min_curves = 0;
146166
const unsigned int max_curves = 2;
147167
syntax.setObjectType(MSyntax::kSelectionList, min_curves, max_curves);
148168
syntax.useSelectionAsDefault(true);
@@ -158,21 +178,104 @@ MStatus MMAnimCurveDiffStatisticsCmd::parseArgs(const MArgList &args) {
158178
MArgDatabase argData(syntax(), args, &status);
159179
MMSOLVER_CHECK_MSTATUS_AND_RETURN_IT(status);
160180

161-
// Get animation curves from selection.
162-
status = argData.getObjects(m_selection);
163-
MMSOLVER_CHECK_MSTATUS_AND_RETURN_IT(status);
181+
// Check if list inputs are provided
182+
bool hasSomeListInputs = argData.isFlagSet(X_VALUES_FLAG_SHORT) ||
183+
argData.isFlagSet(Y_VALUES_A_FLAG_SHORT) ||
184+
argData.isFlagSet(Y_VALUES_B_FLAG_SHORT);
185+
bool hasAllListInputs = argData.isFlagSet(X_VALUES_FLAG_SHORT) &&
186+
argData.isFlagSet(Y_VALUES_A_FLAG_SHORT) &&
187+
argData.isFlagSet(Y_VALUES_B_FLAG_SHORT);
164188

165-
if (m_selection.length() != 2) {
166-
MGlobal::displayError(CMD_NAME
167-
": Please select exactly two animation curves.");
189+
// All four list flags must be provided, or none at all.
190+
if (hasAllListInputs && !hasAllListInputs) {
191+
MGlobal::displayError(
192+
CMD_NAME
193+
": All list value flags (xValues, yValuesA, yValuesB) must be "
194+
"provided together, or none at all.");
168195
return MS::kFailure;
169196
}
170197

171-
// Validate both curves.
172-
status = m_selection.getDependNode(0, m_animCurveObj1);
173-
MMSOLVER_CHECK_MSTATUS_AND_RETURN_IT(status);
174-
status = m_selection.getDependNode(1, m_animCurveObj2);
175-
MMSOLVER_CHECK_MSTATUS_AND_RETURN_IT(status);
198+
m_useListInput = false;
199+
if (hasAllListInputs) {
200+
m_useListInput = true;
201+
202+
Count32 xCount = argData.numberOfFlagUses(X_VALUES_FLAG_SHORT);
203+
Count32 yCount1 = argData.numberOfFlagUses(Y_VALUES_A_FLAG_SHORT);
204+
Count32 yCount2 = argData.numberOfFlagUses(Y_VALUES_A_FLAG_SHORT);
205+
206+
// Validate list lengths
207+
if (xCount != yCount1) {
208+
MGlobal::displayError(
209+
CMD_NAME
210+
": X and Y value lists for curve 1 must have the same length.");
211+
return MS::kFailure;
212+
}
213+
214+
if (xCount != yCount2) {
215+
MGlobal::displayError(
216+
CMD_NAME
217+
": X and Y value lists for curve 2 must have the same length.");
218+
return MS::kFailure;
219+
}
220+
221+
if (xCount < 2) {
222+
MGlobal::displayError(
223+
CMD_NAME ": Value lists must contain at least 2 values.");
224+
return MS::kFailure;
225+
}
226+
227+
m_xValues.clear();
228+
m_yValuesA.clear();
229+
m_yValuesB.clear();
230+
231+
for (Count32 i = 0; i < xCount; ++i) {
232+
MArgList xArgList;
233+
status =
234+
argData.getFlagArgumentList(X_VALUES_FLAG_SHORT, i, xArgList);
235+
MMSOLVER_CHECK_MSTATUS_AND_RETURN_IT(status);
236+
const double value = xArgList.asDouble(0, &status);
237+
MMSOLVER_CHECK_MSTATUS_AND_RETURN_IT(status);
238+
m_xValues.push_back(value);
239+
}
240+
241+
for (Count32 i = 0; i < xCount; ++i) {
242+
MArgList yArgList1;
243+
status = argData.getFlagArgumentList(Y_VALUES_A_FLAG_SHORT, i,
244+
yArgList1);
245+
MMSOLVER_CHECK_MSTATUS_AND_RETURN_IT(status);
246+
const double value = yArgList1.asDouble(0, &status);
247+
MMSOLVER_CHECK_MSTATUS_AND_RETURN_IT(status);
248+
m_yValuesA.push_back(value);
249+
}
250+
251+
for (Count32 i = 0; i < xCount; ++i) {
252+
MArgList yArgList2;
253+
status = argData.getFlagArgumentList(Y_VALUES_B_FLAG_SHORT, i,
254+
yArgList2);
255+
MMSOLVER_CHECK_MSTATUS_AND_RETURN_IT(status);
256+
const double value = yArgList2.asDouble(0, &status);
257+
MMSOLVER_CHECK_MSTATUS_AND_RETURN_IT(status);
258+
m_yValuesB.push_back(value);
259+
}
260+
261+
} else {
262+
// Get animation curves from selection.
263+
status = argData.getObjects(m_selection);
264+
MMSOLVER_CHECK_MSTATUS_AND_RETURN_IT(status);
265+
266+
if (m_selection.length() != 2) {
267+
MGlobal::displayError(CMD_NAME
268+
": Please select exactly two animation "
269+
"curves or provide list values.");
270+
return MS::kFailure;
271+
}
272+
273+
// Validate both curves.
274+
status = m_selection.getDependNode(0, m_animCurveObj1);
275+
MMSOLVER_CHECK_MSTATUS_AND_RETURN_IT(status);
276+
status = m_selection.getDependNode(1, m_animCurveObj2);
277+
MMSOLVER_CHECK_MSTATUS_AND_RETURN_IT(status);
278+
}
176279

177280
// Parse optional frame range arguments.
178281
m_startFrame = std::numeric_limits<FrameNumber>::max();
@@ -264,6 +367,7 @@ MStatus MMAnimCurveDiffStatisticsCmd::parseArgs(const MArgList &args) {
264367
MMSOLVER_MAYA_VRB(CMD_NAME << ": m_calculatePeakToPeak="
265368
<< m_calculatePeakToPeak);
266369
MMSOLVER_MAYA_VRB(CMD_NAME << ": m_calculateSNR=" << m_calculateSNR);
370+
MMSOLVER_MAYA_VRB(CMD_NAME << ": m_useListInput=" << m_useListInput);
267371

268372
return status;
269373
}
@@ -274,85 +378,116 @@ MStatus MMAnimCurveDiffStatisticsCmd::doIt(const MArgList &args) {
274378
MStatus status = parseArgs(args);
275379
MMSOLVER_CHECK_MSTATUS_AND_RETURN_IT(status);
276380

277-
// Set up the animation curve function objects.
278-
status = m_animCurveFn1.setObject(m_animCurveObj1);
279-
if (status != MS::kSuccess) {
280-
MGlobal::displayError(
281-
CMD_NAME ": First selected object is not an animation curve.");
282-
return status;
283-
}
381+
// Evaluate both curves.
382+
rust::Vec<mmsg::Real> values_x1;
383+
rust::Vec<mmsg::Real> values_y1;
384+
rust::Vec<mmsg::Real> values_x2;
385+
rust::Vec<mmsg::Real> values_y2;
386+
387+
if (m_useListInput) {
388+
// Use provided list values with interpolation for matching X
389+
// values.
390+
values_x1.reserve(m_xValues.size());
391+
values_y1.reserve(m_xValues.size());
392+
values_x2.reserve(m_xValues.size());
393+
values_y2.reserve(m_xValues.size());
394+
395+
for (auto i = 0; i < m_xValues.size(); i++) {
396+
values_x1.push_back(m_xValues[i]);
397+
}
284398

285-
status = m_animCurveFn2.setObject(m_animCurveObj2);
286-
if (status != MS::kSuccess) {
287-
MGlobal::displayError(
288-
CMD_NAME ": Second selected object is not an animation curve.");
289-
return status;
290-
}
399+
for (auto i = 0; i < m_yValuesA.size(); i++) {
400+
values_y1.push_back(m_yValuesA[i]);
401+
}
291402

292-
// Validate both curves and determine frame ranges.
293-
FrameNumber start_frame1 = 0;
294-
FrameNumber end_frame1 = 0;
295-
FrameNumber start_frame2 = 0;
296-
FrameNumber end_frame2 = 0;
297-
const FrameCount min_keyframe_count = 2;
298-
const FrameCount min_frame_count = 2;
299-
const char *cmd_name = CMD_NAME;
300-
301-
bool success1 = validate_anim_curve(
302-
cmd_name, m_startFrame, m_endFrame, min_keyframe_count, min_frame_count,
303-
m_animCurveFn1, start_frame1, end_frame1);
304-
if (!success1) {
305-
MGlobal::displayError(CMD_NAME
306-
": Failed to validate first animation curve.");
307-
return MS::kFailure;
308-
}
403+
for (auto i = 0; i < m_xValues.size(); i++) {
404+
values_x2.push_back(m_xValues[i]);
405+
}
309406

310-
bool success2 = validate_anim_curve(
311-
cmd_name, m_startFrame, m_endFrame, min_keyframe_count, min_frame_count,
312-
m_animCurveFn2, start_frame2, end_frame2);
313-
if (!success2) {
314-
MGlobal::displayError(CMD_NAME
315-
": Failed to validate second animation curve.");
316-
return MS::kFailure;
317-
}
407+
for (auto i = 0; i < m_yValuesB.size(); i++) {
408+
values_y2.push_back(m_yValuesB[i]);
409+
}
318410

319-
// Use the intersection of both frame ranges.
320-
FrameNumber start_frame = std::max(start_frame1, start_frame2);
321-
FrameNumber end_frame = std::min(end_frame1, end_frame2);
322-
if (start_frame > end_frame) {
323-
MGlobal::displayError(
324-
CMD_NAME ": Animation curves have no overlapping frame range.");
325-
return MS::kFailure;
326-
}
411+
} else {
412+
// Use animation curves
327413

328-
MMSOLVER_MAYA_VRB(CMD_NAME << ": start_frame=" << start_frame);
329-
MMSOLVER_MAYA_VRB(CMD_NAME << ": end_frame=" << end_frame);
414+
// Set up the animation curve function objects.
415+
status = m_animCurveFn1.setObject(m_animCurveObj1);
416+
if (status != MS::kSuccess) {
417+
MGlobal::displayError(
418+
CMD_NAME ": First selected object is not an animation curve.");
419+
return status;
420+
}
330421

331-
auto time_unit = MTime::uiUnit();
332-
auto frame_count = static_cast<size_t>(end_frame - start_frame) + 1;
422+
status = m_animCurveFn2.setObject(m_animCurveObj2);
423+
if (status != MS::kSuccess) {
424+
MGlobal::displayError(
425+
CMD_NAME ": Second selected object is not an animation curve.");
426+
return status;
427+
}
333428

334-
// Evaluate both curves.
335-
rust::Vec<mmsg::Real> values_x1, values_y1;
336-
rust::Vec<mmsg::Real> values_x2, values_y2;
337-
values_x1.reserve(frame_count);
338-
values_y1.reserve(frame_count);
339-
values_x2.reserve(frame_count);
340-
values_y2.reserve(frame_count);
341-
342-
status = evaluate_curve(start_frame, end_frame, time_unit, m_animCurveFn1,
343-
values_x1, values_y1);
344-
if (status != MS::kSuccess) {
345-
MGlobal::displayError(CMD_NAME
346-
": Failed to evaluate first animation curve.");
347-
return status;
348-
}
429+
// Validate both curves and determine frame ranges.
430+
FrameNumber start_frame1 = 0;
431+
FrameNumber end_frame1 = 0;
432+
FrameNumber start_frame2 = 0;
433+
FrameNumber end_frame2 = 0;
434+
const FrameCount min_keyframe_count = 2;
435+
const FrameCount min_frame_count = 2;
436+
const char *cmd_name = CMD_NAME;
437+
438+
bool success1 = validate_anim_curve(
439+
cmd_name, m_startFrame, m_endFrame, min_keyframe_count,
440+
min_frame_count, m_animCurveFn1, start_frame1, end_frame1);
441+
if (!success1) {
442+
MGlobal::displayError(
443+
CMD_NAME ": Failed to validate first animation curve.");
444+
return MS::kFailure;
445+
}
349446

350-
status = evaluate_curve(start_frame, end_frame, time_unit, m_animCurveFn2,
351-
values_x2, values_y2);
352-
if (status != MS::kSuccess) {
353-
MGlobal::displayError(CMD_NAME
354-
": Failed to evaluate second animation curve.");
355-
return status;
447+
bool success2 = validate_anim_curve(
448+
cmd_name, m_startFrame, m_endFrame, min_keyframe_count,
449+
min_frame_count, m_animCurveFn2, start_frame2, end_frame2);
450+
if (!success2) {
451+
MGlobal::displayError(
452+
CMD_NAME ": Failed to validate second animation curve.");
453+
return MS::kFailure;
454+
}
455+
456+
// Use the intersection of both frame ranges.
457+
FrameNumber start_frame = std::max(start_frame1, start_frame2);
458+
FrameNumber end_frame = std::min(end_frame1, end_frame2);
459+
if (start_frame > end_frame) {
460+
MGlobal::displayError(
461+
CMD_NAME ": Animation curves have no overlapping frame range.");
462+
return MS::kFailure;
463+
}
464+
465+
MMSOLVER_MAYA_VRB(CMD_NAME << ": start_frame=" << start_frame);
466+
MMSOLVER_MAYA_VRB(CMD_NAME << ": end_frame=" << end_frame);
467+
468+
auto time_unit = MTime::uiUnit();
469+
auto frame_count = static_cast<size_t>(end_frame - start_frame) + 1;
470+
471+
values_x1.reserve(frame_count);
472+
values_y1.reserve(frame_count);
473+
values_x2.reserve(frame_count);
474+
values_y2.reserve(frame_count);
475+
476+
status = evaluate_curve(start_frame, end_frame, time_unit,
477+
m_animCurveFn1, values_x1, values_y1);
478+
if (status != MS::kSuccess) {
479+
MGlobal::displayError(
480+
CMD_NAME ": Failed to evaluate first animation curve.");
481+
return status;
482+
}
483+
484+
status = evaluate_curve(start_frame, end_frame, time_unit,
485+
m_animCurveFn2, values_x2, values_y2);
486+
if (status != MS::kSuccess) {
487+
MGlobal::displayError(
488+
CMD_NAME ": Failed to evaluate second animation curve.");
489+
return status;
490+
}
356491
}
357492

358493
// Verify we have the same number of values.

src/mmSolver/cmd/MMAnimCurveDiffStatisticsCmd.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,12 @@
2525

2626
// STL
2727
#include <limits>
28+
#include <vector>
2829

2930
// Maya
3031
#include <maya/MArgDatabase.h>
3132
#include <maya/MArgList.h>
33+
#include <maya/MDoubleArray.h>
3234
#include <maya/MFnAnimCurve.h>
3335
#include <maya/MObject.h>
3436
#include <maya/MPxCommand.h>
@@ -53,7 +55,8 @@ class MMAnimCurveDiffStatisticsCmd : public MPxCommand {
5355
, m_calculateVariance(false)
5456
, m_calculateStdDev(false)
5557
, m_calculatePeakToPeak(false)
56-
, m_calculateSNR(false){};
58+
, m_calculateSNR(false)
59+
, m_useListInput(false){};
5760
virtual ~MMAnimCurveDiffStatisticsCmd();
5861

5962
virtual bool hasSyntax() const;
@@ -88,6 +91,12 @@ class MMAnimCurveDiffStatisticsCmd : public MPxCommand {
8891
MObject m_animCurveObj2;
8992
MFnAnimCurve m_animCurveFn1;
9093
MFnAnimCurve m_animCurveFn2;
94+
95+
// List input mode
96+
bool m_useListInput;
97+
std::vector<double> m_xValues;
98+
std::vector<double> m_yValuesA;
99+
std::vector<double> m_yValuesB;
91100
};
92101

93102
} // namespace mmsolver

0 commit comments

Comments
 (0)