/*---------------------------------------------------------------------------*/
FEATURE_SET ExtractCharNormFeatures(TBLOB *Blob, LINE_STATS *LineStats) { 
/*
 **	Parameters:
 **		Blob		blob to extract char norm feature from
 **		LineStats	statistics on text row blob is in
 **	Globals: none
 **	Operation: Compute a feature whose parameters describe how a
 **		character will be affected by the character normalization
 **		algorithm.  The feature parameters are:
 **			y position of center of mass in baseline coordinates
 **			total length of outlines in baseline coordinates
 **				divided by a scale factor
 **			radii of gyration about the center of mass in
 **				baseline coordinates
 **	Return: Character normalization feature for Blob.
 **	Exceptions: none
 **	History: Wed May 23 18:06:38 1990, DSJ, Created.
 */
  FEATURE_SET FeatureSet;
  FEATURE Feature;
  FLOAT32 Scale;
  FLOAT32 Baseline;
  LIST Outlines;
  INT_FEATURE_ARRAY blfeatures;
  INT_FEATURE_ARRAY cnfeatures;
  INT_FX_RESULT_STRUCT FXInfo;

  /* allocate the feature and feature set - note that there is always one
     and only one char normalization feature for any blob */
  FeatureSet = NewFeatureSet (1);
  Feature = NewFeature (&CharNormDesc);
  AddFeature(FeatureSet, Feature); 

  /* compute the normalization statistics for this blob */
  Outlines = ConvertBlob (Blob);
  /*---------Debug--------------------------------------------------*
  OFile = fopen ("f:/ims/debug/nfOutline.logCPP", "r");
  if (OFile == NULL)
  {
    OFile = Efopen ("f:/ims/debug/nfOutline.logCPP", "w");
    WriteOutlines(OFile, Outlines);
  }
  else
  {
    fclose (OFile);
    OFile = Efopen ("f:/ims/debug/nfOutline.logCPP", "a");
  }
  WriteOutlines(OFile, Outlines);
  fclose (OFile);
  *--------------------------------------------------------------------*/

  ExtractIntFeat(Blob, blfeatures, cnfeatures, &FXInfo);
  Baseline = BaselineAt (LineStats, FXInfo.Xmean);
  Scale = ComputeScaleFactor (LineStats);
  Feature->Params[CharNormY] = (FXInfo.Ymean - Baseline) * Scale;
  Feature->Params[CharNormLength] =
    FXInfo.Length * Scale / LENGTH_COMPRESSION;
  Feature->Params[CharNormRx] = FXInfo.Rx * Scale;
  Feature->Params[CharNormRy] = FXInfo.Ry * Scale;

  /*---------Debug--------------------------------------------------*
  File = fopen ("f:/ims/debug/nfFeatSet.logCPP", "r");
  if (File == NULL)
  {
    File = Efopen ("f:/ims/debug/nfFeatSet.logCPP", "w");
    WriteFeatureSet(File, FeatureSet);
  }
  else
  {
    fclose (File);
    File = Efopen ("f:/ims/debug/nfFeatSet.logCPP", "a");
  }
  WriteFeatureSet(File, FeatureSet);
  fclose (File);
  *--------------------------------------------------------------------*/
  FreeOutlines(Outlines); 
  return (FeatureSet);
}                                /* ExtractCharNormFeatures */
void CRSRCellDeform::RSRCellDeform(double dLamda,int iType,int iIterNum,KW_Mesh& Mesh,
                                   vector<HandlePointStruct>& vecHandlePoint,vector<Vertex_handle>& vecHandleNb,
                                   vector<Vertex_handle>& ROIVertices,vector<Vertex_handle>& vecAnchorVertices,
                                   vector<Point_3>& vecDeformCurvePoint3d)
{
    SparseMatrix LaplacianMatrix(vecHandleNb.size()+ROIVertices.size());
    CDeformationAlgorithm::ComputeLaplacianMatrix(iType,Mesh,vecHandleNb,ROIVertices,vecAnchorVertices,LaplacianMatrix);


    SparseMatrix AnchorConstraintMatrix(vecAnchorVertices.size()),HandleConstraintMatrix(vecHandlePoint.size());
    CDeformationAlgorithm::GetConstraintsMatrixToNaiveLaplacian(vecHandlePoint,vecHandleNb,ROIVertices,vecAnchorVertices,
            AnchorConstraintMatrix,HandleConstraintMatrix);
    SparseMatrix LeftHandMatrixA=LaplacianMatrix;
    LeftHandMatrixA.insert(LeftHandMatrixA.end(),AnchorConstraintMatrix.begin(),AnchorConstraintMatrix.end());
    LeftHandMatrixA.insert(LeftHandMatrixA.end(),HandleConstraintMatrix.begin(),HandleConstraintMatrix.end());

    CMath TAUCSSolver;
    SparseMatrix AT(LeftHandMatrixA.NCols());
    TAUCSSolver.TAUCSFactorize(LeftHandMatrixA,AT);

    //the anchor constraints must keep fixed during iterations,so store them first
    vector<Point_3> AnchorPosConstraints;
    for (unsigned int i=0; i<vecAnchorVertices.size(); i++)
    {
        AnchorPosConstraints.push_back(vecAnchorVertices.at(i)->point());
    }

    for (int iCurrent=0; iCurrent<=iIterNum; iCurrent++)
    {
        vector<vector<double> > LaplacianRightHandSide,AnchorRightHandSide,HandleRightHandSide;
        if (iCurrent==0)
        {
            CDeformationAlgorithm::BackUpEdgeVectorsForRigidDeform(Mesh,vecHandleNb,ROIVertices,vecAnchorVertices);
            CDeformationAlgorithm::ComputeNaiveLaplacianRightHandSide(iType,vecHandleNb,ROIVertices,vecAnchorVertices,
                    vecDeformCurvePoint3d,LaplacianRightHandSide,AnchorRightHandSide,HandleRightHandSide);
        }
        else
        {
            ComputeRSRRightHandSide(dLamda,iType,vecHandleNb,ROIVertices,AnchorPosConstraints,//vecAnchorVertices,
                                    vecDeformCurvePoint3d,LaplacianRightHandSide,AnchorRightHandSide,HandleRightHandSide);
        }

        vector<vector<double> > RightHandSide=LaplacianRightHandSide;
        for (int i=0; i<3; i++)
        {
            RightHandSide.at(i).insert(RightHandSide.at(i).end(),AnchorRightHandSide.at(i).begin(),
                                       AnchorRightHandSide.at(i).end());
            RightHandSide.at(i).insert(RightHandSide.at(i).end(),HandleRightHandSide.at(i).begin(),
                                       HandleRightHandSide.at(i).end());
        }
        vector<vector<double> > Result;
        //		bool bResult=CMath::ComputeLSE(LeftHandMatrixA,RightHandSide,Result);

        bool bResult=TAUCSSolver.TAUCSComputeLSE(AT,RightHandSide,Result);

        if (bResult)
        {
            //vecDeformCurvePoint3d.clear();
            //calculated result of handle
            for (unsigned int i=0; i<vecHandleNb.size(); i++)
            {
                vecHandleNb.at(i)->point()=Point_3(Result.at(0).at(i),Result.at(1).at(i),Result.at(2).at(i));
            }
            //calculated result of ROI
            for (unsigned int i=0; i<ROIVertices.size(); i++)
            {
                ROIVertices.at(i)->point()=Point_3(Result.at(0).at(vecHandleNb.size()+i),
                                                   Result.at(1).at(vecHandleNb.size()+i),
                                                   Result.at(2).at(vecHandleNb.size()+i));
            }
            //calculated result of anchor
            for (unsigned int i=0; i<vecAnchorVertices.size(); i++)
            {
                vecAnchorVertices.at(i)->point()=Point_3(Result.at(0).at(vecHandleNb.size()+ROIVertices.size()+i),
                                                 Result.at(1).at(vecHandleNb.size()+ROIVertices.size()+i),
                                                 Result.at(2).at(vecHandleNb.size()+ROIVertices.size()+i));
            }
        }

        //compute Rotation for Handle+ROI+Anchor
        if (iCurrent!=iIterNum)
        {
            CDeformationAlgorithm::ComputeRotationForRigidDeform(iType,Mesh,vecHandleNb,ROIVertices,vecAnchorVertices);
            ComputeScaleFactor(iType,Mesh,vecHandleNb,ROIVertices,vecAnchorVertices);
            CDeformationAlgorithm::ComputeSecondRotationForRigidDeform(iType,Mesh,vecHandleNb,ROIVertices,vecAnchorVertices);
            ComputeRSRMatrixForDeform(Mesh,vecHandleNb,ROIVertices,vecAnchorVertices);
        }
    }

    TAUCSSolver.TAUCSClear();
}