Polyscope
repository·master·Indexed 24 days ago
https://github.com/nmwsharp/polyscopeA lightweight C++/Python viewer and user interface for 3D data such as meshes and point clouds. It provides an interactive 3D GUI to visualize geometric structures and associated scalar or vector quantities with minimal code.
What's inside polyscope
- IconFontCppHeaders provides language-specific files (C, C++, C#, Python, Rust, and Go) for using popular icon fonts in your applications. It includes pre-generated definitions for icon code points and font loading metadata for various icon sets like Font Awesome, Google Material Design, and Lucide.
Performance characteristics of args
masterTheargslibrary is designed for high performance. Benchmarks indicate it is significantly faster than common alternatives likeTCLAPandboost::program_optionswhen parsing and retrieving arguments.Core design principles of JSON for Modern C++
masterThe library is designed around three primary goals:
- Intuitive syntax: Uses C++ operator overloading to make JSON feel like a first-class data type, similar to how it feels in languages like Python.
- Trivial integration: Consists of a single header file (
json.hpp) with no dependencies or complex build requirements. - Serious testing: Heavily unit-tested with 100% coverage and verified for memory leaks using Valgrind.
Note on Performance and Memory:
- Memory: Each JSON object has an overhead of one pointer and one enumeration element (1 byte). Default types used are
std::stringfor strings,int64_t/uint64_t/doublefor numbers,std::mapfor objects,std::vectorfor arrays, andboolfor Booleans. You can customize this by templating thebasic_jsonclass. - Speed: While there are faster libraries available, this library prioritizes development speed and ease of integration via its single-header design.
How Polyscope structures and quantities work
masterPolyscope operates on a paradigm of structures and quantities:
- Structures: Geometric objects in the 3D scene, such as a surface mesh or a point cloud.
- Quantities: Data associated with a structure, such as a scalar function (e.g., temperature, curvature) or a vector field (e.g., normals, velocity).
When you register a structure and its quantities, Polyscope automatically handles the visualization boilerplate, including toggling visibility, color-mapping data, adjusting color maps, and enabling 'picking' to query numerical values by clicking in the 3D scene.
Handle unchecked access and assertions in JSON for Modern C++
masterThe library uses debug assertions to catch errors. You can disable these by defining the
NDEBUGpreprocessor macro.Warning on
operator[]: Forconstobjects,operator[]implements unchecked access. If the requested key does not exist, the behavior is undefined (similar to dereferencing a null pointer) and will trigger an assertion failure if assertions are enabled.Best Practice: If you are unsure whether a key exists in a JSON object, use the checked access method
at()instead ofoperator[]to avoid undefined behavior.Use argument groups for validation
masterArguments can be organized into
args::Groupobjects to enforce validation logic. Groups can be nested to create complex validation hierarchies.Supported validators for
args::Groupinclude:args::Group::Validators::Xor: Exactly one of the flags in the group must be present.args::Group::Validators::AllOrNone: Either all flags in the group must be present, or none at all.args::Group::Validators::AtLeastOne: At least one flag in the group must be present.
When a
ValidationErroroccurs, you can useparser.Help(std::cerr)to print a formatted help menu that clearly shows the group nesting and validation requirements.Convert third-party types using adl_serializer
masterIf you cannot modify the namespace of a type (e.g.,
boost::optionalorstd::filesystem::path), you can specializenlohmann::adl_serializerwithin thenlohmannnamespace.namespace nlohmann { template <typename T> struct adl_serializer<boost::optional<T>> { static void to_json(json& j, const boost::optional<T>& opt) { if (opt == boost::none) { j = nullptr; } else { j = *opt; } } static void from_json(const json& j, boost::optional<T>& opt) { if (j.is_null()) { opt = boost::none; } else { opt = j.get<T>(); } } }; }Use argument groups and validation
masterYou can group arguments together and apply validation logic (e.g.,
Xor,And,Or). If a group's validation fails, the parser throws anargs::ValidationError.Because group validation can involve complex logic (like
(A && B) || (C && (D XOR E))), the library cannot automatically tell you which specific part of the logic failed. To provide helpful error messages to users, you must catchargs::ValidationErrorand manually check your group conditions to print custom messages.#include <iostream> #include <args.hxx> int main(int argc, char **argv) { args::ArgumentParser parser("This is a test program.", "This goes after the options."); // Create an exclusive group (XOR) args::Group group(parser, "This group is all exclusive:", args::Group::Validators::Xor); args::Flag foo(group, "foo", "The foo flag", {'f', "foo"}); args::Flag bar(group, "bar", "The bar flag", {'b'}); args::Flag baz(group, "baz", "The baz flag", {"baz"}); try { parser.ParseCLI(argc, argv); } catch (args::Help) { std::cout << parser; return 0; } catch (args::ParseError e) { std::cerr << e.what() << std::endl; std::cerr << parser; return 1; } catch (args::ValidationError e) { // Custom error handling for failed group validation std::cerr << e.what() << std::endl; std::cerr << parser; return 1; } if (foo) { std::cout << "foo" << std::endl; } if (bar) { std::cout << "bar" << std::endl; } if (baz) { std::cout << "baz" << std::endl; } return 0; }Preserve insertion order of object elements
masterBy default, the library does not preserve the insertion order of object elements, as per the JSON standard. If your application requires preserving the order in which elements were added, you must specialize the object type using an ordered container such astsl::ordered_mapornlohmann::fifo_map.Configure Unicode and String handling
masterThe library follows RFC 7159 for Unicode support:
- Supported Encoding: Only UTF-8 encoded input is supported. Other encodings (Latin-1, UTF-16, UTF-32) will result in parse errors.
- String Storage: Strings are stored as UTF-8.
- String Length: When using the default
std::stringtype, functions like.size()or.length()return the number of bytes, not the number of characters or glyphs.
How IconFontCppHeaders language files work
masterEach generated language file for a specific font contains:
- Icon Definitions: Each icon code point is defined using an
ICON_*naming convention. - Font Loading Metadata:
min: The minimum code point (excluding ASCII characters).max: The maximum code point.max 16 bit: The maximum 16-bit code point, specifically useful for libraries that only support 16-bit code points, such as Dear ImGui.
- Icon Definitions: Each icon code point is defined using an
Generate Font Awesome Pro language files
masterFont Awesome Pro is a commercial product. To generate language files for version 5 (or similar processes for 6+), follow these steps:
- Download the Font Awesome Pro 5 Web package from fontawesome.com.
- Place the
icons.ymlfile (found in the package'smetadata/directory) in the same directory as theGenerateIconFontCppHeaders.pyscript. - Run the
GenerateIconFontCppHeaders.pyscript. - Use the generated files with the corresponding
.ttffiles from the package (e.g.,fa-brands-400.ttf,fa-light-300.ttf,fa-regular-400.ttf,fa-solid-900.ttf).