Cutting Plane and Isosurface

../../../_images/cutiso_example.png

This example shows how to use the isosurface and cutting plane features in a VTFx file. Isosurfaces and cutting planes are set as case properties.

  • Isosurface

    • An isosurface is defined as an area with a constant result value (e.g. pressure, temperature, velocity, density) within a volume of space. It is the 3D equivalent of a contour line.

    • An isosurface is derived from a scalar result and a scalar value

    • An isosurface can have (the same or another) scalar result shown as fringes on the surface

    • An isosurface can also have a vector result shown on it

  • Cutting plane

    • A cutting plane is defined by a point and a normal

    • A cutting plane can have a scalar or vector result shown on it

This example creates a small part with a scalar result shown as fringes and adds an isosurface and a cutting plane. The part is set transparent to make the isosurface and cutting plane viewable.

Source file

//--------------------------------------------------------------------------------------------------
// Main function, program entry point
//--------------------------------------------------------------------------------------------------
int main()
{
    // Initialize components and set up logging to console
    // -------------------------------------------------------------------------
    g_componentInstance = cee::CoreComponent::initialize(HOOPS_LICENSE);
    cee::vtfx::VTFxComponent::initialize(g_componentInstance.get());

    cee::PtrRef<cee::LogDestinationConsole> log = new cee::LogDestinationConsole();
    cee::CoreComponent::logManager()->setDestination(log.get());
    cee::CoreComponent::logManager()->setLevel("", 3);               // Log errors, warnings and info


    // Create the VTFx file
    // -------------------------------------------------------------------------
    cee::PtrRef<cee::vtfx::File> file = new cee::vtfx::File;

    // Create VTFx file settings struct
    // -------------------------------------------------------------------------
    cee::vtfx::FileSettings fileSettings;
    fileSettings.applicationName = "VTFx: VTFxCutIso";
    fileSettings.vendorName = "My Company AS";

    // Let the API create the VTFx file 
    cee::Str fileName = "ExampleCutIso.vtfx";
    if (!file->create(fileName, fileSettings))
    {
        return EXIT_FAILURE;
    }

    // Create a single database (could have many)
    // -------------------------------------------------------------------------
    cee::PtrRef<cee::vtfx::Database> database = new cee::vtfx::Database(file.get(), "Only Database", 1); // database id 1

    // Create a single case (could have many)
    // -------------------------------------------------------------------------
    cee::PtrRef<cee::vtfx::Case> singleCase = new cee::vtfx::Case(file.get(), "Only Case", 1, 1); // case id 1 using database with id 1

    // Create part (a cube)
    // -------------------------------------------------------------------------
    {
        // Create the node block
        cee::PtrRef<cee::vtfx::NodeBlock> nodeBlock1 = new cee::vtfx::NodeBlock(1, false); // node block id 1
        {
            std::vector<float> nodesPart(NODES_PART, NODES_PART + sizeof(NODES_PART) / sizeof(NODES_PART[0]));
            if (!nodeBlock1->setNodes(nodesPart))
            {
                return EXIT_FAILURE;
            }

            if (!database->writeBlock(nodeBlock1.get()))
            {
                return EXIT_FAILURE;
            }
        }

        // Create the element block, using index mapping for the nodes
        cee::PtrRef<cee::vtfx::ElementBlock> elementBlock1 = new cee::vtfx::ElementBlock(1, false, false); // element block id 1
        {
            elementBlock1->setNodeBlockId(1); // Use node block with id = 1
            std::vector<int> elementNodes(CONNECTS_PART, CONNECTS_PART + sizeof(CONNECTS_PART) / sizeof(CONNECTS_PART[0]));
            if (!elementBlock1->addElements(cee::vtfx::ElementBlock::HEXAHEDRONS, elementNodes))
            {
                return EXIT_FAILURE;
            }

            if (!database->writeBlock(elementBlock1.get()))
            {
                return EXIT_FAILURE;
            }
        }
    }


    // Write Geometry definition
    // -------------------------------------------------------------------------
    cee::PtrRef<cee::vtfx::GeometryBlock> geoBlock = new cee::vtfx::GeometryBlock(1); // Only one geometry per state
    {
        size_t geoIndex = 0;
        int partId = 1;

        // Set the element data 
        if (!geoBlock->addElementBlock(geoIndex, 1, partId)) // Add element block with id = 1.
        {
            return EXIT_FAILURE;
        }

        if (!database->writeBlock(geoBlock.get()))
        {
            return EXIT_FAILURE;
        }

        // Set geometry info
        cee::PtrRef<cee::vtfx::GeometryInfoBlock> infoBlock = new cee::vtfx::GeometryInfoBlock(1); // Only one geometry per state
        infoBlock->addPartInfo(geoIndex, partId, cee::Str("Cube"));
        if (!database->writeBlock(infoBlock.get()))
        {
            return EXIT_FAILURE;
        }
    }


    // Write state information 
    // -------------------------------------------------------------------------
    cee::PtrRef<cee::vtfx::StateInfoBlock> stepInfo = new cee::vtfx::StateInfoBlock;
    {
        if (!stepInfo->addStateInfo(1, "First step", 1.0f, cee::vtfx::StateInfoBlock::TIME))
        {
            return EXIT_FAILURE;
        }

        if (!database->writeBlock(stepInfo.get()))
        {
            return EXIT_FAILURE;
        }
    }


    // Write the scalar results
    // -------------------------------------------------------------------------
    cee::PtrRef<cee::vtfx::ResultBlock> scalarResult = new cee::vtfx::ResultBlock(1, cee::vtfx::ResultBlock::SCALAR, cee::vtfx::ResultBlock::NODE_MAPPING);
    {
        // Part 1 (the cube)
        {
            // Result values for step 1
            cee::PtrRef<cee::vtfx::ResultValuesBlock> resultValuesBlockPart1Step1 = new cee::vtfx::ResultValuesBlock(1, cee::vtfx::ResultValuesBlock::SCALAR1D, false);
            {
                if (!resultValuesBlockPart1Step1->setMapToBlockId(1, cee::vtfx::Block::NODES)) // Use node block with id = 1
                {
                    return EXIT_FAILURE;
                }

                std::vector<float> resultValues(SCALAR_PART, SCALAR_PART + sizeof(SCALAR_PART) / sizeof(SCALAR_PART[0]));
                if (!resultValuesBlockPart1Step1->setResultValues(resultValues))
                {
                    return EXIT_FAILURE;
                }

                if (!database->writeBlock(resultValuesBlockPart1Step1.get()))
                {
                    return EXIT_FAILURE;
                }
            }
        }

        // Assign the result values blocks to state ids. Order is not significant.
        if (!scalarResult->addResultValuesBlock(1, 1))
        {
            return EXIT_FAILURE;
        }
        scalarResult->setResultId(1);
        scalarResult->setName("My scalar result");

        if (!database->writeBlock(scalarResult.get()))
        {
            return EXIT_FAILURE;
        }
    }


    // Write properties
    // -------------------------------------------------------------------------
    cee::PtrRef<cee::PropertySetCollection> vtfxProps = new cee::PropertySetCollection;
    {
        // Show result with id = 1 as fringes
        cee::PtrRef<cee::PropertySet> scalarSelection = new cee::PropertySet("result_selection");
        scalarSelection->setValue("fringes_result_id", 1);
        vtfxProps->addPropertySet(scalarSelection.get());

        // Show part as transparent
        cee::PtrRef<cee::PropertySet> partSettings = new cee::PropertySet("part_settings");
        partSettings->setValue("context_geometry_index", static_cast<unsigned int>(0));
        partSettings->setValue("context_part_id", 1);
        partSettings->setValue("opacity", 0.2f);
        vtfxProps->addPropertySet(partSettings.get());

        // Create and show cutting plane. Show result (id = 1) on plane.
        cee::PtrRef<cee::PropertySet> cuttingPlane = new cee::PropertySet("cutting_plane");
        cuttingPlane->setValue("point", cee::Vec3d(1.0, 1.0, 0.5));
        cuttingPlane->setValue("normal", cee::Vec3d(0.0, 0.0, 1.0));
        cuttingPlane->setValue("map_scalar_result_id", 1);
        cuttingPlane->setValue("visible", true);
        vtfxProps->addPropertySet(cuttingPlane.get());

        // Create an show isosurface. 
        cee::PtrRef<cee::PropertySet> isosurface = new cee::PropertySet("isosurface");
        isosurface->setValue("iso_scalar_result_id", 1);
        isosurface->setValue("map_scalar_result_id", 1);
        isosurface->setValue("iso_value", 2.0);
        isosurface->setValue("visible", true);
        vtfxProps->addPropertySet(isosurface.get());

        // Set the camera to look at the model from negative y axis
        cee::PtrRef<cee::PropertySet> camera = new cee::PropertySet("camera");
        camera->setValue("eye", cee::Vec3d(1.0, -7.5, 0.5));
        camera->setValue("vrp", cee::Vec3d(1.0, -5.5, 0.5));
        camera->setValue("vup", cee::Vec3d(0.0,  0.0, 1.0));
        vtfxProps->addPropertySet(camera.get());

        // Write the block
        if (!singleCase->setProperties(vtfxProps.get()))
        {
            return EXIT_FAILURE;
        }
    }

    // Finally close the file
    // -------------------------------------------------------------------------
    if (!file->close())
    {
        return EXIT_FAILURE;
    }
    
    std::cout << "Exported successfully to file: " << fileName.toStdString() << std::endl;
    std::cout << std::endl << "Press enter to exit..." << std::endl;
    std::cin.ignore();

    return EXIT_SUCCESS;
}

