void HxCPDSpatialGraphWarp::preparePoints(McDArray<McVec3f>& p1,
                                          McDArray<McVec3f>& p2,
                                          SpatialGraphSelection& slice2,
                                          const HxSpatialGraph* spatialGraph) {
    ma::SliceSelector selectionHelper(spatialGraph, "TransformInfo");

    ma::EndPointParams params;
    params.endPointRegion = 30;
    params.projectionPlane = selectionHelper.computeMidPlane(0, 1);
    params.projectionType = ma::P_ORTHOGONAL;
    params.refSliceNum = 0;
    params.transSliceNum = 1;
    params.useAbsoluteValueForEndPointRegion = false;
    params.maxDistForAngle = 2000;
    params.angleToPlaneFilter = 0.01;
    SpatialGraphSelection slice1;
    ma::FacingPointSets pr =
        ma::projectEndPoints(spatialGraph, slice1, slice2, params);
    McDArray<McVec3f> refCoords = pr.ref.positions;
    McDArray<McVec3f> transCoords = pr.trans.positions;
    mcassert(refCoords.size() == slice1.getNumSelectedVertices());
    mcassert(transCoords.size() == slice2.getNumSelectedVertices());

    p1.resize(refCoords.size());
    for (int i = 0; i < refCoords.size(); i++) {
        McVec3f coord = refCoords[i];
        p1[i] = McVec3f(coord.x, coord.y, 0);
    }
    p2.resize(transCoords.size());
    for (int i = 0; i < transCoords.size(); i++) {
        McVec3f coord = transCoords[i];
        p2[i] = McVec3f(coord.x, coord.y, 0);
    }
    mcassert(p2.size() == slice2.getNumSelectedVertices());
}
void HxCPDSpatialGraphWarp::computeRigidVanMises() {
    const HxSpatialGraph* inputSG = (HxSpatialGraph*)portData.getSource();

    ma::SliceSelector selectionHelper(inputSG, "TransformInfo");

    HxSpatialGraph* resultSG = createOutputDataSet();
    resultSG->copyFrom(inputSG);
    McDArray<McVec3f> points1, points2;
    McDArray<McVec3f> dirs1, dirs2;
    SpatialGraphSelection slice2;
    preparePointsAndDirectionsRigid(points1, points2, dirs1, dirs2, slice2,
                                    resultSG);
    mcassert(slice2.getNumSelectedVertices() == points2.size());
    ma::CPDLinearAligner cpd;
    cpd.params.w = portW.getValue();
    cpd.params.withScaling = portWithScale.getValue();
    cpd.params.maxIterations = portEMParams.getValue(0);
    cpd.params.sigmaSquareStop = portEMParams.getValue(1);
    cpd.params.eDiffRelStop = portEMParams.getValue(2);
    cpd.params.useDirections = portUseDirection.getValue();
    cpd.params.usePositions = portUseCoords.getValue();

    if (!portUseDirection.getValue()) {
        dirs1.fill(McVec3f(0, 0, 1));
        dirs2.fill(McVec3f(0, 0, 1));
    }

    ma::FacingPointSets points;
    points.ref.positions = points1;
    points.ref.directions = dirs1;
    points.trans.positions = points2;
    points.trans.directions = dirs2;
    cpd.setPoints(points);

    McDMatrix<double> Rc, Rd;
    McDVector<double> t;
    double s;
    const mtalign::AlignInfo info = cpd.align(Rc, s, t, Rd);

    applyRigidDeformationToSliceVanMises(slice2, resultSG, cpd, Rc, s, t);
    portCPDResults.setValue(0, info.sigmaSquare);
    portCPDResults.setValue(1, info.kappa);
    portCPDResults.setValue(2, s);
    double rho = mtalign::rotationAngle2d(Rc);

    portCPDResults.setValue(3, rho);
    portCPDResults.setValue(4, t[0]);
    portCPDResults.setValue(5, t[1]);
    portCPDResults.setValue(6, info.numIterations);

    resultSG->touch();
    resultSG->fire();
}
float AssignEModulus::averageVoxels( const OBLelement3D* FEelement,
									const McDArray<McVec3f>& vertices,
									HxUniformScalarField3* field )
{
	if ( !FEelement ) { return 0; }

	McVec3f pcoords;

	// Create an instance of HxLoc3Regular instead of HxLocation3,
	// because we know we are dealing with a uniform scalar field and
	// we want access to the voxelindices
	//HxLoc3Regular* location = image->coords()->createLocation();
	HxLoc3Regular* location = (HxLoc3Regular*)field->createLocation();

	// determine bounding box of voxel indices within element
	location->set( vertices[0][0], vertices[0][1], vertices[0][2] );
	int indexbbox[6] = { location->ix, location->ix,
						location->iy, location->iy,
						location->iz, location->iz };
	for ( int el = 1; el < vertices.size(); el++ )
	{
		location->move( vertices[el][0], vertices[el][1], vertices[el][2] );
		if ( location->ix < indexbbox[0] ) { indexbbox[0] = location->ix; }
		if ( location->ix > indexbbox[1] ) { indexbbox[1] = location->ix; }
		if ( location->iy < indexbbox[2] ) { indexbbox[2] = location->iy; }
		if ( location->iy > indexbbox[3] ) { indexbbox[3] = location->iy; }
		if ( location->iz < indexbbox[4] ) { indexbbox[4] = location->iz; }
		if ( location->iz > indexbbox[5] ) { indexbbox[5] = location->iz; }
	}

	float sum = 0.0;
	int count = 0;
	for ( int k = indexbbox[4]; k <= indexbbox[5]; k++ )
	{
		for ( int j = indexbbox[2]; j <= indexbbox[3]; j++ )
		{
			for ( int i = indexbbox[0]; i <= indexbbox[1]; i++ )
			{
				float point[3];
				field->lattice.coords()->pos( i, j, k, point );
				int inside = FEelement->getIsoParam( vertices,
					McVec3f(point[0],point[1], point[2]), pcoords );
				if ( inside == 1 )
				{
					location->move( point );
					float value;
					field->eval( location, &value );
					sum += value;
					count++;
				}
			}
		}
	}
	delete location;

	return ( count > 0 ) ? ( sum/count ) : 0.0;
}
void MicrotubuleTransformOperation::undo() {
    SbMatrix invMat = mMat.inverse();
    SpatialGraphSelection::Iterator iter(mSelection);
    iter.vertices.reset();
    int vNum = iter.vertices.nextSelected();
    while (vNum != -1) {
        McVec3f c = graph->getVertexCoords(vNum);
        SbVec3f t(c.x, c.y, c.z);
        SbVec3f res;
        invMat.multVecMatrix(t, res);
        graph->setVertexCoords(vNum, McVec3f(res[0], res[1], res[2]));
        vNum = iter.vertices.nextSelected();
    }

    iter.edges.reset();
    int eNum = iter.edges.nextSelected();
    while (eNum != -1) {
        McDArray<McVec3f> points = graph->getEdgePoints(eNum);
        for (int p = 0; p < points.size(); p++) {
            SbVec3f t(points[p].x, points[p].y, points[p].z);
            SbVec3f res;
            invMat.multVecMatrix(t, res);
            points[p] = McVec3f(res[0], res[1], res[2]);
        }
        graph->setEdgePoints(eNum, points);
        eNum = iter.edges.nextSelected();
    }
    int numPoints = mSelection.getNumSelectedPoints();
    for (int i = 0; i < numPoints; ++i) {
        SpatialGraphPoint p = mSelection.getSelectedPoint(i);
        McDArray<McVec3f> points = graph->getEdgePoints(p.edgeNum);
        SbVec3f t(points[p.pointNum].x, points[p.pointNum].y,
                  points[p.pointNum].z);
        SbVec3f res;
        invMat.multVecMatrix(t, res);
        points[p.pointNum] = McVec3f(res[0], res[1], res[2]);
        graph->setEdgePoints(p.edgeNum, points);
    }

    // update the transform parameters
    for (int i = 0; i < mTransParams.size(); ++i) {
        appendTransform(mTransParams[i], invMat);
    }
}
void HxMovingLeastSquaresWarp::compute() {
    if (!portAction.wasHit())
        return;

    HxUniformScalarField3* fromImage =
        (HxUniformScalarField3*)portFromImage.getSource();

    HxLandmarkSet* pointSet = hxconnection_cast<HxLandmarkSet>(portData);

    if (!fromImage)
        return;

    /* It is ok to warp without landmarks, if method is rigid and
       input has a transformation */
    if (!pointSet) {
        return;
    } else if (pointSet->getNumSets() < 2) {
        theMsg->printf(
            "Error: LandmarkWarp data has to contain at least 2 sets.");
        return;
    }

    HxUniformScalarField3* outputImage;

    HxUniformVectorField3* outputVectorField = 0;

    outputImage = createOutputDataSet();
    outputVectorField = createOutputVectorDataSet();

    float* outputImageData = (float*)outputImage->lattice().dataPtr();

    McDArray<McVec2d> landmarks1, landmarks2;

    prepareLandmarks(landmarks1, landmarks2);

    MovingLeastSquares mls;
    mls.setAlpha(portAlpha.getValue());
    mls.setLandmarks(landmarks2, landmarks1);

    const McDim3l& dims = outputImage->lattice().getDims();

    McVec3f voxelSizeInOutputImage = outputImage->getVoxelSize();
    const McBox3f& bboxOfOutputImage = outputImage->getBoundingBox();
    const McBox3f& bboxOfFromImage = fromImage->getBoundingBox();
#ifdef _OPENMP
#pragma omp parallel for
#endif
    for (int i = 0; i < dims[0]; i++) {
        HxLocation3* locationInFromImage = fromImage->createLocation();
        std::cout << "\n" << i << " of " << dims[0];
        for (int j = 0; j < dims[1]; j++) {
            McVec2d currentPositionInOutput = McVec2d(
                bboxOfOutputImage[0] + (float)(i)*voxelSizeInOutputImage.x,
                bboxOfOutputImage[2] + (float)(j)*voxelSizeInOutputImage.y);
            McVec2d warpedCoordInFromImage =
                mls.interpolate(currentPositionInOutput);
            McVec3f displacement = McVec3f(
                warpedCoordInFromImage.x - currentPositionInOutput.x,
                warpedCoordInFromImage.y - currentPositionInOutput.y, 0);

            displacement = displacement * -1;
            locationInFromImage->move(McVec3f(warpedCoordInFromImage.x,
                                              warpedCoordInFromImage.y,
                                              bboxOfFromImage[4]));
            float resultValue[1];
            fromImage->eval(*locationInFromImage, resultValue);
            unsigned long pos = latticePos(i, j, 0, dims);
            outputImageData[pos] = resultValue[0];
            outputVectorField->lattice().set(i, j, 0, displacement.getValue());
        }
        delete locationInFromImage;
    }

    outputImage->touch();
    outputImage->fire();
}
void HxCPDSpatialGraphWarp::warpPoint(const McVec3f& source, McVec3f& target,
                                      MovingLeastSquares& mlsInterpolator) {
    McVec2d curPoint = McVec2d(source.x, source.y);
    McVec2d warpedPoint = mlsInterpolator.interpolate(curPoint);
    target = McVec3f(warpedPoint.x, warpedPoint.y, source.z);
}