# Adaptive Topology

This example shows how to write a model where the topology changes between time steps (model is remeshed).

The example writes out a very simple model which consists of one triangle in the first time step, which is then changed (“remeshed”) into two triangles in the second time step. The example also includes a scalar result (with per element mapping) for the two time steps.

To setup an adaptive topology model, you first write out all the unique element blocks and node blocks. You then specify the sequence of the element blocks in the `cee::vtfx::GeometryBlock`. Use the `addElementBlockForState()` method to specify a given element block for a given state.

Please note that you either have to provide geometry setup for all time steps or one geometry setup for each step in your analysis. However, if you have a changing topology on only some time steps, you can reuse the element and node blocks by referring to them from several time steps.

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

        // Let the API create the VTFx file
        const cee::Str fileName = "ExampleAdaptiveTopology.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
        // -------------------------------------------------------------------------
        {
            // 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
        // -------------------------------------------------------------------------
        {
            // 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;
                }
            }
        }

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

            // Set the element data
            if (!geoBlock->addElementBlockForState(geoIdx, 1, 1, partId) ||
                !geoBlock->addElementBlockForState(geoIdx, 2, 2, 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(1); // Only one geometry per state
            infoBlock->addPartInfo(geoIdx, partId, cee::Str("Adaptive part"));

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

        // Write state information
        // -------------------------------------------------------------------------
        cee::PtrRef<cee::vtfx::StateInfoBlock> stepInfo = new cee::vtfx::StateInfoBlock;
        {
            stepInfo->addStateInfo(1, "First step",  1.0f, cee::vtfx::StateInfoBlock::TIME);
            stepInfo->addStateInfo(2, "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
            {
                // 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;
                    }
                }
            }

            // Assign the result values blocks to state ids. Order is not significant.
            scalarResult->addResultValuesBlock(11, 1);
            scalarResult->addResultValuesBlock(12, 2);
            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[] = { 1, 2 };
            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(1.0, 1.0, 5.0));
            camera->setValue("vrp", cee::Vec3d(1.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;

Conversation saved
HOOPSY BETA

### Hello! I'm HOOPSY

Your multilingual generative AI assistant for documentation. Ask me anything about HOOPS Envision for Desktop in your own language, or choose a sample question below to start a conversation:

What is HOOPS Envision for Desktop?
What are the latest release notes for HOOPS Envision for Desktop?
How do I start evaluating HOOPS Envision for Desktop?
How do I write my first sample application?
How can I get assistance?

HOOPSY may store conversations according to OpenAI's policy. Responses may not always be accurate.

HOOPSY is thinking...