bitpit icon indicating copy to clipboard operation
bitpit copied to clipboard

Levelset use multi solid objects

Open tbjoss opened this issue 4 years ago • 2 comments

Hello everyone,

Is there a simple way to add individual parts of a SurfUnstructured as a new object to the Levelset? My use case is that I would like to access and perform operations only with certain parts of the object. Is there a simple way to achieve this?

Or do I have to decompose the multi solid STL into individuals, so that I can add them as individual objects to the Levelset?

Any advice would be highly appreciated.

tbjoss avatar Jan 18 '21 19:01 tbjoss

I don't think what you are willing to achieve can be done without using multiple SurfUnstructured objects.

What you can do (but it may not be what you need) is tag each cell of the SurfUnstructured patch with a part id (facet.setPID(int pid)), then you can ask to the levelset which is the closest part to a specified volume cell (levelset.getPart(long cellId)).

If you are able to split the STL into multiple bodies, you can create a SurfUnstructured patch for each body and then add these patches to the levelset:

// Add signle bodies to the levelset
std::vector<int> bodyIds;
for (auto &bodyEntry : bodies) {
        std::unique_ptr<bitpit::SurfUnstructured> bodyPatch = <IMPORT BODY INTO SURFUNSTRUCTURED>
        int bodyId = levelset.addObject(std::move(bodyPatch));
        bodyIds.push_back(bodyId);
}

once you have added all the bodies, you can create a special levelset object that represent the union of all the bodies:

// Create body envelope
int envelpeId = levelset.addObject(LevelSetBooleanOperation::UNION, bodyIds);

this will allow to work with both the single bodies and the body envelope:

bitpit::LevelSetMetaObject const *envelope = levelset.getObjectPtr<LevelSetMetaObject>(envelopeId);
double envelopeDistance = envelope->getLS(cellId);

bitpit::LevelSetMetaObject const *firstBody = levelset.getObjectPtr<LevelSetMetaObject>(bodyIds[0]);
double firstBodyDistance = firstBody->getLS(cellId);

Supported boolean operations are unions (LevelSetBooleanOperation::UNION) and subtractions (LevelSetBooleanOperation::SUBTRACTION).

If you need sign propagation, single bodies have to be closed and well oriented.

andrea-iob avatar Jan 20 '21 08:01 andrea-iob

Thank you for this hint. There is no need to assign the PID manually, if they are properly assigned in the input STL file. I import the files as follows:

constexpr std::string full_file_name = "path/to/file";
constexpr int space_dim{3};
constexpr bool is_binary{false};
constexpr bool pid_offest{0};
constexpr bool pid_squash{false};

auto pid_names = std::make_unique<std::unordered_map<int, std::string>>();
auto surf = std::make_unique<bitpit::SurfUnstructured>(space_dim-1, space_dim);

surf->setExpert(true);
surf->importSTL(full_file_name, is_binary, pid_offest, pid_squash, pid_names.get());

surf->deleteCoincidentVertices();
surf->buildAdjacencies();
surf->getVTK().setName("my_name");

I was not aware of the fact that I can get the PID back by:

const auto& cells = my_vol_octree->getCells();

std::for_each(cells.begin(), cell.end(), [=](const auto& cell) {
    const auto& shape = my_levelset->getObject(my_shape_id);  
    const auto& surf_pid = shape.getPart(cell_id);

    // do something
});

Your idea by making a levelset object out of the multiple surface was my first approach. However, I would like to avoid this. As you mentioned, the body needs to be closed and the surface normals must have the correct sign. It is easy to verify this by making the STL files in the cad software.

tbjoss avatar Jan 20 '21 10:01 tbjoss