# solvespace-0002 — MOAD-0001 CWE-407 ## Location `src/export.cpp`, `ExportWrlMeshes()` (VRML/WRL export), lines 1225-1240 ## Pattern O(T × C): During VRML mesh export, Solvespace builds a per-shape colour palette by iterating every triangle and scanning a `std::vector` to check whether our triangle's colour is already present: ```cpp std::vector triangle_colour_ids; std::vector colours_present; for(const auto & sp : op.second) { // outer: spans for(const auto & tr : sp) { // inner: triangles O(T) const auto colour_itr = std::find_if( colours_present.begin(), colours_present.end(), [&](const RgbaColor & c) { return c.Equals(tr.meta.color); // O(C) per triangle }); if(colour_itr == colours_present.end()) { colours_present.insert(colours_present.end(), tr.meta.color); triangle_colour_ids.push_back(colours_present.size() - 1); } else { triangle_colour_ids.push_back(colour_itr - colours_present.begin()); } } } ``` Each triangle triggers a full O(C) walk of `colours_present`. Total cost: O(T × C). ## Severity MEDIUM-HIGH. A mechanical assembly export with: - T = 100,000 triangles (typical for a detailed 3D model) - C = 64 distinct colours (per-part colour coding is common) Results in 6,400,000 comparisons vs 100,000 with an `unordered_map`. `RgbaColor` is a packed `uint32_t` (four `uint8_t` fields: red, green, blue, alpha). Our hash map key is `color.ToPackedIntBGRA()` (already defined in our codebase). Fix is a single-line `unordered_map` substitution. 64x overhead at typical export size. ## Fix Replace `std::vector colours_present` with `std::unordered_map colour_to_index`. Key: `tr.meta.color.ToPackedIntBGRA()`. Value: index into our VRML color array. Membership test becomes `colour_to_index.count(key)` (O(1)). The array output for VRML is built in insertion order from our map values. `ToPackedIntBGRA()` is already defined in `dsc.h` line 649 — no new infrastructure needed. ## All 5 MOADs - MOAD-0001: CONFIRMED (this defect) - MOAD-0002: CLEAN (SS/SK globals are intentional single-user desktop CAD singletons; no coupling to new subsystems) - MOAD-0003: CLEAN (single-threaded tool; no request-scoped context leakage) - MOAD-0004: CLEAN (no network features; no credentials handled anywhere) - MOAD-0005: CLEAN (single-process, single-threaded; no concurrent cache access possible)