Simple VTFx File

../../../_images/simple_example.png

Small VTFx file showing the use of results, multiple states and properties.

This example contains of two simple parts. The first part consists of a single hexahedron element and the second part of a single pyramid element. It is also set up with three states and one scalar result. The scalar result is defined for both parts and for all three states.

This example also uses properties for the following features:

  • Show the scalar result as fringes on the parts

  • Select all three states (to run an animation over all states)

  • Set the animation to start when the file is opened in a viewer

  • Set the initial camera position

    // 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: VTFxSimple";
    fileSettings.vendorName = "My Company AS";
    fileSettings.binary = false;

    // Let the API create the VTFx file 
    const cee::Str fileName = "ExampleSimple.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 1 (a cube)
    // -------------------------------------------------------------------------
    {
        // Create the node block
        cee::PtrRef<cee::vtfx::NodeBlock> nodeBlock1 = new cee::vtfx::NodeBlock(1, false);
        {
            // Set the node data (Note: Express Writer expects interleaved node coordinates (xyzxyzxyz...))
            const float NODES_PART_1[] =
            {
                0.0f, 0.0f, 0.0f,
                1.0f, 0.0f, 0.0f,
                1.0f, 1.0f, 0.0f,
                0.0f, 1.0f, 0.0f,
                0.0f, 0.0f, 1.0f,
                1.0f, 0.0f, 1.0f,
                1.0f, 1.0f, 1.0f,
                0.0f, 1.0f, 1.0f
            };

            std::vector<float> nodesPart(NODES_PART_1, NODES_PART_1 + sizeof(NODES_PART_1) / sizeof(NODES_PART_1[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);
        {
            elementBlock1->setNodeBlockId(1); // Use node block with id = 1

            // Set the element data
            const int CONNECTS_PART_1[] = { 0, 1, 2, 3, 4, 5, 6, 7 };
            std::vector<int> elementNodes(CONNECTS_PART_1, CONNECTS_PART_1 + sizeof(CONNECTS_PART_1) / sizeof(CONNECTS_PART_1[0]));
            if (!elementBlock1->addElements(cee::vtfx::ElementBlock::HEXAHEDRONS, elementNodes))
            {
                return EXIT_FAILURE;
            }

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

    // Create part 2 (a pyramid)
    // -------------------------------------------------------------------------
    {
        // Create the node block
        cee::PtrRef<cee::vtfx::NodeBlock> nodeBlock2 = new cee::vtfx::NodeBlock(2, false);
        {
            // Set the node data (Note: Express Writer expects interleaved node coordinates (xyzxyzxyz...))
            const float NODES_PART_2[] =
            {
                3.0f, 0.0f, 0.0f,
                4.0f, 0.0f, 0.0f,
                4.0f, 1.0f, 0.0f,
                3.0f, 1.0f, 0.0f,
                3.5f, 0.5f, 1.0f
            };

            std::vector<float> nodesPart(NODES_PART_2, NODES_PART_2 + sizeof(NODES_PART_2) / sizeof(NODES_PART_2[0]));
            if (!nodeBlock2->setNodes(nodesPart))
            {
                return EXIT_FAILURE;
            }

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

        // Create the element block, using index mapping for the nodes
        cee::PtrRef<cee::vtfx::ElementBlock> elementBlock2 = new cee::vtfx::ElementBlock(2, false, false);
        {
            elementBlock2->setNodeBlockId(2); // Use node block with id = 2

            // Set the element data
            const int CONNECTS_PART_2[] = { 0, 1, 2, 3, 4 };
            std::vector<int> elementNodes(CONNECTS_PART_2, CONNECTS_PART_2 + sizeof(CONNECTS_PART_2) / sizeof(CONNECTS_PART_2[0]));
            if (!elementBlock2->addElements(cee::vtfx::ElementBlock::PYRAMIDS, elementNodes))
            {
                return EXIT_FAILURE;
            }

            if (!database->writeBlock(elementBlock2.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 partIdCube = 1;
        int partIdPyramid = 2;

        // Set the element data
        if (!geoBlock->addElementBlock(geoIndex, 1, partIdCube) ||  // element block with id = 1
            !geoBlock->addElementBlock(geoIndex, 2, partIdPyramid)) // element block with id = 2
        {
            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, partIdCube, cee::Str("Cube"));
        infoBlock->addPartInfo(geoIndex, partIdPyramid, cee::Str("Pyramid"));

        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) ||
            !stepInfo->addStateInfo(2, "Second step", 2.0f, cee::vtfx::StateInfoBlock::TIME) ||
            !stepInfo->addStateInfo(3, "Third step", 3.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(11, cee::vtfx::ResultValuesBlock::SCALAR1D, false);
            {
                if (!resultValuesBlockPart1Step1->setMapToBlockId(1, cee::vtfx::Block::NODES))
                {
                    return EXIT_FAILURE;
                }

                const float RESULT_VALUES[] = { 0.0f, 0.5f, 1.0f, 1.0f, 2.0f, 2.0f, 2.0f, 3.0f };
                std::vector<float> resultValues(RESULT_VALUES, RESULT_VALUES + sizeof(RESULT_VALUES) / sizeof(RESULT_VALUES[0]));
                if (!resultValuesBlockPart1Step1->setResultValues(resultValues))
                {
                    return EXIT_FAILURE;
                }

                if (!database->writeBlock(resultValuesBlockPart1Step1.get()))
                {
                    return EXIT_FAILURE;
                }
            }
            // Result values for step 2
            cee::PtrRef<cee::vtfx::ResultValuesBlock> resultValuesBlockPart1Step2 = new cee::vtfx::ResultValuesBlock(12, cee::vtfx::ResultValuesBlock::SCALAR1D, false);
            {
                if (!resultValuesBlockPart1Step2->setMapToBlockId(1, cee::vtfx::Block::NODES))
                {
                    return EXIT_FAILURE;
                }

                const float RESULT_VALUES[] = { 0.0f, 0.5f, 2.5f, 2.5f, 3.0f, 3.0f, 3.0f, 4.0f };
                std::vector<float> resultValues(RESULT_VALUES, RESULT_VALUES + sizeof(RESULT_VALUES) / sizeof(RESULT_VALUES[0]));
                if (!resultValuesBlockPart1Step2->setResultValues(resultValues))
                {
                    return EXIT_FAILURE;
                }

                if (!database->writeBlock(resultValuesBlockPart1Step2.get()))
                {
                    return EXIT_FAILURE;
                }
            }
            // Result values for step 3
            cee::PtrRef<cee::vtfx::ResultValuesBlock> resultValuesBlockPart1Step3 = new cee::vtfx::ResultValuesBlock(13, cee::vtfx::ResultValuesBlock::SCALAR1D, false);
            {
                if (!resultValuesBlockPart1Step3->setMapToBlockId(1, cee::vtfx::Block::NODES))
                {
                    return EXIT_FAILURE;
                }

                const float RESULT_VALUES[] = { 0.0f, 0.5f, 2.5f, 2.5f, 3.0f, 3.0f, 4.0f, 6.0f };
                std::vector<float> resultValues(RESULT_VALUES, RESULT_VALUES + sizeof(RESULT_VALUES) / sizeof(RESULT_VALUES[0]));
                if (!resultValuesBlockPart1Step3->setResultValues(resultValues))
                {
                    return EXIT_FAILURE;
                }

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

        // Part 2 (the pyramid)
        {
            // Result values for step 1
            cee::PtrRef<cee::vtfx::ResultValuesBlock> resultValuesBlockPart2Step1 = new cee::vtfx::ResultValuesBlock(21, cee::vtfx::ResultValuesBlock::SCALAR1D, false);
            {
                if (!resultValuesBlockPart2Step1->setMapToBlockId(2, cee::vtfx::Block::NODES))
                {
                    return EXIT_FAILURE;
                }

                const float RESULT_VALUES[] = { 0.0f, 0.5f, 1.0f, 1.0f, 1.5f };
                std::vector<float> resultValues(RESULT_VALUES, RESULT_VALUES + sizeof(RESULT_VALUES) / sizeof(RESULT_VALUES[0]));
                if (!resultValuesBlockPart2Step1->setResultValues(resultValues))
                {
                    return EXIT_FAILURE;
                }

                if (!database->writeBlock(resultValuesBlockPart2Step1.get()))
                {
                    return EXIT_FAILURE;
                }
            }
            // Result values for step 2
            cee::PtrRef<cee::vtfx::ResultValuesBlock> resultValuesBlockPart2Step2 = new cee::vtfx::ResultValuesBlock(22, cee::vtfx::ResultValuesBlock::SCALAR1D, false);
            {
                if (!resultValuesBlockPart2Step2->setMapToBlockId(2, cee::vtfx::Block::NODES))
                {
                    return EXIT_FAILURE;
                }

                const float RESULT_VALUES[] = { 0.0f, 0.5f, 1.0f, 1.0f, 3.5f };
                std::vector<float> resultValues(RESULT_VALUES, RESULT_VALUES + sizeof(RESULT_VALUES) / sizeof(RESULT_VALUES[0]));
                if (!resultValuesBlockPart2Step2->setResultValues(resultValues))
                {
                    return EXIT_FAILURE;
                }

                if (!database->writeBlock(resultValuesBlockPart2Step2.get()))
                {
                    return EXIT_FAILURE;
                }
            }
            // Result values for step 3
            cee::PtrRef<cee::vtfx::ResultValuesBlock> resultValuesBlockPart2Step3 = new cee::vtfx::ResultValuesBlock(23, cee::vtfx::ResultValuesBlock::SCALAR1D, false);
            {
                if (!resultValuesBlockPart2Step3->setMapToBlockId(2, cee::vtfx::Block::NODES))
                {
                    return EXIT_FAILURE;
                }

                const float RESULT_VALUES[] = { 0.0f, 0.5f, 1.0f, 1.0f, 6.0f };
                std::vector<float> resultValues(RESULT_VALUES, RESULT_VALUES + sizeof(RESULT_VALUES) / sizeof(RESULT_VALUES[0]));
                if (!resultValuesBlockPart2Step3->setResultValues(resultValues))
                {
                    return EXIT_FAILURE;
                }

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

        // Assign the result values blocks to state ids. Order is not significant.
        if (!scalarResult->addResultValuesBlock(11, 1) ||
            !scalarResult->addResultValuesBlock(12, 2) ||
            !scalarResult->addResultValuesBlock(13, 3) ||
            !scalarResult->addResultValuesBlock(21, 1) ||
            !scalarResult->addResultValuesBlock(22, 2) ||
            !scalarResult->addResultValuesBlock(23, 3))
        {
            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());

        // Set animation to run over all states
        cee::PtrRef<cee::PropertySet> stateSelection = new cee::PropertySet("state_selection");
        const cee::Variant STATE_IDS[] = { 1, 2, 3 };
        std::vector<cee::Variant> stateIds(STATE_IDS, STATE_IDS + sizeof(STATE_IDS) / sizeof(STATE_IDS[0]));
        stateSelection->setValue("state_ids", stateIds);
        vtfxProps->addPropertySet(stateSelection.get());

        // Start animation when opening file. Set frames per second to 3.0.
        cee::PtrRef<cee::PropertySet> viewer = new cee::PropertySet("viewer");
        viewer->setValue("animation_fps", 3.0);
        viewer->setValue("start_animation", true);
        vtfxProps->addPropertySet(viewer.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(2.0, -7.5, 0.5));
        camera->setValue("vrp", cee::Vec3d(2.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;