Exemplo n.º 1
0
/**
 * This method scales a model based on user-specified XYZ body scale factors
 * and/or a set of marker-to-marker distance measurements.
 *
 * @param aModel the model to scale.
 * @param aSubjectMass the final mass of the model after scaling.
 * @return Whether the scaling process was successful or not.
 */
bool ModelScaler::processModel(Model* aModel, const string& aPathToSubject, double aSubjectMass)
{
    if (!getApply()) return false;

    int i;
    ScaleSet theScaleSet;
    Vec3 unity(1.0);

    cout << endl << "Step 2: Scaling generic model" << endl;

    ComponentList<PhysicalFrame> segments
        = aModel->getComponentList<PhysicalFrame>();
    ComponentList<PhysicalFrame>::const_iterator it = segments.begin();

    /* Make a scale set with a Scale for each physical frame.
     * Initialize all factors to 1.0.
     */
    for (; it != segments.end(); ++it) {
        Scale* segmentScale = new Scale();
        segmentScale->setSegmentName(it->getName());
        segmentScale->setScaleFactors(unity);
        segmentScale->setApply(true);
        theScaleSet.adoptAndAppend(segmentScale);
    }

    SimTK::State& s = aModel->initSystem();
    aModel->getMultibodySystem().realize(s, SimTK::Stage::Position);

    try
    {
        /* Make adjustments to theScaleSet, in the user-specified order. */
        for (i = 0; i < _scalingOrder.getSize(); i++)
        {
            /* For measurements, measure the distance between a pair of markers
             * in the model, and in the static pose. The latter divided by the
             * former is the scale factor. Put that scale factor in theScaleSet,
             * using the body/axis names specified in the measurement to
             * determine in what place[s] to put the factor.
             */
            if (_scalingOrder[i] == "measurements")
            {
                /* Load the static pose marker file, and convert units.
                */
                MarkerData *markerData = 0;
                if(!_markerFileName.empty() && _markerFileName!=PropertyStr::getDefaultStr()) {
                    markerData = new MarkerData(aPathToSubject + _markerFileName);
                    markerData->convertToUnits(aModel->getLengthUnits());
                }

                /* Now take and apply the measurements. */
                for (int j = 0; j < _measurementSet.getSize(); j++)
                {
                    if (_measurementSet.get(j).getApply())
                    {
                        if(!markerData)
                            throw Exception("ModelScaler.processModel: ERROR- "+_markerFileNameProp.getName()+
                                                " not set but measurements are used",__FILE__,__LINE__);
                        double scaleFactor = computeMeasurementScaleFactor(s,*aModel, *markerData, _measurementSet.get(j));
                        if (!SimTK::isNaN(scaleFactor))
                            _measurementSet.get(j).applyScaleFactor(scaleFactor, theScaleSet);
                        else
                            cout << "___WARNING___: " << _measurementSet.get(j).getName() << " measurement not used to scale " << aModel->getName() << endl;
                    }
                }
            }
            /* For manual scales, just copy the XYZ scale factors from
             * the manual scale into theScaleSet.
             */
            else if (_scalingOrder[i] == "manualScale")
            {
                for (int j = 0; j < _scaleSet.getSize(); j++)
                {
                    if (_scaleSet[j].getApply())
                    {
                        const string& bodyName = _scaleSet[j].getSegmentName();
                        Vec3 factors(1.0);
                        _scaleSet[j].getScaleFactors(factors);
                        for (int k = 0; k < theScaleSet.getSize(); k++)
                        {
                            if (theScaleSet[k].getSegmentName() == bodyName)
                                theScaleSet[k].setScaleFactors(factors);
                        }
                    }
                }
            }
            else
            {
                throw Exception("ModelScaler: ERR- Unrecognized string '"+_scalingOrder[i]+"' in "+_scalingOrderProp.getName()+" property (expecting 'measurements' or 'manualScale').",__FILE__,__LINE__);
            }
        }

        /* Now scale the model. */
        aModel->scale(s, theScaleSet, aSubjectMass, _preserveMassDist);


        if(_printResultFiles) {
            std::string savedCwd = IO::getCwd();
            IO::chDir(aPathToSubject);

            if (!_outputModelFileNameProp.getValueIsDefault())
            {
                if (aModel->print(_outputModelFileName))
                    cout << "Wrote model file " << _outputModelFileName << " from model " << aModel->getName() << endl;
            }

            if (!_outputScaleFileNameProp.getValueIsDefault())
            {
                if (theScaleSet.print(_outputScaleFileName))
                    cout << "Wrote scale file " << _outputScaleFileName << " for model " << aModel->getName() << endl;
            }
            IO::chDir(savedCwd);
        }
    }
    catch (const Exception& x)
    {
        x.print(cout);
        return false;
    }

    return true;
}