Header file

// Nodes
// -----------------------------------------------------------------------------
const float NODES_PART[] =
{
    0.0f, 0.0f, 0.0f,
    1.0f, 0.0f, 0.0f,
    2.0f, 0.0f, 0.0f,
    0.0f, 0.0f, 1.0f,
    1.0f, 0.0f, 1.0f,
    2.0f, 0.0f, 1.0f,
    0.0f, 0.0f, 2.0f,
    1.0f, 0.0f, 2.0f,
    2.0f, 0.0f, 2.0f,

    0.0f, 1.0f, 0.0f,
    1.0f, 1.0f, 0.0f,
    2.0f, 1.0f, 0.0f,
    0.0f, 1.0f, 1.0f,
    1.0f, 1.0f, 1.0f,
    2.0f, 1.0f, 1.0f,
    0.0f, 1.0f, 2.0f,
    1.0f, 1.0f, 2.0f,
    2.0f, 1.0f, 2.0f,

    0.0f, 2.0f, 0.0f,
    1.0f, 2.0f, 0.0f,
    2.0f, 2.0f, 0.0f,
    0.0f, 2.0f, 1.0f,
    1.0f, 2.0f, 1.0f,
    2.0f, 2.0f, 1.0f,
    0.0f, 2.0f, 2.0f,
    1.0f, 2.0f, 2.0f,
    2.0f, 2.0f, 2.0f
};

// Connectivities
// -----------------------------------------------------------------------------
const int CONNECTS_PART[] = 
{
    0, 1, 10, 9, 3, 4, 13, 12,
    1, 2, 11, 10, 4, 5, 14, 13,
    3, 4, 13, 12, 6, 7, 16, 15,
    4, 5, 14, 13, 7, 8, 17, 16,
    9, 10, 19, 18, 12, 13, 22, 21,
    10, 11, 20, 19, 13, 14, 23, 22,
    12, 13, 22, 21, 15, 16, 25, 24,
    13, 14, 23, 22, 16, 17, 26, 25
};

// Scalar result values
// -----------------------------------------------------------------------------
const float SCALAR_PART[] =
{
    4.0f, 4.0f, 4.0f, 3.0f, 3.0f, 3.0f, 2.0f, 2.0f, 2.0f,
    3.0f, 3.0f, 3.0f, 2.0f, 2.0f, 2.0f, 1.0f, 1.0f, 1.0f,
    3.0f, 3.0f, 3.0f, 2.0f, 2.0f, 2.0f, 0.0f, 0.0f, 0.0f
};