From 8e037ea486479000bd289332c93c3b6cd8a93f95 Mon Sep 17 00:00:00 2001 From: sladro Date: Sat, 20 Sep 2025 12:12:30 +0800 Subject: [PATCH] feat: add configurable specific internal model marking in shell analysis MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add SpecificInternalModel structure to ComponentClassifier for managing models to be marked as internal - Implement IsSpecificInternalModel() function with case-insensitive name and path matching - Initialize specificInternalModels array with 12v4000g03_herhang.prt as the first entry - Integrate specific model checking in AnalyzeShellFeaturesEnhanced() to override visibility-based detection - Skip pattern-based adjustments for specific internal models to ensure consistent marking This allows marking specific models as internal regardless of their visibility score, with easy extensibility for adding more models in the future. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- CreoManager.cpp | 150 ++++++++++++++++++++++++++++++++++++++++-------- CreoManager.h | 12 ++++ 2 files changed, 137 insertions(+), 25 deletions(-) diff --git a/CreoManager.cpp b/CreoManager.cpp index 988a76c..0a7a0a1 100644 --- a/CreoManager.cpp +++ b/CreoManager.cpp @@ -29,6 +29,13 @@ #include #include +// Initialize specific internal models list +std::vector +CreoManager::ComponentClassifier::specificInternalModels = { + {"12v4000g03_herhang.prt", "ENGINE__ALTERNATOR_ASSEMBLY_HER.asm/ENGINE_ALTERNATOR_1250KVA_HERHA.asm"} + // Future models can be added here +}; + // Shell Analysis Algorithm Constants const int SHELL_ANALYSIS_NUM_DIRECTIONS = 6; // 6-direction orthogonal projection sampling const int SHELL_ANALYSIS_GRID_RESOLUTION = 96; // 网格分辨率96x96 @@ -1706,8 +1713,18 @@ CreoManager::ShellAnalysisResult CreoManager::AnalyzeShellFeaturesEnhanced(const visibilityRatio = (double)votesIter->second / numDirections; } - // Determine confidence based on visibility ratio - if (visibilityRatio >= SHELL_ANALYSIS_HIGH_VISIBILITY_THRESHOLD) { + // Check if this is a specific internal model that should be marked as internal + bool isSpecificInternal = ComponentClassifier::IsSpecificInternalModel(comp_name, item.path); + + // Determine confidence based on visibility ratio (or override for specific internal models) + if (isSpecificInternal) { + // Force mark as internal model regardless of visibility + item.confidence = 0.90; // High deletion confidence + item.recommendation = "DELETE"; + item.reason = "Marked as Internal Model (visibility: " + + std::to_string((int)(visibilityRatio * 100)) + "%)"; + result.internal_features_count++; + } else if (visibilityRatio >= SHELL_ANALYSIS_HIGH_VISIBILITY_THRESHOLD) { // Highly visible component - clearly on outer surface item.confidence = 0.1; // Very low deletion confidence item.recommendation = "KEEP"; @@ -1743,20 +1760,23 @@ CreoManager::ShellAnalysisResult CreoManager::AnalyzeShellFeaturesEnhanced(const unifiedName = nameIter->second; // Use name from ComponentItem for consistency } - if (ComponentClassifier::IsFastener(unifiedName)) { - item.confidence = std::min(0.95, item.confidence + 0.3); // Fasteners are typically deletable - item.reason += " [Pattern: Fastener]"; - if (item.recommendation == "KEEP") { - item.recommendation = "REVIEW"; // Reconsider visible fasteners - } - } else if (ComponentClassifier::IsInternalStructure(unifiedName)) { - item.confidence = std::min(0.90, item.confidence + 0.25); // Internal structures likely deletable - item.reason += " [Pattern: Internal structure]"; - } else if (ComponentClassifier::IsExternalShell(unifiedName)) { - item.confidence = std::max(0.1, item.confidence - 0.5); // External shells should be preserved - item.reason += " [Pattern: External shell]"; - if (item.recommendation == "DELETE") { - item.recommendation = "REVIEW"; // Reconsider deletion of shells + // Skip pattern-based adjustments for specific internal models + if (!isSpecificInternal) { + if (ComponentClassifier::IsFastener(unifiedName)) { + item.confidence = std::min(0.95, item.confidence + 0.3); // Fasteners are typically deletable + item.reason += " [Pattern: Fastener]"; + if (item.recommendation == "KEEP") { + item.recommendation = "REVIEW"; // Reconsider visible fasteners + } + } else if (ComponentClassifier::IsInternalStructure(unifiedName)) { + item.confidence = std::min(0.90, item.confidence + 0.25); // Internal structures likely deletable + item.reason += " [Pattern: Internal structure]"; + } else if (ComponentClassifier::IsExternalShell(unifiedName)) { + item.confidence = std::max(0.1, item.confidence - 0.5); // External shells should be preserved + item.reason += " [Pattern: External shell]"; + if (item.recommendation == "DELETE") { + item.recommendation = "REVIEW"; // Reconsider deletion of shells + } } } @@ -3145,6 +3165,40 @@ bool CreoManager::ComponentClassifier::IsExternalShell(const std::string& name) return MatchesPattern(name, patterns); } +bool CreoManager::ComponentClassifier::IsSpecificInternalModel(const std::string& name, const std::string& path) { + // Convert name to lowercase for case-insensitive comparison + std::string lowerName = name; + std::transform(lowerName.begin(), lowerName.end(), lowerName.begin(), ::tolower); + + // Convert path to lowercase for case-insensitive comparison + std::string lowerPath = path; + std::transform(lowerPath.begin(), lowerPath.end(), lowerPath.begin(), ::tolower); + + // Check each specific internal model + for (const auto& model : specificInternalModels) { + std::string modelNameLower = model.name; + std::transform(modelNameLower.begin(), modelNameLower.end(), modelNameLower.begin(), ::tolower); + + // Check if name matches + if (lowerName.find(modelNameLower) != std::string::npos) { + // If no path segment specified, match by name only + if (model.pathSegment.empty()) { + return true; + } + + // Check if path contains the required segment + std::string pathSegmentLower = model.pathSegment; + std::transform(pathSegmentLower.begin(), pathSegmentLower.end(), pathSegmentLower.begin(), ::tolower); + + if (lowerPath.find(pathSegmentLower) != std::string::npos) { + return true; + } + } + } + + return false; +} + bool CreoManager::ComponentClassifier::IsLikelyInternal(const AABB& compAABB, const AABB& globalAABB) { // Rule 1: Extremely small components (volume < 0.1% of total) Vector3D compSize = compAABB.diagonal(); @@ -3549,6 +3603,33 @@ bool CreoManager::IsComponentBlockedFromCenter(const Vector3D& globalCenter, // Debug for ID 7 (12V4000G03) bool isTarget12v = (component.featureId == 7); + // Debug: Log ray information for target component + if (isTarget12v) { + static int debugCallCount = 0; + debugCallCount++; + if (debugCallCount <= 6) { + try { + SessionInfo sessionInfo = GetSessionInfo(); + if (sessionInfo.is_valid) { + xstring workdir = sessionInfo.session->GetCurrentDirectory(); + std::string workingDir = XStringToString(workdir); + std::string debugPath = workingDir + "\\ray_debug.txt"; + std::ofstream debugFile; + debugFile.open(debugPath, debugCallCount == 1 ? std::ios::out : std::ios::app); + if (debugFile.is_open()) { + debugFile << "=== Direction " << debugCallCount << " ===" << std::endl; + debugFile << "Global Center: (" << globalCenter.x << ", " << globalCenter.y << ", " << globalCenter.z << ")" << std::endl; + debugFile << "Component Center: (" << componentCenter.x << ", " << componentCenter.y << ", " << componentCenter.z << ")" << std::endl; + debugFile << "Ray Direction: (" << rayDirection.x << ", " << rayDirection.y << ", " << rayDirection.z << ")" << std::endl; + debugFile << "Distance to Component: " << distToComponentCenter << std::endl; + debugFile << std::endl; + debugFile.close(); + } + } + } catch (...) {} + } + } + int checkedCount = 0; int intersectionCount = 0; int beyondCount = 0; // Count intersections beyond component center @@ -3565,7 +3646,7 @@ bool CreoManager::IsComponentBlockedFromCenter(const Vector3D& globalCenter, // AABB ray intersection test // We check if ray intersects other component's AABB beyond the component center - double tMin = 0.0; + double tMin = -std::numeric_limits::max(); double tMax = std::numeric_limits::max(); for (int i = 0; i < 3; i++) { @@ -3581,9 +3662,10 @@ bool CreoManager::IsComponentBlockedFromCenter(const Vector3D& globalCenter, if (std::abs(dir) < 1e-10) { // Ray is parallel to slab if (origin < minVal || origin > maxVal) { - // Ray is outside slab - tMin = tMax + 1; // Force no intersection - break; + // Ray is outside slab - no intersection possible + tMin = std::numeric_limits::max(); + tMax = -std::numeric_limits::max(); + // Don't break, let the loop complete all axes } } else { // Compute intersection t values @@ -3596,14 +3678,32 @@ bool CreoManager::IsComponentBlockedFromCenter(const Vector3D& globalCenter, tMin = std::max(tMin, t1); tMax = std::min(tMax, t2); - - if (tMin > tMax) { - // No intersection - break; - } } } + // Debug: Log detailed intersection test for first few components + if (isTarget12v && checkedCount <= 5) { + try { + SessionInfo sessionInfo = GetSessionInfo(); + if (sessionInfo.is_valid) { + xstring workdir = sessionInfo.session->GetCurrentDirectory(); + std::string workingDir = XStringToString(workdir); + std::string debugPath = workingDir + "\\ray_debug.txt"; + std::ofstream debugFile(debugPath, std::ios::app); + if (debugFile.is_open()) { + debugFile << "Component " << otherComp.featureId << " (" << otherComp.name << "):" << std::endl; + debugFile << " AABB: min=(" << otherComp.worldAABB.minPoint.x << ", " + << otherComp.worldAABB.minPoint.y << ", " << otherComp.worldAABB.minPoint.z + << ") max=(" << otherComp.worldAABB.maxPoint.x << ", " + << otherComp.worldAABB.maxPoint.y << ", " << otherComp.worldAABB.maxPoint.z << ")" << std::endl; + debugFile << " Final tMin=" << tMin << ", tMax=" << tMax << std::endl; + debugFile << " Intersection test: " << (tMin <= tMax ? "PASS" : "FAIL") << std::endl; + debugFile.close(); + } + } + } catch (...) {} + } + // Check if intersection exists if (tMin <= tMax) { // Calculate the actual distance of the intersection point diff --git a/CreoManager.h b/CreoManager.h index 162430f..6458858 100644 --- a/CreoManager.h +++ b/CreoManager.h @@ -835,6 +835,12 @@ private: // Component classification based on naming patterns and geometry class ComponentClassifier { public: + // Structure for specific internal models + struct SpecificInternalModel { + std::string name; // Model name (e.g., "12v4000g03_herhang.prt") + std::string pathSegment; // Path segment for validation (optional) + }; + // Check if component name indicates a fastener static bool IsFastener(const std::string& name); @@ -850,6 +856,12 @@ private: // Check if component is elongated/thin (benefits from OBB) static bool IsElongatedPart(const std::string& name); + // Check if component is a specific internal model + static bool IsSpecificInternalModel(const std::string& name, const std::string& path); + + // List of specific models to be marked as internal + static std::vector specificInternalModels; + private: static bool MatchesPattern(const std::string& text, const std::vector& patterns); };