HxUniformVectorField3* HxMovingLeastSquaresWarp::createOutputVectorDataSet() {
    HxUniformScalarField3* fromImage =
        dynamic_cast<HxUniformScalarField3*>(portFromImage.getSource());
    HxUniformVectorField3* output =
        dynamic_cast<HxUniformVectorField3*>(getResult(1));

    if (!fromImage)
        return (0);

    McDim3l dims;
    McBox3f bbox;

    if (fromImage) {
        dims = fromImage->lattice().getDims();
        bbox = fromImage->getBoundingBox();
    }
    if (!output || output->lattice().getDims() != dims)
        output = 0;

    if (!output) {
        output = new HxUniformVectorField3(dims, McPrimType::MC_FLOAT);
    }
    output->lattice().setBoundingBox(bbox);
    output->composeLabel(fromImage->getLabel(), "Displacement");
    setResult(1, output);
    return (output);
}
HxUniformScalarField3* HxMovingLeastSquaresWarp::createOutputDataSet() {
    HxUniformScalarField3* fromImage =
        dynamic_cast<HxUniformScalarField3*>(portFromImage.getSource());
    HxUniformScalarField3* toImage =
        dynamic_cast<HxUniformScalarField3*>(portToImage.getSource());
    HxUniformScalarField3* warpedImage =
        dynamic_cast<HxUniformScalarField3*>(getResult(0));

    if (!fromImage)
        return (0);

    McDim3l dims;
    McBox3f bbox;

    if (toImage) {
        dims = toImage->lattice().getDims();
        bbox = toImage->getBoundingBox();
    }
    if (!warpedImage || warpedImage->lattice().getDims()[0] != dims[0] ||
        warpedImage->lattice().getDims()[1] != dims[1] ||
        warpedImage->lattice().getDims()[2] != dims[2])
        warpedImage = 0;

    if (!warpedImage) {
        if (toImage->isOfType(HxUniformLabelField3::getClassTypeId())) {
            warpedImage = new HxUniformLabelField3(dims);
            ((HxUniformLabelField3*)warpedImage)->parameters =
                ((HxUniformLabelField3*)fromImage)->parameters;
        } else
            warpedImage =
                new HxUniformScalarField3(dims, fromImage->primType());
    }

    warpedImage->setBoundingBox(bbox);
    warpedImage->composeLabel(fromImage->getLabel(), "Warped");
    setResult(0, warpedImage);
    return (warpedImage);
}
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();
}