jklimke / libcitygml

C++ Library for CityGML Parsing and Visualization
GNU Lesser General Public License v2.1
98 stars 55 forks source link

How to get the index of vertex #86

Open fuqifacai opened 11 months ago

fuqifacai commented 11 months ago

Hi : I can get the vertex info from test gml file by using below sample codes, however there is no index or indics for these vertex info. How can I get that ? My goal is to generate the mesh object by using vertex and index info. Thanks.

std::shared_ptr myPolygon = inGeometry.getPolygon(i); std::shared_ptr myExternalLinearRing = tempPolygon->exteriorRing(); std::vector myExternalLinearVertices = myExternalLinearRing->getVertices();

mlavik1 commented 11 months ago

Hi @fuqifacai !

Maybe I'm misunderstanding, but if your goal is to generate tessellated mesh geometry from a CityGML file, then you should use getVertices() and getIndices() instead of exteriorRing(). The OSG plugin is actually a nice example you could have a look at: https://github.com/jklimke/libcitygml/blob/3f66e6a2ba66404565e0029e3fd51671472af59e/osgplugin/ReaderWriterCityGML.cpp#L361

fuqifacai commented 11 months ago

Thanks for your reply. The problem is I can not get any data from Polygon.getVertices() and getIndices(). they both return null or empty. I can only get some sort of vertex array info from exteriorRing object. The test gml file is which you listed on website: https://www.citygmlwiki.org/index.php?title=FZK_Haus Not sure this is because my test gml file has no vertex info actually , or ..my code is incorrect. I've checked your osg plugin code and sample codes .....

mlavik1 commented 11 months ago

Hi again @fuqifacai

(By the way, I'm not the maintainer of this project - I'm just someone using it, so not everything I say might be 100% correct )

Hmm, that's weird. I was able to successfully get the data from getVertices/getIndices..

I'm wondering, have you created a valid Tesselator and passed it to the citygml::load function? I believe you'll need to build with LIBCITYGML_USE_OPENGL enabled to use that.

This is how I initialise it in our application:

std::unique_ptr<TesselatorBase> tesselator = std::unique_ptr<TesselatorBase>(new Tesselator(nullptr));
std::shared_ptr<const citygml::CityModel> city = citygml::load(filePath, params, std::move(tesselator));

This is how it looks for me:

image

I'm afraid I can't share my full source code (since it belongs to my employer), but maybe I can set up a simple sample project if that's useful?

fuqifacai commented 11 months ago

@mlavik1 Very appreciate your reply . That's very helpful and correct solution . I checked my codes and verified that the problem is that not created with a valid Tesselator object by enable LIBCITYGML_USE_OPENGL macro. Problem solved and result seems perfect. Thanks again .

mlavik1 commented 11 months ago

@fuqifacai Oh, that's great! Glad I could help :grin: Wish you best of luck with your project!

fuqifacai commented 10 months ago

@mlavik1 May I ask did you know why the building's top is red, how can I get this color info from the citygml file ? I've check the whole test file , still can not figure out where the color information is . Thanks for any advice .

mlavik1 commented 10 months ago

Hi again @fuqifacai , So first of all: it seems to be common for some CityGML viewers to use a colour scheme where they set a default colour based on object type ("RoofSurface" is typically red). However, in this case the CityGML contains some colour information. When you've read the CityGML file you can call CityModel::themes() to get a list of themes, and pick one (if it has any - not all models have that).

std::shared_ptr<const citygml::CityModel> city = citygml::load(filePath, params, std::move(tesselator));
const auto& themes = city->themes();
std::string theme = themes.size() > 0 ? themes[0] : ""; // I pick the first one, but if there are several themes you might want to support custom theme selection

Then, when you're processing the geometry you can call Polygon::getMaterialFor(theme) to get the material, and then getDiffuse to get the colour:

unsigned int polygonCount = geometry.getPolygonsCount();
for (unsigned int i = 0; i < polygonCount; ++i)
{
    auto polygon = geometry.getPolygon(i);
    const auto citygmlMaterial = polygon->getMaterialFor(theme);
    if (citygmlMaterial)
    {
        auto col = citygmlMaterial->getDiffuse();
        ...
    }
}

If the polygon has no material for the given theme, then you can call object.getTypeAsString() and pick a default colour based on the type (roofs can be red, etc..).

I'm not 100% sure, but I believe getThemes() will return a list containing one empty string if it has no themes (at least that's the case of this model), but you can still get the material by passing that empty string to polygon->getMaterialFor(theme)

fuqifacai commented 10 months ago

Thanks for your detailed reply . why "RoofSurface" is typically red ?

mlavik1 commented 10 months ago

Thanks for your detailed reply . why "RoofSurface" is typically red ?

No idea! I've just seen it in some software - though I don't have a lot of practical experience with CityGML yet (started working with it a few months ago). But if a CityGML has no colour data, it would look bad to colour everything white, so it might sense to add some default colours. Here's an example from CityJSON Ninja: image (https://ninja.cityjson.org/)

mlavik1 commented 10 months ago

But for this specific model that shouldn't be needed, since it already has materials.

jklimke commented 10 months ago

Thanks for your detailed reply . why "RoofSurface" is typically red ?

Maybe i can help out here... It has its roots in the histrorical development of the CityGML Standard which was conducted in Germany. It is quite typical for roofs to have a red-ish color. This also facilitated visual debugging a lot ;-)

fuqifacai commented 10 months ago

Finally understood. Thanks guy.