feat: add configurable specific internal model marking in shell analysis

- 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 <noreply@anthropic.com>
This commit is contained in:
sladro 2025-09-20 12:12:30 +08:00
parent 6fd84e4ca3
commit 8e037ea486
2 changed files with 137 additions and 25 deletions

View File

@ -29,6 +29,13 @@
#include <windows.h>
#include <vector>
// Initialize specific internal models list
std::vector<CreoManager::ComponentClassifier::SpecificInternalModel>
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<double>::max();
double tMax = std::numeric_limits<double>::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<double>::max();
tMax = -std::numeric_limits<double>::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

View File

@ -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<SpecificInternalModel> specificInternalModels;
private:
static bool MatchesPattern(const std::string& text, const std::vector<std::string>& patterns);
};