Two geometries

../../_images/twogeometries_example.png

This example shows how to write two different geometries to the same database. This could be useful if you have separate entities in your model, and especially so if you are going to read this file into a CEETRON Envision based application where you want to use multiple geometries for structural reasons.

It is also useful to use multiple geometries if some parts of your model/scene have a static topology and some parts have an adaptive topology.

The example shows how to create two geometries in the same model. There are two time steps, and the first part has an adaptive topology and has a different mesh in the two time steps, whereas the second part has the same topology in both states.

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

    // Let the API create the VTFx file 
    const cee::Str fileName = "ExampleTwoGeometries.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 the part for the first time step of Geo Index = 0
    // -------------------------------------------------------------------------
    {
        // 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[] =
            {
                0.0f, 0.0f, 0.0f,
                2.0f, 0.0f, 0.0f,
                2.0f, 2.0f, 0.0f,
            };

            std::vector<float> nodesPart(NODES, NODES + sizeof(NODES) / sizeof(NODES[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[] = { 0, 1, 2};
            std::vector<int> elementNodes(CONNECTS, CONNECTS + sizeof(CONNECTS) / sizeof(CONNECTS[0]));
            if (!elementBlock1->addElements(cee::vtfx::ElementBlock::TRIANGLES, elementNodes))
            {
                return EXIT_FAILURE;
            }

            if (!database->writeBlock(elementBlock1.get()))
            {
                return EXIT_FAILURE;
            }
        }
    }
    
    // Create the part for the second time step of Geo Index = 0
    // -------------------------------------------------------------------------
    {
        // Create the node block
        cee::PtrRef<cee::vtfx::NodeBlock> nodeBlock1 = new cee::vtfx::NodeBlock(2, false);
        {
            // Set the node data (Note: Express Writer expects interleaved node coordinates (xyzxyzxyz...))
            const float NODES[] =
            {
                0.0f, 0.0f, 0.0f,
                2.0f, 0.0f, 0.0f,
                2.0f, 2.0f, 0.0f,
                0.9f, 1.1f, 0.0f,
            };
            
            std::vector<float> nodesPart(NODES, NODES + sizeof(NODES) / sizeof(NODES[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(2, false, false);
        {
            elementBlock1->setNodeBlockId(2); // Use node block with id = 2
            
            // Set the element data
            const int CONNECTS[] = { 0, 1, 3, 1, 2, 3};
            std::vector<int> elementNodes(CONNECTS, CONNECTS + sizeof(CONNECTS) / sizeof(CONNECTS[0]));
            if (!elementBlock1->addElements(cee::vtfx::ElementBlock::TRIANGLES, elementNodes))
            {
                return EXIT_FAILURE;
            }
            
            if (!database->writeBlock(elementBlock1.get()))
            {
                return EXIT_FAILURE;
            }
        }
    }
    
    // Create the constant topology part for Geo Index = 1
    // -------------------------------------------------------------------------
    {
        // Create the node block
        cee::PtrRef<cee::vtfx::NodeBlock> nodeBlock1 = new cee::vtfx::NodeBlock(3, false);
        {
            // Set the node data (Note: Express Writer expects interleaved node coordinates (xyzxyzxyz...))
            const float NODES[] =
            {
                3.0f, 0.0f, 0.0f,
                4.0f, 0.0f, 0.0f,
                4.0f, 1.0f, 0.0f,
                3.0f, 1.0f, 0.0f,
            };
            
            std::vector<float> nodesPart(NODES, NODES + sizeof(NODES) / sizeof(NODES[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(3, false, false);
        {
            elementBlock1->setNodeBlockId(3); // Use node block with id = 2
            
            // Set the element data
            const int CONNECTS[] = { 0, 1, 2, 3 };
            std::vector<int> elementNodes(CONNECTS, CONNECTS + sizeof(CONNECTS) / sizeof(CONNECTS[0]));
            if (!elementBlock1->addElements(cee::vtfx::ElementBlock::QUADS, elementNodes))
            {
                return EXIT_FAILURE;
            }
            
            if (!database->writeBlock(elementBlock1.get()))
            {
                return EXIT_FAILURE;
            }
        }
    }



    // Write Geometry definition
    // -------------------------------------------------------------------------
    int state1Id = 1;
    int state2Id = 2;
    
    cee::PtrRef<cee::vtfx::GeometryBlock> geoBlock = new cee::vtfx::GeometryBlock(2); // Only one geometry per state
    {
        size_t adaptiveGeoIdx = 0;
        size_t staticGeoIdx = 1;
        
        int partId = 1;
        
        // Specify the geometry with adaptive topology
        if (!geoBlock->addElementBlockForState(adaptiveGeoIdx, 1, state1Id, partId) ||
            !geoBlock->addElementBlockForState(adaptiveGeoIdx, 2, state2Id, partId))
        {
            return EXIT_FAILURE;
        }

        partId = 2;

        // Specify the geometry with constant topology - same element block in both states
        if (!geoBlock->addElementBlockForState(staticGeoIdx, 3, state1Id, partId) ||
            !geoBlock->addElementBlockForState(staticGeoIdx, 3, state2Id, partId))
        {
            return EXIT_FAILURE;
        }

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

        // Set geometry info
        cee::PtrRef<cee::vtfx::GeometryInfoBlock> infoBlock = new cee::vtfx::GeometryInfoBlock(2); // Only one geometry per state
        infoBlock->addPartInfo(adaptiveGeoIdx, 1, cee::Str("Geo 0 : Adaptive part"));
        infoBlock->addPartInfo(staticGeoIdx, 2, cee::Str("Geo 1 : Constant part"));

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


    // Write state information 
    // -------------------------------------------------------------------------
    cee::PtrRef<cee::vtfx::StateInfoBlock> stepInfo = new cee::vtfx::StateInfoBlock;
    {
        stepInfo->addStateInfo(state1Id, "First step",  1.0f, cee::vtfx::StateInfoBlock::TIME);
        stepInfo->addStateInfo(state2Id, "Second step", 2.0f, cee::vtfx::StateInfoBlock::TIME);

        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::ELEMENT_MAPPING);
    {
        // Part 1 (adaptive topology)
        {
            // Result values for step 1
            cee::PtrRef<cee::vtfx::ResultValuesBlock> resultValuesBlockPart1Step1 = new cee::vtfx::ResultValuesBlock(11, cee::vtfx::ResultValuesBlock::SCALAR1D, false);
            {
                resultValuesBlockPart1Step1->setMapToBlockId(1, cee::vtfx::Block::ELEMENTS);
                const float RESULT_VALUES[] = { 1.0f };
                std::vector<float> resultValues(RESULT_VALUES, RESULT_VALUES + sizeof(RESULT_VALUES) / sizeof(RESULT_VALUES[0]));
                resultValuesBlockPart1Step1->setResultValues(resultValues);
                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);
            {
                resultValuesBlockPart1Step2->setMapToBlockId(2, cee::vtfx::Block::ELEMENTS);
                const float RESULT_VALUES[] = { 1.0f, 2.0f };
                std::vector<float> resultValues(RESULT_VALUES, RESULT_VALUES + sizeof(RESULT_VALUES) / sizeof(RESULT_VALUES[0]));
                resultValuesBlockPart1Step2->setResultValues(resultValues);
                if (!database->writeBlock(resultValuesBlockPart1Step2.get()))
                {
                    return EXIT_FAILURE;
                }
            }
        }
        
        // Part 2 (constant topology)
        {
            // Result values for step 1
            cee::PtrRef<cee::vtfx::ResultValuesBlock> resultValuesBlockPart1Step1 = new cee::vtfx::ResultValuesBlock(21, cee::vtfx::ResultValuesBlock::SCALAR1D, false);
            {
                resultValuesBlockPart1Step1->setMapToBlockId(3, cee::vtfx::Block::ELEMENTS);
                const float RESULT_VALUES[] = { 1.2f };
                std::vector<float> resultValues(RESULT_VALUES, RESULT_VALUES + sizeof(RESULT_VALUES) / sizeof(RESULT_VALUES[0]));
                resultValuesBlockPart1Step1->setResultValues(resultValues);
                if (!database->writeBlock(resultValuesBlockPart1Step1.get()))
                {
                    return EXIT_FAILURE;
                }
            }
            // Result values for step 2
            cee::PtrRef<cee::vtfx::ResultValuesBlock> resultValuesBlockPart1Step2 = new cee::vtfx::ResultValuesBlock(22, cee::vtfx::ResultValuesBlock::SCALAR1D, false);
            {
                resultValuesBlockPart1Step2->setMapToBlockId(3, cee::vtfx::Block::ELEMENTS);
                const float RESULT_VALUES[] = { 1.4f };
                std::vector<float> resultValues(RESULT_VALUES, RESULT_VALUES + sizeof(RESULT_VALUES) / sizeof(RESULT_VALUES[0]));
                resultValuesBlockPart1Step2->setResultValues(resultValues);
                if (!database->writeBlock(resultValuesBlockPart1Step2.get()))
                {
                    return EXIT_FAILURE;
                }
            }
        }

        // Assign the result values blocks to state ids. Order is not significant.
        scalarResult->addResultValuesBlock(11, state1Id);
        scalarResult->addResultValuesBlock(12, state2Id);
        scalarResult->addResultValuesBlock(21, state1Id);
        scalarResult->addResultValuesBlock(22, state2Id);
        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;
    {
        // Turn on mesh to show the change in model topology
        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("draw_style", "surface_mesh");
        vtfxProps->addPropertySet(partSettings.get());
   
        // 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[] = { state1Id, state2Id };
        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 2.0.
        cee::PtrRef<cee::PropertySet> viewer = new cee::PropertySet("viewer");
        viewer->setValue("animation_fps", 2.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, 1.0, 5.0));
        camera->setValue("vrp", cee::Vec3d(2.0, 1.0, 0.0));
        camera->setValue("vup", cee::Vec3d(0.0, 1.0, 0.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;