first commit

This commit is contained in:
2026-07-17 17:45:56 +08:00
commit 04c487823b
5873 changed files with 12227228 additions and 0 deletions
@@ -0,0 +1,826 @@
using SolidWorks.Interop.sldworks;
static class AssemblyModelProcessing
{
public static List<ComponentHighlightImageRequest> BuildComponentHighlightImageRequests(SectionBrepReport report)
{
var componentsById = report.AssemblyComponents
.ToDictionary(component => component.Id, StringComparer.OrdinalIgnoreCase);
var designTargets = report.PartImagePlan
.Where(item => !string.IsNullOrWhiteSpace(item.ComponentId))
.Where(item => IsTopLevelAssemblyComponent(item.InstanceName))
.GroupBy(item => item.ComponentId, StringComparer.OrdinalIgnoreCase)
.Select(group => group.First())
.Select(item => new ComponentHighlightImageRequest
{
PlanId = item.AssemblyContextImagePlanId,
ComponentId = item.ComponentId,
InstanceName = item.InstanceName,
DisplayName = item.DisplayName,
ComponentPath = item.ComponentPath,
Views = ["best_oblique"],
PreferredDirectionMm = componentsById.TryGetValue(item.ComponentId, out var component)
? ChooseComponentHighlightDirection(component, report.AssemblyComponents)
: [],
ShowComponents =
[
BuildComponentImageRef(
componentsById.GetValueOrDefault(item.ComponentId),
item.InstanceName,
item.DisplayName,
item.ComponentPath)
]
})
.ToList();
return designTargets;
}
static bool IsTopLevelAssemblyComponent(string instanceName)
{
return !string.IsNullOrWhiteSpace(instanceName) &&
!instanceName.Contains("/", StringComparison.Ordinal) &&
!instanceName.Contains("\\", StringComparison.Ordinal);
}
public static List<ComponentContextImageRequest> BuildComponentContextImageRequests(SectionBrepReport report)
{
var componentsById = report.AssemblyComponents
.ToDictionary(component => component.Id, StringComparer.OrdinalIgnoreCase);
return report.ComponentContextImagePlan
.Where(item => ShouldExportComponentContext(item, report.ExternalInterfaceRoots))
.Where(item => item.ShowComponents.Count > 0)
.Select(item =>
{
var showComponents = item.ShowComponents
.Select(component => BuildComponentImageRef(component, componentsById))
.ToList();
var preserveComponents = item.BoundaryComponents
.Select(component => BuildComponentImageRef(component, componentsById))
.ToList();
var protectedIds = showComponents
.Concat(preserveComponents)
.Select(component => component.ComponentId)
.ToHashSet(StringComparer.OrdinalIgnoreCase);
var hideComponents = item.MemberOcclusionAnalyses
.SelectMany(analysis => analysis.Directions)
.Where(direction => direction.Occluded)
.SelectMany(direction => direction.FirstHitComponents)
.Where(blocker => !protectedIds.Contains(blocker.ComponentId))
.DistinctBy(blocker => $"{blocker.InstanceName}::{blocker.ComponentPath}", StringComparer.OrdinalIgnoreCase)
.Select(blocker => new ComponentImageRef
{
ComponentId = blocker.ComponentId,
InstanceName = blocker.InstanceName,
DisplayName = blocker.DisplayName,
ComponentPath = blocker.ComponentPath,
BBoxMm = componentsById.TryGetValue(blocker.ComponentId, out var blockerSummary)
? blockerSummary.BBoxMm
: []
})
.ToList();
return new ComponentContextImageRequest
{
PlanId = item.Id,
GroupId = item.GroupId,
TargetComponentId = item.TargetComponentId,
TargetInstanceName = item.TargetInstanceName,
TargetDisplayName = item.TargetDisplayName,
TargetComponentPath = item.TargetComponentPath,
Views = ["best_oblique"],
PreferredDirectionMm = componentsById.TryGetValue(item.TargetComponentId, out var component)
? ChooseComponentHighlightDirection(component, report.AssemblyComponents)
: [],
ShowComponents = showComponents,
PreserveComponents = preserveComponents,
HideComponents = hideComponents
};
})
.ToList();
}
static bool ShouldExportComponentContext(ComponentContextImagePlanItem item, IReadOnlyList<string> externalInterfaceRoots)
{
if (externalInterfaceRoots.Count == 0)
return true;
// Purchased-component hints are semantic hints, not a switch to disable
// all component context images. But ordinary component-context images
// should not expand the inside of a user-specified purchased module.
// Those internal contacts are represented by physical-interface images
// when they cross the purchased-module boundary.
return !IsExternalInterfaceRootDescendant(item.TargetInstanceName, item.TargetComponentPath, externalInterfaceRoots);
}
static bool IsExternalInterfaceRootDescendant(string instanceName, string path, IReadOnlyList<string> roots)
{
var name = NormalizeRootMatchText(instanceName);
var strippedName = NormalizeRootMatchText(StripInstanceSuffix(instanceName));
var file = NormalizeRootMatchText(Path.GetFileNameWithoutExtension(path));
foreach (var root in roots.Select(NormalizeRootMatchText).Where(root => root.Length > 0))
{
var exactRoot =
name.Equals(root, StringComparison.OrdinalIgnoreCase) ||
strippedName.Equals(root, StringComparison.OrdinalIgnoreCase) ||
file.Equals(root, StringComparison.OrdinalIgnoreCase);
if (exactRoot)
return false;
if (name.StartsWith(root + "-", StringComparison.OrdinalIgnoreCase) ||
name.StartsWith(root + "/", StringComparison.OrdinalIgnoreCase) ||
strippedName.StartsWith(root + "-", StringComparison.OrdinalIgnoreCase) ||
strippedName.StartsWith(root + "/", StringComparison.OrdinalIgnoreCase))
{
return true;
}
}
return false;
}
public static List<InterfaceHighlightImageRequest> BuildInterfaceHighlightImageRequests(
SectionBrepReport report,
int maxRequests = 30,
bool compactViews = false)
{
if (!report.DocumentKind.Equals("assembly", StringComparison.OrdinalIgnoreCase) ||
report.AssemblyFaceContacts.Count == 0)
{
return [];
}
var components = report.AssemblyComponents;
var groups = BuildPhysicalInterfaceGroups(report.AssemblyFaceContacts, report.ExternalInterfaceRoots)
.OrderByDescending(group => group.AnalysisPriority)
.ThenByDescending(group => group.Contacts.Max(contact => contact.Confidence))
.Take(Math.Max(0, maxRequests))
.ToList();
var requests = new List<InterfaceHighlightImageRequest>();
foreach (var group in groups)
{
var contact = group.Contacts[0];
var componentA = FindComponentSummary(components, contact.ComponentA, contact.ComponentPathA);
var componentB = FindComponentSummary(components, contact.ComponentB, contact.ComponentPathB);
var refA = BuildComponentImageRef(componentA, contact.ComponentA, contact.ComponentDisplayNameA, contact.ComponentPathA);
var refB = BuildComponentImageRef(componentB, contact.ComponentB, contact.ComponentDisplayNameB, contact.ComponentPathB);
var axis = RepresentativeAxis(group.Contacts);
var normal = RepresentativeNormal(group.Contacts);
var interfaceBox = UnionBoxes(group.Contacts.SelectMany(item => new[] { item.BBoxA, item.BBoxB }));
var isCylindrical = contact.ContactKind.Contains("cylindrical", StringComparison.OrdinalIgnoreCase);
var verificationStatuses = group.Contacts
.Select(item => item.VerificationStatus)
.Where(status => !string.IsNullOrWhiteSpace(status))
.Distinct(StringComparer.OrdinalIgnoreCase)
.ToList();
requests.Add(new InterfaceHighlightImageRequest
{
PlanId = $"physical_interface_highlight_{SanitizeId(group.Id)}",
InterfaceId = group.Id,
ContactKind = contact.ContactKind,
MateRole = contact.MateRole,
ComponentA = refA,
ComponentB = refB,
FaceARef = group.FaceARefs[0],
FaceBRef = group.FaceBRefs[0],
FaceAIndex = group.FaceAIndices[0],
FaceBIndex = group.FaceBIndices[0],
FaceARefs = group.FaceARefs,
FaceBRefs = group.FaceBRefs,
FaceAIndices = group.FaceAIndices,
FaceBIndices = group.FaceBIndices,
RuntimeFaces = group.RuntimeFaces,
SourceContactIds = group.Contacts.Select(item => item.Id).Distinct(StringComparer.OrdinalIgnoreCase).ToList(),
Views = compactViews
? ["assembled_oblique"]
: isCylindrical
? ["assembled_oblique", "axis_end", "axis_side"]
: ["assembled_oblique", "normal_view"],
PreferredDirectionMm = ChooseInterfaceHighlightDirection(contact, components),
InterfaceAxisMm = axis,
InterfaceNormalMm = normal,
InterfaceCenterMm = AverageCenters(group.Contacts),
InterfaceBBoxMm = interfaceBox,
AnalysisPriority = group.AnalysisPriority,
ConfidenceTier = group.ConfidenceTier,
EvidencePurpose = "physical_interface_function_analysis",
TrimmedPatchVerified = group.Contacts.All(item => item.TrimmedPatchVerified),
VerificationStatus = verificationStatuses.Count == 1
? verificationStatuses[0]
: "mixed_verified_interface",
VerificationMethods = group.Contacts
.Select(item => item.VerificationMethod)
.Where(method => !string.IsNullOrWhiteSpace(method))
.Distinct(StringComparer.OrdinalIgnoreCase)
.ToList(),
VerificationSampleHits = group.Contacts.Sum(item => item.VerificationSampleHits),
VerificationMinDistanceMm = group.Contacts.Min(item => item.VerificationMinDistanceMm),
DisplayMode = "actual_assembly_position_with_native_selected_interface_faces",
ActualAssemblyPosition = true,
NotActualClearance = true,
ShowComponents = [refA, refB],
PreserveComponents = []
});
}
return requests;
}
static List<PhysicalInterfaceGroup> BuildPhysicalInterfaceGroups(
IReadOnlyList<AssemblyFaceContactEvidence> contacts,
IReadOnlyList<string> externalInterfaceRoots)
{
var planarProfilePairKeys = BuildPlanarProfilePairKeys(contacts);
var groups = new List<PhysicalInterfaceGroup>();
foreach (var contact in contacts
.Where(contact => contact.FaceA > 0 && contact.FaceB > 0)
.Where(IsConfirmedInterfaceContact)
.Where(contact => IsExternalPurchasedInterfaceContact(contact, externalInterfaceRoots))
.Where(contact => ShouldExportFitLikeInterface(contact, planarProfilePairKeys)))
{
var key = PhysicalInterfaceKey(contact);
var group = groups.FirstOrDefault(candidate =>
candidate.BaseKey.Equals(key, StringComparison.OrdinalIgnoreCase) &&
candidate.Contacts.Any(existing => SamePhysicalInterfaceSegment(existing, contact)));
if (group == null)
{
group = new PhysicalInterfaceGroup
{
BaseKey = key,
Id = $"physical_interface_{groups.Count + 1:000}_{ShortInterfaceToken(contact.ComponentFileNameA, contact.ComponentA)}__{ShortInterfaceToken(contact.ComponentFileNameB, contact.ComponentB)}"
};
groups.Add(group);
}
// Keep every group oriented like its first contact so face-side identity remains stable.
var first = group.Contacts.FirstOrDefault();
var sameOrientation = first == null || SameComponentIdentity(first.ComponentA, first.ComponentPathA, contact.ComponentA, contact.ComponentPathA);
group.Contacts.Add(contact);
if (sameOrientation)
{
AddFace(group.FaceARefs, group.FaceAIndices, contact.ComponentA, contact.FaceA);
AddFace(group.FaceBRefs, group.FaceBIndices, contact.ComponentB, contact.FaceB);
AddRuntimeFace(group.RuntimeFaces, contact.RuntimeFaceA);
AddRuntimeFace(group.RuntimeFaces, contact.RuntimeFaceB);
}
else
{
AddFace(group.FaceARefs, group.FaceAIndices, contact.ComponentB, contact.FaceB);
AddFace(group.FaceBRefs, group.FaceBIndices, contact.ComponentA, contact.FaceA);
AddRuntimeFace(group.RuntimeFaces, contact.RuntimeFaceB);
AddRuntimeFace(group.RuntimeFaces, contact.RuntimeFaceA);
}
}
foreach (var group in groups)
{
var text = string.Join(" ", group.Contacts.Select(contact =>
$"{contact.ContactKind} {contact.MateRole} {contact.ComponentCategoryA} {contact.ComponentCategoryB} {contact.ComponentDisplayNameA} {contact.ComponentDisplayNameB}"));
var containsKnownStandardPart = ContainsAny(text, "bearing", "轴承", "bolt", "screw", "nut", "pin", "key", "螺", "销", "键");
var geometryConfidence = group.Contacts.Max(contact => contact.Confidence);
group.AnalysisPriority = (containsKnownStandardPart ? 100 : 0)
+ (group.Contacts.Any(contact => contact.ContactKind.Contains("cylindrical", StringComparison.OrdinalIgnoreCase)) ? 30 : 10)
+ geometryConfidence * 20
+ Math.Min(10, group.Contacts.Count);
group.ConfidenceTier = containsKnownStandardPart && geometryConfidence >= 0.75
? "anchor"
: geometryConfidence >= 0.75 ? "high" : geometryConfidence >= 0.45 ? "medium" : "low";
}
return groups;
}
// Physical-interface images are boundary evidence only:
// exactly one side must be a purchased/standard component and the other
// side must be a top-level external non-purchased component. Internal
// purchased-to-purchased or purchased-to-internal contacts remain in the
// B-rep contact report but are not exported as physical-interface images.
static bool IsExternalPurchasedInterfaceContact(AssemblyFaceContactEvidence contact, IReadOnlyList<string> externalInterfaceRoots)
{
if (externalInterfaceRoots.Count > 0)
{
var aIsRoot = IsExternalInterfaceRootMember(contact.ComponentA, contact.ComponentPathA, externalInterfaceRoots);
var bIsRoot = IsExternalInterfaceRootMember(contact.ComponentB, contact.ComponentPathB, externalInterfaceRoots);
return aIsRoot ^ bIsRoot;
}
var purchasedA = IsPurchasedInterfaceComponent(contact.ComponentCategoryA, contact.ComponentA, contact.ComponentPathA);
var purchasedB = IsPurchasedInterfaceComponent(contact.ComponentCategoryB, contact.ComponentB, contact.ComponentPathB);
if (purchasedA == purchasedB)
return false;
var externalOther = purchasedA
? contact.ComponentB
: contact.ComponentA;
var otherCategory = purchasedA
? contact.ComponentCategoryB
: contact.ComponentCategoryA;
var otherPath = purchasedA
? contact.ComponentPathB
: contact.ComponentPathA;
return !IsPurchasedInterfaceComponent(otherCategory, externalOther, otherPath) &&
IsTopLevelAssemblyComponent(externalOther);
}
static bool IsExternalInterfaceRootMember(string instanceName, string path, IReadOnlyList<string> roots)
{
var name = NormalizeRootMatchText(instanceName);
var strippedName = NormalizeRootMatchText(StripInstanceSuffix(instanceName));
var file = NormalizeRootMatchText(Path.GetFileNameWithoutExtension(path));
foreach (var root in roots.Select(NormalizeRootMatchText).Where(root => root.Length > 0))
{
if (name.Equals(root, StringComparison.OrdinalIgnoreCase) ||
strippedName.Equals(root, StringComparison.OrdinalIgnoreCase) ||
file.Equals(root, StringComparison.OrdinalIgnoreCase) ||
name.StartsWith(root + "-", StringComparison.OrdinalIgnoreCase) ||
name.StartsWith(root + "/", StringComparison.OrdinalIgnoreCase) ||
strippedName.StartsWith(root + "-", StringComparison.OrdinalIgnoreCase) ||
strippedName.StartsWith(root + "/", StringComparison.OrdinalIgnoreCase))
{
return true;
}
}
return false;
}
static string StripInstanceSuffix(string value) =>
System.Text.RegularExpressions.Regex.Replace(value ?? "", @"-\d+(?=/|$)", "");
static string NormalizeRootMatchText(string value) =>
(value ?? "").Trim().Replace('\\', '/');
static bool IsPurchasedInterfaceComponent(string category, string instanceName, string path)
{
if (category.Equals("bearing", StringComparison.OrdinalIgnoreCase) ||
category.Equals("purchased_motor", StringComparison.OrdinalIgnoreCase) ||
category.Equals("purchased_reducer", StringComparison.OrdinalIgnoreCase) ||
category.Equals("purchased_motor_reducer_assembly", StringComparison.OrdinalIgnoreCase) ||
category.Equals("user_purchased_component", StringComparison.OrdinalIgnoreCase))
{
return true;
}
var text = $"{category} {instanceName} {path}".ToLowerInvariant();
if (LooksLikeDesignedConnectorOrHousing(text))
return false;
return ContainsAny(
text,
"gb", "t70", "t276", "bearing", "bolt", "screw",
"csg", "shg", "mhc", "ec60", "purchased_motor", "purchased_reducer", "gearbox",
"motor", "servo", "reducer", "gear motor",
"\u8f74\u627f", "\u87ba\u9489", "\u87ba\u6813", "\u7535\u673a", "\u9a6c\u8fbe", "\u4f3a\u670d", "\u51cf\u901f\u5668", "\u51cf\u901f\u673a");
}
static bool LooksLikeDesignedConnectorOrHousing(string text)
{
return ContainsAny(
text,
"\u8fde\u63a5\u4ef6", "\u6cd5\u5170", "\u5916\u58f3", "\u58f3\u4f53", "\u652f\u67b6", "\u5ea7",
"connector", "adapter", "bracket", "flange", "housing", "mount");
}
static bool IsConfirmedInterfaceContact(AssemblyFaceContactEvidence contact) =>
contact.TrimmedPatchVerified &&
(contact.VerificationStatus.Equals("trimmed_interface_confirmed", StringComparison.OrdinalIgnoreCase) ||
contact.VerificationStatus.Equals("trimmed_cylindrical_domain_confirmed", StringComparison.OrdinalIgnoreCase) ||
contact.VerificationStatus.Equals("analytic_cylindrical_domain_confirmed", StringComparison.OrdinalIgnoreCase));
static string ShortInterfaceToken(string fileName, string componentName)
{
var token = SanitizeId(FirstNonEmpty(Path.GetFileNameWithoutExtension(fileName), componentName, "component"));
return token.Length <= 24 ? token : token[..24];
}
static bool SamePhysicalInterfaceSegment(AssemblyFaceContactEvidence a, AssemblyFaceContactEvidence b)
{
if (!a.ContactKind.Contains("cylindrical", StringComparison.OrdinalIgnoreCase) ||
!b.ContactKind.Contains("cylindrical", StringComparison.OrdinalIgnoreCase))
{
return true;
}
var axis = a.AxisA.Length >= 3 ? Vec.Normalize(a.AxisA) : Vec.Normalize(a.AxisB);
if (axis.Length < 3)
return true;
var intervalA = ContactAxialInterval(a, axis);
var intervalB = ContactAxialInterval(b, axis);
if (!intervalA.HasValue || !intervalB.HasValue)
return true;
var radius = new[] { a.RadiusAmm, a.RadiusBmm, b.RadiusAmm, b.RadiusBmm }.Where(value => value > 0).DefaultIfEmpty(1).Average();
var allowedGap = Math.Max(0.5, radius * 0.03);
return intervalA.Value.Min <= intervalB.Value.Max + allowedGap &&
intervalB.Value.Min <= intervalA.Value.Max + allowedGap;
}
static (double Min, double Max)? ContactAxialInterval(AssemblyFaceContactEvidence contact, double[] axis)
{
var boxes = new[] { contact.BBoxA, contact.BBoxB }.Where(box => box.Length >= 6).ToList();
if (boxes.Count == 0)
return null;
var values = boxes.SelectMany(BoxCorners).Select(point => Vec.Dot(point, axis)).ToList();
return (values.Min(), values.Max());
}
static string PhysicalInterfaceKey(AssemblyFaceContactEvidence contact)
{
var pair = ComponentPairKey(
FirstNonEmpty(contact.ComponentPathA, contact.ComponentA),
FirstNonEmpty(contact.ComponentPathB, contact.ComponentB));
if (!contact.ContactKind.Contains("cylindrical", StringComparison.OrdinalIgnoreCase))
return $"{pair}|planar_profile";
var axis = contact.AxisA.Length >= 3 ? Vec.Normalize(contact.AxisA) : Vec.Normalize(contact.AxisB);
axis = CanonicalDirection(axis);
var radius = new[] { contact.RadiusAmm, contact.RadiusBmm }.Where(value => value > 0).DefaultIfEmpty(0).Average();
var center = AverageVectors(contact.CenterA, contact.CenterB);
var axisOffset = axis.Length >= 3 && center.Length >= 3
? Vec.Sub(center, Vec.Mul(axis, Vec.Dot(center, axis)))
: [];
return string.Join("|", new[]
{
pair,
"cylindrical",
VectorKey(axis, 0.02),
VectorKey(axisOffset, Math.Max(0.1, radius * 0.01)),
$"r{Math.Round(radius, 2):0.00}"
});
}
static void AddFace(List<string> refs, List<int> indices, string component, int faceIndex)
{
if (faceIndex <= 0)
return;
var faceRef = $"{component}:face#{faceIndex}";
if (refs.Contains(faceRef, StringComparer.OrdinalIgnoreCase))
return;
refs.Add(faceRef);
indices.Add(faceIndex);
}
static void AddRuntimeFace(List<Face2> faces, Face2? face)
{
if (face != null && !faces.Any(existing => ReferenceEquals(existing, face)))
faces.Add(face);
}
static bool SameComponentIdentity(string nameA, string pathA, string nameB, string pathB) =>
!string.IsNullOrWhiteSpace(pathA) && !string.IsNullOrWhiteSpace(pathB)
? pathA.Equals(pathB, StringComparison.OrdinalIgnoreCase)
: nameA.Equals(nameB, StringComparison.OrdinalIgnoreCase);
static double[] RepresentativeAxis(IReadOnlyList<AssemblyFaceContactEvidence> contacts) =>
contacts.Select(contact => contact.AxisA.Length >= 3 ? contact.AxisA : contact.AxisB)
.FirstOrDefault(axis => axis.Length >= 3) is { Length: >= 3 } axis ? CanonicalDirection(Vec.Normalize(axis)) : [];
static double[] RepresentativeNormal(IReadOnlyList<AssemblyFaceContactEvidence> contacts) =>
contacts.Select(contact => contact.NormalA.Length >= 3 ? contact.NormalA : contact.NormalB)
.FirstOrDefault(normal => normal.Length >= 3) is { Length: >= 3 } normal ? CanonicalDirection(Vec.Normalize(normal)) : [];
static double[] AverageCenters(IReadOnlyList<AssemblyFaceContactEvidence> contacts)
{
var centers = contacts.Select(contact => AverageVectors(contact.CenterA, contact.CenterB)).Where(center => center.Length >= 3).ToList();
return centers.Count == 0
? []
: [centers.Average(center => center[0]), centers.Average(center => center[1]), centers.Average(center => center[2])];
}
static double[] CanonicalDirection(double[] direction)
{
if (direction.Length < 3)
return [];
var first = direction.FirstOrDefault(value => Math.Abs(value) > 1e-6);
return first < 0 ? Vec.Mul(direction, -1) : direction;
}
static string VectorKey(double[] vector, double tolerance)
{
if (vector.Length < 3)
return "none";
tolerance = Math.Max(tolerance, 1e-6);
return string.Join(",", vector.Take(3).Select(value => Math.Round(value / tolerance).ToString(System.Globalization.CultureInfo.InvariantCulture)));
}
static HashSet<string> BuildPlanarProfilePairKeys(IReadOnlyList<AssemblyFaceContactEvidence> contacts)
{
var result = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
foreach (var group in contacts
.Where(contact => contact.ContactKind.Equals("planar_face_contact_candidate", StringComparison.OrdinalIgnoreCase))
.GroupBy(contact => ComponentPairKey(contact.ComponentA, contact.ComponentB), StringComparer.OrdinalIgnoreCase))
{
var items = group.ToList();
if (items.Count < 2)
continue;
var normalFamilies = new List<double[]>();
foreach (var contact in items)
{
var normal = contact.NormalA.Length >= 3 ? Vec.Normalize(contact.NormalA) : [];
if (normal.Length < 3)
continue;
var existing = normalFamilies.Any(family => Math.Abs(Vec.Dot(family, normal)) >= 0.92);
if (!existing)
normalFamilies.Add(normal);
}
// Multi-direction planar contacts indicate prismatic/profile fits such as square shafts,
// rectangular bosses, slots, or keyed interfaces. Same-direction multi-face groups are
// kept as weaker profile candidates; ordinary single flat mounting contacts are excluded.
if (normalFamilies.Count >= 2 || items.Count >= 3)
result.Add(group.Key);
}
return result;
}
static bool ShouldExportFitLikeInterface(AssemblyFaceContactEvidence contact, IReadOnlySet<string> planarProfilePairKeys)
{
if (contact.ContactKind.Equals("cylindrical_coaxial_fit_candidate", StringComparison.OrdinalIgnoreCase))
return true;
if (!contact.ContactKind.Equals("planar_face_contact_candidate", StringComparison.OrdinalIgnoreCase))
return false;
return planarProfilePairKeys.Contains(ComponentPairKey(contact.ComponentA, contact.ComponentB));
}
static ComponentImageRef BuildComponentImageRef(
ComponentContextMember component,
IReadOnlyDictionary<string, AssemblyComponentSummary> componentsById)
{
return new ComponentImageRef
{
ComponentId = component.ComponentId,
InstanceName = component.InstanceName,
DisplayName = component.DisplayName,
ComponentPath = component.ComponentPath,
BBoxMm = componentsById.TryGetValue(component.ComponentId, out var summary)
? summary.BBoxMm
: []
};
}
static ComponentImageRef BuildComponentImageRef(
AssemblyComponentSummary? component,
string instanceName,
string displayName,
string componentPath)
{
return new ComponentImageRef
{
ComponentId = component?.Id ?? SanitizeId(FirstNonEmpty(instanceName, displayName, Path.GetFileNameWithoutExtension(componentPath), "component")),
InstanceName = component?.InstanceName ?? instanceName,
DisplayName = component?.DisplayName ?? displayName,
ComponentPath = component?.Path ?? componentPath,
BBoxMm = component?.BBoxMm ?? []
};
}
static AssemblyComponentSummary? FindComponentSummary(
IReadOnlyList<AssemblyComponentSummary> components,
string instanceName,
string componentPath)
{
return components.FirstOrDefault(component =>
!string.IsNullOrWhiteSpace(instanceName) &&
component.InstanceName.Equals(instanceName, StringComparison.OrdinalIgnoreCase) &&
(string.IsNullOrWhiteSpace(componentPath) ||
string.IsNullOrWhiteSpace(component.Path) ||
component.Path.Equals(componentPath, StringComparison.OrdinalIgnoreCase)))
?? components.FirstOrDefault(component =>
!string.IsNullOrWhiteSpace(componentPath) &&
!string.IsNullOrWhiteSpace(component.Path) &&
component.Path.Equals(componentPath, StringComparison.OrdinalIgnoreCase));
}
static double ContactPriority(AssemblyFaceContactEvidence contact)
{
var text = $"{contact.ContactKind} {contact.MateRole} {contact.FaceRoleA} {contact.FaceRoleB}".ToLowerInvariant();
if (text.Contains("cylindrical") || text.Contains("bearing") || text.Contains("hinge") || text.Contains("fit"))
return 3.0;
if (text.Contains("planar") || text.Contains("profile") || text.Contains("slot") || text.Contains("key"))
return 1.0;
return 0.0;
}
static string ComponentPairKey(string a, string b) =>
string.Compare(a, b, StringComparison.OrdinalIgnoreCase) <= 0
? $"{a}||{b}"
: $"{b}||{a}";
static double[] ChooseInterfaceHighlightDirection(
AssemblyFaceContactEvidence contact,
IReadOnlyList<AssemblyComponentSummary> components)
{
var center = AverageVectors(contact.CenterA, contact.CenterB);
var assemblyBox = UnionBoxes(components.Select(component => component.BBoxMm));
var outward = Array.Empty<double>();
if (center.Length >= 3 && assemblyBox.Length >= 6)
{
var away = Vec.Sub(center, BoxCenter(assemblyBox));
if (Vec.Norm(away) > 1.0)
outward = Vec.Normalize(away);
}
var axis = contact.AxisA.Length >= 3 ? Vec.Normalize(contact.AxisA) :
contact.AxisB.Length >= 3 ? Vec.Normalize(contact.AxisB) : [];
var normal = contact.NormalA.Length >= 3 ? contact.NormalA : contact.NormalB;
normal = normal.Length >= 3 ? Vec.Normalize(normal) : [];
var isCylindrical = contact.ContactKind.Contains("cylindrical", StringComparison.OrdinalIgnoreCase);
var componentA = FindComponentSummary(components, contact.ComponentA, contact.ComponentPathA);
var componentB = FindComponentSummary(components, contact.ComponentB, contact.ComponentPathB);
var boxA = componentA?.BBoxMm is { Length: >= 6 } ? componentA.BBoxMm : contact.BBoxA;
var boxB = componentB?.BBoxMm is { Length: >= 6 } ? componentB.BBoxMm : contact.BBoxB;
return InterfaceObliqueCandidateDirections()
.OrderByDescending(direction => ScoreInterfaceViewDirection(direction, boxA, boxB, outward, axis, normal, isCylindrical))
.First();
}
static double ScoreInterfaceViewDirection(double[] direction, double[] boxA, double[] boxB, double[] outward, double[] axis, double[] normal, bool isCylindrical)
{
var visibilityScore = ScorePairProjectedVisibility(boxA, boxB, direction);
var geometryPreference = 0.0;
if (outward.Length >= 3)
geometryPreference += 0.8 * Math.Max(0.0, Vec.Dot(direction, outward));
if (isCylindrical && axis.Length >= 3)
geometryPreference += 0.7 * (1.0 - Math.Abs(Vec.Dot(direction, axis)));
if (!isCylindrical && normal.Length >= 3)
geometryPreference += 0.7 * Math.Abs(Vec.Dot(direction, normal));
return visibilityScore * (1.0 + geometryPreference);
}
static double ScorePairProjectedVisibility(double[] boxA, double[] boxB, double[] direction)
{
if (boxA.Length < 6 || boxB.Length < 6)
return 1.0;
var projectionA = ProjectBoxForInterface(boxA, direction);
var projectionB = ProjectBoxForInterface(boxB, direction);
var areaA = projectionA.Area;
var areaB = projectionB.Area;
var overlap = OverlapArea(projectionA, projectionB);
var unionArea = Math.Max(1.0, areaA + areaB - overlap);
var smallerArea = Math.Max(1.0, Math.Min(areaA, areaB));
var largerArea = Math.Max(smallerArea, Math.Max(areaA, areaB));
var overlapRatio = Math.Min(1.0, overlap / smallerArea);
var balance = smallerArea / largerArea;
// Contact faces are usually hidden; favor views where both components expose
// enough surrounding exterior area instead of one box covering the other.
return unionArea * (1.0 - overlapRatio * 0.85) * (0.75 + balance * 0.25);
}
static InterfaceProjectionRect ProjectBoxForInterface(double[] box, double[] direction)
{
var d = Vec.Normalize(direction);
var reference = Math.Abs(Vec.Dot(d, [0.0, 1.0, 0.0])) > 0.92
? new[] { 0.0, 0.0, 1.0 }
: [0.0, 1.0, 0.0];
var u = Vec.Normalize(Vec.Cross(reference, d));
var v = Vec.Normalize(Vec.Cross(d, u));
var corners = BoxCorners(box);
var uRange = ProjectionRange(corners, u);
var vRange = ProjectionRange(corners, v);
return new InterfaceProjectionRect(uRange.Min, uRange.Max, vRange.Min, vRange.Max);
}
static double OverlapArea(InterfaceProjectionRect a, InterfaceProjectionRect b)
{
var u = Math.Max(0.0, Math.Min(a.UMax, b.UMax) - Math.Max(a.UMin, b.UMin));
var v = Math.Max(0.0, Math.Min(a.VMax, b.VMax) - Math.Max(a.VMin, b.VMin));
return u * v;
}
static List<double[]> BoxCorners(double[] box) =>
[
[box[0], box[1], box[2]],
[box[0], box[1], box[5]],
[box[0], box[4], box[2]],
[box[0], box[4], box[5]],
[box[3], box[1], box[2]],
[box[3], box[1], box[5]],
[box[3], box[4], box[2]],
[box[3], box[4], box[5]]
];
static (double Min, double Max) ProjectionRange(IReadOnlyList<double[]> points, double[] axis)
{
var values = points.Select(point => Vec.Dot(point, axis)).ToList();
return (values.Min(), values.Max());
}
static List<double[]> InterfaceObliqueCandidateDirections() =>
[
Vec.Normalize([1.0, 1.0, 1.0]),
Vec.Normalize([1.0, 1.0, -1.0]),
Vec.Normalize([1.0, -1.0, 1.0]),
Vec.Normalize([1.0, -1.0, -1.0]),
Vec.Normalize([-1.0, 1.0, 1.0]),
Vec.Normalize([-1.0, 1.0, -1.0]),
Vec.Normalize([-1.0, -1.0, 1.0]),
Vec.Normalize([-1.0, -1.0, -1.0])
];
static double[] AverageVectors(double[] a, double[] b)
{
if (a.Length < 3 && b.Length < 3)
return [];
if (a.Length < 3)
return b.Take(3).ToArray();
if (b.Length < 3)
return a.Take(3).ToArray();
return [(a[0] + b[0]) / 2.0, (a[1] + b[1]) / 2.0, (a[2] + b[2]) / 2.0];
}
static bool ContainsAny(string value, params string[] tokens) =>
tokens.Any(token => value.Contains(token, StringComparison.OrdinalIgnoreCase));
static double[] ChooseComponentHighlightDirection(
AssemblyComponentSummary component,
IReadOnlyList<AssemblyComponentSummary> allComponents)
{
if (component.BBoxMm.Length < 6)
return [1.0, 1.0, 1.0];
var assemblyBox = UnionBoxes(allComponents.Select(item => item.BBoxMm));
if (assemblyBox.Length < 6)
return [1.0, 1.0, 1.0];
var componentCenter = BoxCenter(component.BBoxMm);
var assemblyCenter = BoxCenter(assemblyBox);
var delta = componentCenter.Zip(assemblyCenter, (a, b) => a - b).ToArray();
double Axis(double value, int index)
{
if (Math.Abs(value) > 1.0)
return Math.Sign(value);
var componentSpan = Math.Abs(component.BBoxMm[index + 3] - component.BBoxMm[index]);
var assemblySpan = Math.Abs(assemblyBox[index + 3] - assemblyBox[index]);
return componentSpan >= assemblySpan * 0.45 ? 1.0 : (index == 1 ? 1.0 : -1.0);
}
return Vec.Normalize([Axis(delta[0], 0), Axis(delta[1], 1), Axis(delta[2], 2)]);
}
static double[] UnionBoxes(IEnumerable<double[]> boxes)
{
var valid = boxes.Where(box => box.Length >= 6).ToList();
if (valid.Count == 0)
return [];
return
[
valid.Min(box => box[0]),
valid.Min(box => box[1]),
valid.Min(box => box[2]),
valid.Max(box => box[3]),
valid.Max(box => box[4]),
valid.Max(box => box[5])
];
}
static double[] BoxCenter(double[] box) =>
box.Length >= 6
? [(box[0] + box[3]) / 2.0, (box[1] + box[4]) / 2.0, (box[2] + box[5]) / 2.0]
: [];
static string SanitizeId(string value)
{
var chars = value.Select(ch => char.IsLetterOrDigit(ch) ? ch : '_').ToArray();
return new string(chars).Trim('_');
}
static string FirstNonEmpty(params string[] values) =>
values.FirstOrDefault(value => !string.IsNullOrWhiteSpace(value)) ?? "";
}
readonly record struct InterfaceProjectionRect(double UMin, double UMax, double VMin, double VMax)
{
public double Area => Math.Max(1.0, (UMax - UMin) * (VMax - VMin));
}
sealed class PhysicalInterfaceGroup
{
public string BaseKey { get; set; } = "";
public string Id { get; set; } = "";
public List<AssemblyFaceContactEvidence> Contacts { get; set; } = [];
public List<string> FaceARefs { get; set; } = [];
public List<string> FaceBRefs { get; set; } = [];
public List<int> FaceAIndices { get; set; } = [];
public List<int> FaceBIndices { get; set; } = [];
public List<Face2> RuntimeFaces { get; set; } = [];
public double AnalysisPriority { get; set; }
public string ConfidenceTier { get; set; } = "";
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,505 @@
static class PartModelProcessing
{
public const string DirectPartBrepSource = "part_brep_direct";
public static List<ComponentHighlightImageRequest> BuildComponentHighlightImageRequests(SectionBrepReport report) => [];
public static List<FeatureHighlightImageRequest> BuildFeatureHighlightImageRequests(SectionBrepReport report)
{
var result = new List<FeatureHighlightImageRequest>();
var component = report.AssemblyComponents
.FirstOrDefault(c => c.ReviewScope.Equals("part_design_required", StringComparison.OrdinalIgnoreCase))
?? report.AssemblyComponents.FirstOrDefault();
if (component == null)
return result;
var facesByRef = report.AssemblyFaces
.GroupBy(FaceRef, StringComparer.OrdinalIgnoreCase)
.ToDictionary(g => g.Key, g => g.First(), StringComparer.OrdinalIgnoreCase);
foreach (var feature in report.FeatureGraph.Features
.Where(f => f.FaceRefs.Count > 0)
.Where(f => SameComponent(f, component))
.OrderBy(f => FeatureHighlightPriority(f.Type))
.ThenBy(f => f.Id, StringComparer.OrdinalIgnoreCase))
{
var targetFaces = feature.FaceRefs
.Select(faceRef => facesByRef.TryGetValue(faceRef, out var face) ? face : null)
.OfType<AssemblyFaceEvidence>()
.ToList();
if (targetFaces.Count == 0)
continue;
var viewChoice = ChooseBestObliqueFeatureView(feature, targetFaces, report.AssemblyFaces);
result.Add(new FeatureHighlightImageRequest
{
PlanId = $"feature_highlight_{SanitizeId(feature.Id)}",
ComponentId = component.Id,
InstanceName = component.InstanceName,
DisplayName = component.DisplayName,
ComponentPath = component.Path,
FeatureId = feature.Id,
FeatureType = feature.Type,
FaceRefs = feature.FaceRefs.Distinct(StringComparer.OrdinalIgnoreCase).ToList(),
Views = [viewChoice.ViewName],
PreferredDirectionMm = Vec.Round(viewChoice.Direction),
BlockingFaceRefs = viewChoice.BlockingFaceRefs,
SelectionBasis = "feature_graph_face_refs_grouped_before_image_export"
});
}
return result;
}
public static List<ComponentContextImageRequest> BuildComponentContextImageRequests(SectionBrepReport report) => [];
public static AutoSectionImagePlan BuildAxisSectionPlan(SectionBrepReport report)
{
var plan = new AutoSectionImagePlan
{
MaxRequests = 1
};
var axisFace = report.AssemblyFaces
.Where(face => face.FaceKind.Equals("cylinder", StringComparison.OrdinalIgnoreCase))
.Where(face => face.Axis.Length >= 3 && face.AxisPointMm.Length >= 3)
.OrderByDescending(face => face.AreaMm2)
.ThenByDescending(face => face.RadiusMm)
.FirstOrDefault();
if (axisFace == null)
return plan;
var containedAxis = Vec.Normalize(axisFace.Axis);
var coaxialFaces = report.AssemblyFaces
.Where(face => face.FaceKind.Equals("cylinder", StringComparison.OrdinalIgnoreCase))
.Where(face => face.Axis.Length >= 3 && face.AxisPointMm.Length >= 3)
.Where(face => Math.Abs(Vec.Dot(Vec.Normalize(face.Axis), containedAxis)) >= 0.95)
.ToList();
if (!HasInternalRotationalStructure(coaxialFaces))
return plan;
var target = string.IsNullOrWhiteSpace(axisFace.ComponentDisplayName)
? axisFace.ComponentName
: axisFace.ComponentDisplayName;
var planeCandidates = ChooseSectionPlaneKeys(containedAxis);
for (var i = 0; i < Math.Min(plan.MaxRequests, planeCandidates.Count); i++)
{
var candidate = planeCandidates[i];
plan.Requests.Add(new AutoSectionImageRequest
{
Request = $"part_axis_center_section_{i + 1}",
Rule = "For SLDPRT rotational parts with internal/coaxial structure, create a section plane through the main cylindrical axis.",
Target = target,
Reason = "Part input has no assembly components to hide or highlight; section evidence is generated directly from the opened part body.",
PlaneKey = candidate.PlaneKey,
OffsetMm = 0,
OriginMm = Vec.Round(axisFace.AxisPointMm),
PreferredNormalMm = Vec.Round(candidate.Normal),
PreferredContainedAxisMm = Vec.Round(containedAxis),
SourceRefs = [$"{axisFace.ComponentName}:face#{axisFace.FaceIndex}"]
});
}
return plan;
}
public static List<string> BuildSectionViewRequests(SectionBrepReport report)
{
return report.SectionImagePlan.Requests
.Where(request => !string.IsNullOrWhiteSpace(request.PlaneKey))
.Take(2)
.Select(request =>
$"{request.PlaneKey}:{request.Request}|target={SanitizeMetadata(request.Target)};reason={SanitizeMetadata(request.Reason)}")
.ToList();
}
static bool HasInternalRotationalStructure(IReadOnlyList<AssemblyFaceEvidence> coaxialFaces)
{
if (coaxialFaces.Count < 2)
return false;
var radiusLayers = coaxialFaces
.Where(face => face.RadiusMm > 0)
.Select(face => Math.Round(face.RadiusMm, 1))
.Distinct()
.Count();
if (radiusLayers >= 2)
return true;
return coaxialFaces.Any(face =>
face.FunctionalRole.Contains("hole", StringComparison.OrdinalIgnoreCase) ||
face.FunctionalRole.Contains("bore", StringComparison.OrdinalIgnoreCase) ||
face.SurfaceProcessRole.Contains("hole", StringComparison.OrdinalIgnoreCase) ||
face.SurfaceProcessRole.Contains("bore", StringComparison.OrdinalIgnoreCase));
}
static List<(string PlaneKey, double[] Normal)> ChooseSectionPlaneKeys(double[] containedAxis)
{
var candidates = new List<(string PlaneKey, double[] Normal)>
{
("front", [0.0, 0.0, 1.0]),
("top", [0.0, 1.0, 0.0]),
("right", [1.0, 0.0, 0.0])
};
return candidates
.OrderBy(candidate => Math.Abs(Vec.Dot(containedAxis, candidate.Normal)))
.ThenBy(candidate => candidate.PlaneKey, StringComparer.OrdinalIgnoreCase)
.Take(2)
.ToList();
}
static string SanitizeMetadata(string value) =>
(value ?? "").Replace(';', ',').Replace('|', '/').Replace('\r', ' ').Replace('\n', ' ').Trim();
static bool SameComponent(MechanicalFeature feature, AssemblyComponentSummary component)
{
if (!string.IsNullOrWhiteSpace(feature.ComponentPath) &&
!string.IsNullOrWhiteSpace(component.Path) &&
feature.ComponentPath.Equals(component.Path, StringComparison.OrdinalIgnoreCase))
return true;
return feature.ComponentName.Equals(component.InstanceName, StringComparison.OrdinalIgnoreCase);
}
static int FeatureHighlightPriority(string featureType)
{
if (featureType.Contains("unknown", StringComparison.OrdinalIgnoreCase) ||
featureType.Contains("complex", StringComparison.OrdinalIgnoreCase))
return 0;
if (featureType.Contains("hole", StringComparison.OrdinalIgnoreCase))
return 1;
if (featureType.Contains("cylindrical", StringComparison.OrdinalIgnoreCase))
return 2;
if (featureType.Contains("planar", StringComparison.OrdinalIgnoreCase))
return 3;
return 4;
}
static (string ViewName, double[] Direction, List<string> BlockingFaceRefs) ChooseBestObliqueFeatureView(
MechanicalFeature feature,
IReadOnlyList<AssemblyFaceEvidence> targetFaces,
IReadOnlyList<AssemblyFaceEvidence> allFaces)
{
var targetBox = UnionBoxes(targetFaces.Select(f => f.BBoxMm));
if (targetBox.Length < 6)
return ("isometric", [1.0, 1.0, 1.0], []);
var targetRefs = feature.FaceRefs.ToHashSet(StringComparer.OrdinalIgnoreCase);
var others = allFaces
.Where(face => !targetRefs.Contains(FaceRef(face)))
.Where(face => face.BBoxMm.Length >= 6)
.ToList();
var isPlanarTarget = IsPlanarFeatureTarget(feature, targetFaces);
var preferredViewSide = DeterminePreferredViewSide(feature, targetFaces, allFaces, targetBox);
var candidates = BuildObliqueCandidateDirections(false);
candidates = EnforcePreferredViewSide(candidates, preferredViewSide, isPlanarTarget);
var projectedTargetAreas = candidates
.Select(direction => ProjectBox(targetBox, direction).Area)
.ToList();
var maxTargetArea = Math.Max(1.0, projectedTargetAreas.Max());
var bestScore = double.MaxValue;
var bestDirection = candidates[0];
var bestBlocking = new List<string>();
for (var i = 0; i < candidates.Count; i++)
{
var direction = candidates[i];
var targetProjection = ProjectBox(targetBox, direction);
var blockers = new List<(string Ref, double Penalty)>();
var score = (maxTargetArea - targetProjection.Area) / maxTargetArea * (isPlanarTarget ? 0.08 : 0.35);
var absDirection = direction.Select(Math.Abs).ToArray();
var maxComponent = Math.Max(absDirection[0], Math.Max(absDirection[1], absDirection[2]));
var minComponent = Math.Min(absDirection[0], Math.Min(absDirection[1], absDirection[2]));
score += (maxComponent - minComponent) / Math.Max(maxComponent, 0.001) * (isPlanarTarget ? 0.04 : 0.25);
score += PreferredViewSidePenalty(direction, preferredViewSide, isPlanarTarget);
score += StableNonPlanarAzimuthPenalty(feature, targetFaces, direction, preferredViewSide, isPlanarTarget);
foreach (var other in others)
{
var otherProjection = ProjectBox(other.BBoxMm, direction);
var overlap = OverlapArea(targetProjection, otherProjection);
if (overlap <= 0.001)
continue;
var inFrontGap = otherProjection.MaxDepth - targetProjection.MinDepth;
if (inFrontGap <= 0)
continue;
var penalty = overlap / Math.Max(targetProjection.Area, 1.0) * (1.0 + Math.Min(inFrontGap, 100.0) / 200.0);
score += penalty;
blockers.Add((FaceRef(other), penalty));
}
if (score < bestScore)
{
bestScore = score;
bestDirection = direction;
bestBlocking = blockers
.OrderByDescending(item => item.Penalty)
.Take(8)
.Select(item => item.Ref)
.ToList();
}
}
return (ObliqueDirectionName(bestDirection), bestDirection, bestBlocking);
}
static bool IsPlanarFeatureTarget(MechanicalFeature feature, IReadOnlyList<AssemblyFaceEvidence> targetFaces)
{
if (feature.Type.Contains("planar", StringComparison.OrdinalIgnoreCase))
return true;
return targetFaces.Count > 0 &&
targetFaces.All(face => face.FaceKind.Equals("plane", StringComparison.OrdinalIgnoreCase));
}
static double[] DeterminePreferredViewSide(
MechanicalFeature feature,
IReadOnlyList<AssemblyFaceEvidence> targetFaces,
IReadOnlyList<AssemblyFaceEvidence> allFaces,
double[] targetBox)
{
var planeNormal = WeightedAverageNormal(targetFaces
.Where(face => face.FaceKind.Equals("plane", StringComparison.OrdinalIgnoreCase))
.Where(face => face.Normal.Length >= 3));
if (planeNormal.Length >= 3)
return planeNormal;
var componentFaces = allFaces
.Where(face => face.ComponentName.Equals(feature.ComponentName, StringComparison.OrdinalIgnoreCase))
.Where(face => face.BBoxMm.Length >= 6)
.ToList();
if (componentFaces.Count == 0)
componentFaces = allFaces.Where(face => face.BBoxMm.Length >= 6).ToList();
var modelBox = UnionBoxes(componentFaces.Select(face => face.BBoxMm));
var targetCenter = BoxCenter(targetBox);
var modelCenter = BoxCenter(modelBox);
if (targetCenter.Length < 3 || modelCenter.Length < 3 || modelBox.Length < 6)
return [];
var verticalOffset = targetCenter[1] - modelCenter[1];
if (Math.Abs(verticalOffset) >= 0.001)
return verticalOffset > 0
? [0.0, 1.0, 0.0]
: [0.0, -1.0, 0.0];
return [];
}
static double[] WeightedAverageNormal(IEnumerable<AssemblyFaceEvidence> faces)
{
var sum = new[] { 0.0, 0.0, 0.0 };
var totalWeight = 0.0;
foreach (var face in faces)
{
var normal = Vec.Normalize(face.Normal);
if (normal.Length < 3)
continue;
var weight = Math.Max(face.AreaMm2, 1.0);
sum = Vec.Add(sum, Vec.Mul(normal, weight));
totalWeight += weight;
}
if (totalWeight <= 0.0 || Vec.Norm(sum) < 1e-6)
return [];
return Vec.Normalize(sum);
}
static List<double[]> EnforcePreferredViewSide(List<double[]> candidates, double[] preferredViewSide, bool preferSteeperPlanarOblique)
{
if (preferredViewSide.Length < 3)
return candidates;
var preferred = Vec.Normalize(preferredViewSide);
var minimumAlignment = preferSteeperPlanarOblique ? 0.30 : 0.7;
var maximumAlignment = preferSteeperPlanarOblique ? 0.78 : 1.0;
var filtered = candidates
.Where(direction =>
{
var alignment = Vec.Dot(Vec.Normalize(direction), preferred);
return alignment >= minimumAlignment && alignment <= maximumAlignment;
})
.ToList();
if (filtered.Count == 0 && preferSteeperPlanarOblique)
{
filtered = candidates
.Where(direction => Vec.Dot(Vec.Normalize(direction), preferred) >= minimumAlignment)
.ToList();
}
return filtered.Count > 0 ? filtered : candidates;
}
static double PreferredViewSidePenalty(double[] direction, double[] preferredViewSide, bool preferSteeperPlanarOblique)
{
if (preferredViewSide.Length < 3)
return 0.0;
var alignment = Vec.Dot(Vec.Normalize(direction), Vec.Normalize(preferredViewSide));
if (preferSteeperPlanarOblique)
{
const double targetPlanarAlignment = 0.45;
return Math.Abs(alignment - targetPlanarAlignment) * 0.55;
}
return (1.0 - alignment) * 0.55;
}
static double StableNonPlanarAzimuthPenalty(
MechanicalFeature feature,
IReadOnlyList<AssemblyFaceEvidence> targetFaces,
double[] direction,
double[] preferredViewSide,
bool isPlanarTarget)
{
if (isPlanarTarget || preferredViewSide.Length < 3)
return 0.0;
var hasCurvedOrUnknownTarget = targetFaces.Any(face =>
face.FaceKind.Equals("cylinder", StringComparison.OrdinalIgnoreCase) ||
face.FaceKind.Equals("cone", StringComparison.OrdinalIgnoreCase) ||
face.FaceKind.Equals("other", StringComparison.OrdinalIgnoreCase));
if (!hasCurvedOrUnknownTarget)
return 0.0;
var preferred = Vec.Normalize(preferredViewSide);
if (preferred.Length < 3 || Math.Abs(preferred[1]) < 0.5)
return 0.0;
// When curved/unknown faces only tell us "upper/lower", X/Z is otherwise decided
// by small bbox-score differences. Keep a stable oblique quadrant for direct part
// images so adjacent main-axis cylindrical features are viewed consistently.
var stableOblique = Vec.Normalize([1.0, preferred[1] >= 0 ? 2.0 : -2.0, -1.0]);
var alignment = Vec.Dot(Vec.Normalize(direction), stableOblique);
var weight = feature.Type.Contains("main_axis_cylindrical", StringComparison.OrdinalIgnoreCase)
? 0.35
: 0.18;
return (1.0 - alignment) * weight;
}
static double[] ProjectOntoPlane(double[] vector, double[] planeNormal)
{
var normal = Vec.Normalize(planeNormal);
var v = Vec.Normalize(vector);
if (normal.Length < 3 || v.Length < 3)
return [];
return Vec.Normalize(Vec.Sub(v, Vec.Mul(normal, Vec.Dot(v, normal))));
}
static string ObliqueDirectionName(double[] direction)
{
static string Sign(double value, string axis) => value >= 0 ? $"{axis}p" : $"{axis}n";
var ax = Math.Abs(direction.ElementAtOrDefault(0));
var ay = Math.Abs(direction.ElementAtOrDefault(1));
var az = Math.Abs(direction.ElementAtOrDefault(2));
var min = Math.Max(0.001, Math.Min(ax, Math.Min(ay, az)));
var wx = Math.Max(1, (int)Math.Round(ax / min));
var wy = Math.Max(1, (int)Math.Round(ay / min));
var wz = Math.Max(1, (int)Math.Round(az / min));
var signName = $"oblique_{Sign(direction.ElementAtOrDefault(0), "x")}_{Sign(direction.ElementAtOrDefault(1), "y")}_{Sign(direction.ElementAtOrDefault(2), "z")}";
return wx == 1 && wy == 1 && wz == 1
? signName
: $"{signName}_x{wx}_y{wy}_z{wz}";
}
static List<double[]> BuildObliqueCandidateDirections(bool includeSteepPlanarObliques)
{
var signs = new[] { -1.0, 1.0 };
var result = new List<double[]>();
foreach (var sx in signs)
foreach (var sy in signs)
foreach (var sz in signs)
{
result.Add(Vec.Normalize([sx, sy, sz]));
}
return result;
}
static double[] UnionBoxes(IEnumerable<double[]> boxes)
{
var valid = boxes.Where(box => box.Length >= 6).ToList();
if (valid.Count == 0)
return [];
return
[
valid.Min(box => box[0]),
valid.Min(box => box[1]),
valid.Min(box => box[2]),
valid.Max(box => box[3]),
valid.Max(box => box[4]),
valid.Max(box => box[5])
];
}
static double[] BoxCenter(double[] box) =>
box.Length >= 6
? [(box[0] + box[3]) / 2.0, (box[1] + box[4]) / 2.0, (box[2] + box[5]) / 2.0]
: [];
static ProjectedBox ProjectBox(double[] box, double[] viewDirection)
{
var d = Vec.Normalize(viewDirection);
var up = Math.Abs(Vec.Dot(d, [0.0, 1.0, 0.0])) > 0.92 ? new[] { 0.0, 0.0, 1.0 } : new[] { 0.0, 1.0, 0.0 };
var u = Vec.Normalize(Vec.Cross(up, d));
var v = Vec.Normalize(Vec.Cross(d, u));
var corners = BoxCorners(box);
var uValues = corners.Select(p => Vec.Dot(p, u)).ToList();
var vValues = corners.Select(p => Vec.Dot(p, v)).ToList();
var dValues = corners.Select(p => Vec.Dot(p, d)).ToList();
return new ProjectedBox(
uValues.Min(),
uValues.Max(),
vValues.Min(),
vValues.Max(),
dValues.Min(),
dValues.Max());
}
static List<double[]> BoxCorners(double[] box) =>
[
[box[0], box[1], box[2]],
[box[0], box[1], box[5]],
[box[0], box[4], box[2]],
[box[0], box[4], box[5]],
[box[3], box[1], box[2]],
[box[3], box[1], box[5]],
[box[3], box[4], box[2]],
[box[3], box[4], box[5]]
];
static double OverlapArea(ProjectedBox a, ProjectedBox b)
{
var width = Math.Max(0.0, Math.Min(a.MaxU, b.MaxU) - Math.Max(a.MinU, b.MinU));
var height = Math.Max(0.0, Math.Min(a.MaxV, b.MaxV) - Math.Max(a.MinV, b.MinV));
return width * height;
}
static string FaceRef(AssemblyFaceEvidence face) => $"{face.ComponentName}:face#{face.FaceIndex}";
static string SanitizeId(string value)
{
var chars = value.Select(ch => char.IsLetterOrDigit(ch) ? ch : '_').ToArray();
return new string(chars).Trim('_');
}
}
sealed record ProjectedBox(double MinU, double MaxU, double MinV, double MaxV, double MinDepth, double MaxDepth)
{
public double Area => Math.Max(0.0, MaxU - MinU) * Math.Max(0.0, MaxV - MinV);
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,108 @@
# SectionBrepExtractor
Temporary extractor for true section B-rep evidence.
Goal:
1. Use a chosen section plane.
2. Intersect SolidWorks bodies with that plane using official API hooks.
3. Convert the section result into a 2D B-rep-style evidence object: faces, edges, loops, and component provenance.
This is the layer that will eventually compare a textbook section image's lines against a model's section B-rep.
Run:
```powershell
dotnet run --project tools\model-diagnostics\SectionBrepExtractor\SectionBrepExtractor.csproj -c Release -- "D:\path\model.SLDASM"
```
Optionally export model-view JPG images during the same run:
```powershell
dotnet run --project tools\model-diagnostics\SectionBrepExtractor\SectionBrepExtractor.csproj -c Release -- "D:\path\model.SLDASM" --output-dir runtime\section_brep\trial1 --export-images
```
When `--image-views` is omitted, the tool exports seven baseline views:
`front,back,top,bottom,left,right,isometric`.
Section B-rep and section image export are disabled in the current workflow. Use assembly/component B-rep, component highlight images, part-file images, and internal component group context images instead.
Image export is implemented in `ModelImageExporter.cs`, separate from the B-rep extraction logic in `Program.cs`.
Image evidence families are hard workflow boundaries:
- `assembly_component_position`: component position and whole-component function only. It has two visibility variants:
- `unobstructed` (`assembly_component_highlight_view`): the assembly's existing visibility state is preserved and the target instance is highlighted in place. The exporter hides no component in this mode.
- `occluded_context` (`assembly_component_context_isolate_view`): only geometry-derived occlusion blockers are hidden. Direct contact or mate neighbors are always preserved, and unrelated non-blocking components keep their original visibility.
These are complementary renderings of the same evidence family, not component evidence versus interface evidence. Use the first whenever the target is already readable in the assembly; use the second only for an actually occluded internal target.
- `assembly_physical_interface` (`assembly_physical_interface_view`): physical contact/fit function only. Images isolate exactly two participating components and highlight the grouped interface faces. They must not be used as component-position or per-face part evidence.
Planar interface facts are retained in the B-rep report, but ordinary single-plane contacts are not exported as `physical_interfaces` images because they are not fit-tolerance evidence. Planar interface images are only for multi-face/profile fits such as slots, keys, or prismatic locating contacts. Cylindrical interface images first require analytic cylinder axis, radius, and axial-range compatibility. The common axial range is checked in 2 mm slices; for each slice the actual angular intervals are obtained from the SolidWorks trimmed Face and its Loop/Edge boundaries, without face tessellation or triangle-grid overlap. One slice with a positive angular interval intersection is sufficient; no minimum overlap-area threshold is applied. Opposing face normals are still required so two exterior faces on the same theoretical cylinder are not treated as a hole/shaft fit.
- `part_all_face_surface` (`functional_group_all_face_highlight`): post-functional-group part and surface diagnosis only. These images must not enter component-function or interface-function analysis.
- `part_feature_surface` (`part_feature_highlight_view`): direct-part feature evidence only.
`ImageKind` remains the concrete renderer/output type for compatibility. `EvidenceFamily` controls which AI stage may consume an image. Do not route images by filename alone.
Outputs:
- `section_brep_report.json`: assembly/component B-rep facts, face/contact facts, `FeatureGraph`, `SemanticFusionContract`, optional `ImageExport`, and empty legacy section fields.
- `section_brep_report.md`: readable summary with exported image paths.
- `model_images\*.jpg`: SolidWorks standard-view and section-view screenshots when image export is enabled.
Supported image views:
- `front`
- `back`
- `left`
- `right`
- `top`
- `bottom`
- `isometric`
- `trimetric`
- `dimetric`
Supported section planes:
- `front`
- `top`
- `right`
Feature graph:
The extractor also emits `FeatureGraph` as the B-rep side of the image/B-rep fusion layer. The first version groups raw faces into:
- `hole_group` / `hole_feature`
- `main_axis_cylindrical_surface_group`
- `cylindrical_surface_group`
- `planar_pad_step_or_face_candidate`
- assembly contact features when contacts exist
Each feature keeps source face refs and lists `VisualObservationNeeds` plus `RequiredBrepChecks` so AI diagnostics can combine image cues with measurable B-rep facts instead of treating either source as absolute.
Semantic fusion contract:
The extractor emits `SemanticFusionContract` as the machine-readable instruction boundary for AI diagnosis. It does not generate final mechanical semantics in code. Instead, it defines:
- the required pipeline from B-rep facts and images to a global mechanical semantic graph, then to local semantic units;
- supported B-rep feature types;
- semantic assertion types such as `part_identity`, `structural_semantic`, `functional_semantic`, `manufacturing_semantic`, `assembly_semantic`, and `risk_semantic`;
- retrieval views, local semantic unit schema, B-rep fact bundle schema, confidence/status policy, missing-check fields, retrieval policy, and dedup policy.
At diagnosis time, the AI uses this contract plus `FeatureGraph`, raw B-rep facts, standard images, and section images to generate the actual mechanical semantic graph. Then it generates knowledge-blind `LocalSemanticUnit` objects: one neutral retrieval sentence plus concrete B-rep/image facts. Rule ids and final judgements are added only after knowledge retrieval and detailed rule verification.
Assembly diagnosis scope:
- For `SLDASM` input, diagnose both assembly-level relations and part-level structure.
- Standard or purchased components are marked `review_scope=assembly_context_only`; they are used for mating context, accessibility, and standard-part selection/calculation checks, but not for nonstandard part-structure taboo checks.
- Nonstandard or self-designed components are marked `review_scope=part_design_required`; AI must generate local semantic units for their local shape, surfaces, holes/slots/bosses/ribs, machining accessibility, stiffness, and other part-design views.
For assembly input, the report also emits two alignment structures:
- `ComponentEvidencePackages`: one package per SolidWorks component instance. It partitions assembly-derived B-rep faces, feature ids, and contact ids by component so evidence from different parts is not mixed.
- `PartImagePlan`: image-export plan for components with `review_scope=part_design_required`. These images may come from the component part file, but their geometry facts must still use the component's B-rep subset extracted from the assembly. Do not re-extract part B-rep independently and merge it into the assembly report.
Diagnosis order for assemblies:
1. Analyze assembly-level design issues first: contacts, fits, locating, support, disassembly, accessibility, motion/interference, sealing, and lubrication.
2. Then analyze each nonstandard/self-designed component's part-design issues using its `ComponentEvidencePackage` plus the matching `PartImagePlan` images.
3. Standard or purchased components remain assembly context unless the specific rule is about standard-part selection or calculation.
@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0-windows</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<PlatformTarget>x64</PlatformTarget>
<NoWarn>$(NoWarn);CA1416</NoWarn>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="SolidWorks.Interop.sldworks" Version="32.1.0" />
<PackageReference Include="SolidWorks.Interop.swconst" Version="32.1.0" />
</ItemGroup>
</Project>
@@ -0,0 +1,57 @@
{
"runtimeTarget": {
"name": ".NETCoreApp,Version=v8.0",
"signature": ""
},
"compilationOptions": {},
"targets": {
".NETCoreApp,Version=v8.0": {
"SectionBrepExtractor/1.0.0": {
"dependencies": {
"SolidWorks.Interop.sldworks": "32.1.0",
"SolidWorks.Interop.swconst": "32.1.0"
},
"runtime": {
"SectionBrepExtractor.dll": {}
}
},
"SolidWorks.Interop.sldworks/32.1.0": {
"runtime": {
"lib/netstandard2.0/SolidWorks.Interop.sldworks.dll": {
"assemblyVersion": "32.1.0.123",
"fileVersion": "32.1.0.123"
}
}
},
"SolidWorks.Interop.swconst/32.1.0": {
"runtime": {
"lib/netstandard2.0/SolidWorks.Interop.swconst.dll": {
"assemblyVersion": "32.1.0.123",
"fileVersion": "32.1.0.123"
}
}
}
}
},
"libraries": {
"SectionBrepExtractor/1.0.0": {
"type": "project",
"serviceable": false,
"sha512": ""
},
"SolidWorks.Interop.sldworks/32.1.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-lq3QmJwBbVE3K+pN5JFSGn1Bj7J1vUyTr4TtT23UAOtd8MXLElZROm9Iee2N8SP8AXsLTpXdBXGs7xYeJT53qw==",
"path": "solidworks.interop.sldworks/32.1.0",
"hashPath": "solidworks.interop.sldworks.32.1.0.nupkg.sha512"
},
"SolidWorks.Interop.swconst/32.1.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-mOLeWDKf0hX7iSNmdc22FmwoCaqH3KuNhODNGdWuT36KB/maGzQdfU+r9YS97n3mMIdWN3qaLBQ4eJG8z77rMw==",
"path": "solidworks.interop.swconst/32.1.0",
"hashPath": "solidworks.interop.swconst.32.1.0.nupkg.sha512"
}
}
}
@@ -0,0 +1,13 @@
{
"runtimeOptions": {
"tfm": "net8.0",
"framework": {
"name": "Microsoft.NETCore.App",
"version": "8.0.0"
},
"configProperties": {
"System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization": false,
"CSWINRT_USE_WINDOWS_UI_XAML_PROJECTIONS": false
}
}
}
@@ -0,0 +1,57 @@
{
"runtimeTarget": {
"name": ".NETCoreApp,Version=v8.0",
"signature": ""
},
"compilationOptions": {},
"targets": {
".NETCoreApp,Version=v8.0": {
"SectionBrepExtractor/1.0.0": {
"dependencies": {
"SolidWorks.Interop.sldworks": "32.1.0",
"SolidWorks.Interop.swconst": "32.1.0"
},
"runtime": {
"SectionBrepExtractor.dll": {}
}
},
"SolidWorks.Interop.sldworks/32.1.0": {
"runtime": {
"lib/netstandard2.0/SolidWorks.Interop.sldworks.dll": {
"assemblyVersion": "32.1.0.123",
"fileVersion": "32.1.0.123"
}
}
},
"SolidWorks.Interop.swconst/32.1.0": {
"runtime": {
"lib/netstandard2.0/SolidWorks.Interop.swconst.dll": {
"assemblyVersion": "32.1.0.123",
"fileVersion": "32.1.0.123"
}
}
}
}
},
"libraries": {
"SectionBrepExtractor/1.0.0": {
"type": "project",
"serviceable": false,
"sha512": ""
},
"SolidWorks.Interop.sldworks/32.1.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-lq3QmJwBbVE3K+pN5JFSGn1Bj7J1vUyTr4TtT23UAOtd8MXLElZROm9Iee2N8SP8AXsLTpXdBXGs7xYeJT53qw==",
"path": "solidworks.interop.sldworks/32.1.0",
"hashPath": "solidworks.interop.sldworks.32.1.0.nupkg.sha512"
},
"SolidWorks.Interop.swconst/32.1.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-mOLeWDKf0hX7iSNmdc22FmwoCaqH3KuNhODNGdWuT36KB/maGzQdfU+r9YS97n3mMIdWN3qaLBQ4eJG8z77rMw==",
"path": "solidworks.interop.swconst/32.1.0",
"hashPath": "solidworks.interop.swconst.32.1.0.nupkg.sha512"
}
}
}
@@ -0,0 +1,14 @@
{
"runtimeOptions": {
"tfm": "net8.0",
"framework": {
"name": "Microsoft.NETCore.App",
"version": "8.0.0"
},
"configProperties": {
"System.Reflection.Metadata.MetadataUpdater.IsSupported": false,
"System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization": false,
"CSWINRT_USE_WINDOWS_UI_XAML_PROJECTIONS": false
}
}
}
@@ -0,0 +1,4 @@
// <autogenerated />
using System;
using System.Reflection;
[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETCoreApp,Version=v8.0", FrameworkDisplayName = ".NET 8.0")]
@@ -0,0 +1,24 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
using System;
using System.Reflection;
[assembly: System.Reflection.AssemblyCompanyAttribute("SectionBrepExtractor")]
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+1bdf41f4900b623dd9948b3fc71ac3bb71e8e8e4")]
[assembly: System.Reflection.AssemblyProductAttribute("SectionBrepExtractor")]
[assembly: System.Reflection.AssemblyTitleAttribute("SectionBrepExtractor")]
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
[assembly: System.Runtime.Versioning.TargetPlatformAttribute("Windows7.0")]
[assembly: System.Runtime.Versioning.SupportedOSPlatformAttribute("Windows7.0")]
// Generated by the MSBuild WriteCodeFragment class.
@@ -0,0 +1 @@
e0d52fd083d15feeb9edc676163068d473a3e40a719480780b00c952c06952c2
@@ -0,0 +1,19 @@
is_global = true
build_property.TargetFramework = net8.0-windows
build_property.TargetFrameworkIdentifier = .NETCoreApp
build_property.TargetFrameworkVersion = v8.0
build_property.TargetPlatformMinVersion = 7.0
build_property.UsingMicrosoftNETSdkWeb =
build_property.ProjectTypeGuids =
build_property.InvariantGlobalization =
build_property.PlatformNeutralAssembly =
build_property.EnforceExtendedAnalyzerRules =
build_property.EntryPointFilePath =
build_property._SupportedPlatformList = Linux,macOS,Windows
build_property.RootNamespace = SectionBrepExtractor
build_property.ProjectDir = D:\CSharpProjects\agent4\tools\model-diagnostics\SectionBrepExtractor\
build_property.EnableComHosting =
build_property.EnableGeneratedComInterfaceComImportInterop =
build_property.CsWinRTUseWindowsUIXamlProjections = false
build_property.EffectiveAnalysisLevelStyle = 8.0
build_property.EnableCodeStyleSeverity =
@@ -0,0 +1,8 @@
// <auto-generated/>
global using System;
global using System.Collections.Generic;
global using System.IO;
global using System.Linq;
global using System.Net.Http;
global using System.Threading;
global using System.Threading.Tasks;
@@ -0,0 +1 @@
3bf86a3a67add5a7744ad92490ed4a208bb57db2cccadbb013d27a19957e1432
@@ -0,0 +1,41 @@
D:\CSharpProjects\agent4\tools\SectionBrepExtractor\bin\Debug\net8.0-windows\SectionBrepExtractor.exe
D:\CSharpProjects\agent4\tools\SectionBrepExtractor\bin\Debug\net8.0-windows\SectionBrepExtractor.deps.json
D:\CSharpProjects\agent4\tools\SectionBrepExtractor\bin\Debug\net8.0-windows\SectionBrepExtractor.runtimeconfig.json
D:\CSharpProjects\agent4\tools\SectionBrepExtractor\bin\Debug\net8.0-windows\SectionBrepExtractor.dll
D:\CSharpProjects\agent4\tools\SectionBrepExtractor\bin\Debug\net8.0-windows\SectionBrepExtractor.pdb
D:\CSharpProjects\agent4\tools\SectionBrepExtractor\bin\Debug\net8.0-windows\SolidWorks.Interop.sldworks.dll
D:\CSharpProjects\agent4\tools\SectionBrepExtractor\bin\Debug\net8.0-windows\SolidWorks.Interop.swconst.dll
D:\CSharpProjects\agent4\tools\SectionBrepExtractor\obj\Debug\net8.0-windows\SectionBrepExtractor.csproj.AssemblyReference.cache
D:\CSharpProjects\agent4\tools\SectionBrepExtractor\obj\Debug\net8.0-windows\SectionBrepExtractor.GeneratedMSBuildEditorConfig.editorconfig
D:\CSharpProjects\agent4\tools\SectionBrepExtractor\obj\Debug\net8.0-windows\SectionBrepExtractor.AssemblyInfoInputs.cache
D:\CSharpProjects\agent4\tools\SectionBrepExtractor\obj\Debug\net8.0-windows\SectionBrepExtractor.AssemblyInfo.cs
D:\CSharpProjects\agent4\tools\SectionBrepExtractor\obj\Debug\net8.0-windows\SectionBrepExtractor.csproj.CoreCompileInputs.cache
D:\CSharpProjects\agent4\tools\SectionBrepExtractor\obj\Debug\net8.0-windows\SectionB.FFBBF4A1.Up2Date
D:\CSharpProjects\agent4\tools\SectionBrepExtractor\obj\Debug\net8.0-windows\SectionBrepExtractor.dll
D:\CSharpProjects\agent4\tools\SectionBrepExtractor\obj\Debug\net8.0-windows\refint\SectionBrepExtractor.dll
D:\CSharpProjects\agent4\tools\SectionBrepExtractor\obj\Debug\net8.0-windows\SectionBrepExtractor.pdb
D:\CSharpProjects\agent4\tools\SectionBrepExtractor\obj\Debug\net8.0-windows\SectionBrepExtractor.genruntimeconfig.cache
D:\CSharpProjects\agent4\tools\SectionBrepExtractor\obj\Debug\net8.0-windows\ref\SectionBrepExtractor.dll
D:\CSharpProjects\agent4\tools\model-diagnostics\SectionBrepExtractor\bin\Debug\net8.0-windows\SectionBrepExtractor.exe
D:\CSharpProjects\agent4\tools\model-diagnostics\SectionBrepExtractor\bin\Debug\net8.0-windows\SectionBrepExtractor.deps.json
D:\CSharpProjects\agent4\tools\model-diagnostics\SectionBrepExtractor\bin\Debug\net8.0-windows\SectionBrepExtractor.runtimeconfig.json
D:\CSharpProjects\agent4\tools\model-diagnostics\SectionBrepExtractor\bin\Debug\net8.0-windows\SectionBrepExtractor.dll
D:\CSharpProjects\agent4\tools\model-diagnostics\SectionBrepExtractor\bin\Debug\net8.0-windows\SectionBrepExtractor.pdb
D:\CSharpProjects\agent4\tools\model-diagnostics\SectionBrepExtractor\bin\Debug\net8.0-windows\SolidWorks.Interop.sldworks.dll
D:\CSharpProjects\agent4\tools\model-diagnostics\SectionBrepExtractor\bin\Debug\net8.0-windows\SolidWorks.Interop.swconst.dll
D:\CSharpProjects\agent4\tools\model-diagnostics\SectionBrepExtractor\obj\Debug\net8.0-windows\SectionBrepExtractor.csproj.AssemblyReference.cache
D:\CSharpProjects\agent4\tools\model-diagnostics\SectionBrepExtractor\obj\Debug\net8.0-windows\SectionBrepExtractor.GeneratedMSBuildEditorConfig.editorconfig
D:\CSharpProjects\agent4\tools\model-diagnostics\SectionBrepExtractor\obj\Debug\net8.0-windows\SectionBrepExtractor.AssemblyInfoInputs.cache
D:\CSharpProjects\agent4\tools\model-diagnostics\SectionBrepExtractor\obj\Debug\net8.0-windows\SectionBrepExtractor.AssemblyInfo.cs
D:\CSharpProjects\agent4\tools\model-diagnostics\SectionBrepExtractor\obj\Debug\net8.0-windows\SectionBrepExtractor.csproj.CoreCompileInputs.cache
D:\CSharpProjects\agent4\tools\model-diagnostics\SectionBrepExtractor\obj\Debug\net8.0-windows\SectionB.FFBBF4A1.Up2Date
D:\CSharpProjects\agent4\tools\model-diagnostics\SectionBrepExtractor\obj\Debug\net8.0-windows\SectionBrepExtractor.dll
D:\CSharpProjects\agent4\tools\model-diagnostics\SectionBrepExtractor\obj\Debug\net8.0-windows\refint\SectionBrepExtractor.dll
D:\CSharpProjects\agent4\tools\model-diagnostics\SectionBrepExtractor\obj\Debug\net8.0-windows\SectionBrepExtractor.pdb
D:\CSharpProjects\agent4\tools\model-diagnostics\SectionBrepExtractor\obj\Debug\net8.0-windows\SectionBrepExtractor.genruntimeconfig.cache
D:\CSharpProjects\agent4\tools\model-diagnostics\SectionBrepExtractor\obj\Debug\net8.0-windows\ref\SectionBrepExtractor.dll
D:\CSharpProjects\agent4\.tmp\buildcheck\SectionBrepExtractor\SectionBrepExtractor.exe
D:\CSharpProjects\agent4\.tmp\buildcheck\SectionBrepExtractor\SectionBrepExtractor.deps.json
D:\CSharpProjects\agent4\.tmp\buildcheck\SectionBrepExtractor\SectionBrepExtractor.runtimeconfig.json
D:\CSharpProjects\agent4\.tmp\buildcheck\SectionBrepExtractor\SectionBrepExtractor.dll
D:\CSharpProjects\agent4\.tmp\buildcheck\SectionBrepExtractor\SectionBrepExtractor.pdb
@@ -0,0 +1 @@
eb1ce21679dd92b145d1cdc40d2b97dc51c457f4bf453243d4fe9be812633e07
@@ -0,0 +1,4 @@
// <autogenerated />
using System;
using System.Reflection;
[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETCoreApp,Version=v8.0", FrameworkDisplayName = ".NET 8.0")]
@@ -0,0 +1,24 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
using System;
using System.Reflection;
[assembly: System.Reflection.AssemblyCompanyAttribute("SectionBrepExtractor")]
[assembly: System.Reflection.AssemblyConfigurationAttribute("Release")]
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+1bdf41f4900b623dd9948b3fc71ac3bb71e8e8e4")]
[assembly: System.Reflection.AssemblyProductAttribute("SectionBrepExtractor")]
[assembly: System.Reflection.AssemblyTitleAttribute("SectionBrepExtractor")]
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
[assembly: System.Runtime.Versioning.TargetPlatformAttribute("Windows7.0")]
[assembly: System.Runtime.Versioning.SupportedOSPlatformAttribute("Windows7.0")]
// Generated by the MSBuild WriteCodeFragment class.
@@ -0,0 +1 @@
eedabf9ecf2e494bda3ce01b91dbe06275088be3b51605f222954bff0309539a
@@ -0,0 +1,19 @@
is_global = true
build_property.TargetFramework = net8.0-windows
build_property.TargetFrameworkIdentifier = .NETCoreApp
build_property.TargetFrameworkVersion = v8.0
build_property.TargetPlatformMinVersion = 7.0
build_property.UsingMicrosoftNETSdkWeb =
build_property.ProjectTypeGuids =
build_property.InvariantGlobalization =
build_property.PlatformNeutralAssembly =
build_property.EnforceExtendedAnalyzerRules =
build_property.EntryPointFilePath =
build_property._SupportedPlatformList = Linux,macOS,Windows
build_property.RootNamespace = SectionBrepExtractor
build_property.ProjectDir = D:\CSharpProjects\agent4\tools\model-diagnostics\SectionBrepExtractor\
build_property.EnableComHosting =
build_property.EnableGeneratedComInterfaceComImportInterop =
build_property.CsWinRTUseWindowsUIXamlProjections = false
build_property.EffectiveAnalysisLevelStyle = 8.0
build_property.EnableCodeStyleSeverity =
@@ -0,0 +1,8 @@
// <auto-generated/>
global using System;
global using System.Collections.Generic;
global using System.IO;
global using System.Linq;
global using System.Net.Http;
global using System.Threading;
global using System.Threading.Tasks;
@@ -0,0 +1 @@
a03aa3e5815a45196bdfa3c23942adab1219bdb8a32240081bf0dd1471b1a01f
@@ -0,0 +1,46 @@
D:\CSharpProjects\agent4\tools\SectionBrepExtractor\bin\Release\net8.0-windows\SectionBrepExtractor.exe
D:\CSharpProjects\agent4\tools\SectionBrepExtractor\bin\Release\net8.0-windows\SectionBrepExtractor.deps.json
D:\CSharpProjects\agent4\tools\SectionBrepExtractor\bin\Release\net8.0-windows\SectionBrepExtractor.runtimeconfig.json
D:\CSharpProjects\agent4\tools\SectionBrepExtractor\bin\Release\net8.0-windows\SectionBrepExtractor.dll
D:\CSharpProjects\agent4\tools\SectionBrepExtractor\bin\Release\net8.0-windows\SectionBrepExtractor.pdb
D:\CSharpProjects\agent4\tools\SectionBrepExtractor\bin\Release\net8.0-windows\SolidWorks.Interop.sldworks.dll
D:\CSharpProjects\agent4\tools\SectionBrepExtractor\bin\Release\net8.0-windows\SolidWorks.Interop.swconst.dll
D:\CSharpProjects\agent4\tools\SectionBrepExtractor\obj\Release\net8.0-windows\SectionBrepExtractor.csproj.AssemblyReference.cache
D:\CSharpProjects\agent4\tools\SectionBrepExtractor\obj\Release\net8.0-windows\SectionBrepExtractor.GeneratedMSBuildEditorConfig.editorconfig
D:\CSharpProjects\agent4\tools\SectionBrepExtractor\obj\Release\net8.0-windows\SectionBrepExtractor.AssemblyInfoInputs.cache
D:\CSharpProjects\agent4\tools\SectionBrepExtractor\obj\Release\net8.0-windows\SectionBrepExtractor.AssemblyInfo.cs
D:\CSharpProjects\agent4\tools\SectionBrepExtractor\obj\Release\net8.0-windows\SectionBrepExtractor.csproj.CoreCompileInputs.cache
D:\CSharpProjects\agent4\tools\SectionBrepExtractor\obj\Release\net8.0-windows\SectionB.FFBBF4A1.Up2Date
D:\CSharpProjects\agent4\tools\SectionBrepExtractor\obj\Release\net8.0-windows\SectionBrepExtractor.dll
D:\CSharpProjects\agent4\tools\SectionBrepExtractor\obj\Release\net8.0-windows\refint\SectionBrepExtractor.dll
D:\CSharpProjects\agent4\tools\SectionBrepExtractor\obj\Release\net8.0-windows\SectionBrepExtractor.pdb
D:\CSharpProjects\agent4\tools\SectionBrepExtractor\obj\Release\net8.0-windows\SectionBrepExtractor.genruntimeconfig.cache
D:\CSharpProjects\agent4\tools\SectionBrepExtractor\obj\Release\net8.0-windows\ref\SectionBrepExtractor.dll
D:\CSharpProjects\agent4\.tmp\SectionBrepExtractor-build\SectionBrepExtractor.exe
D:\CSharpProjects\agent4\.tmp\SectionBrepExtractor-build\SectionBrepExtractor.deps.json
D:\CSharpProjects\agent4\.tmp\SectionBrepExtractor-build\SectionBrepExtractor.runtimeconfig.json
D:\CSharpProjects\agent4\.tmp\SectionBrepExtractor-build\SectionBrepExtractor.dll
D:\CSharpProjects\agent4\.tmp\SectionBrepExtractor-build\SectionBrepExtractor.pdb
D:\CSharpProjects\agent4\.tmp\build-check\SectionBrepExtractor\SectionBrepExtractor.exe
D:\CSharpProjects\agent4\.tmp\build-check\SectionBrepExtractor\SectionBrepExtractor.deps.json
D:\CSharpProjects\agent4\.tmp\build-check\SectionBrepExtractor\SectionBrepExtractor.runtimeconfig.json
D:\CSharpProjects\agent4\.tmp\build-check\SectionBrepExtractor\SectionBrepExtractor.dll
D:\CSharpProjects\agent4\.tmp\build-check\SectionBrepExtractor\SectionBrepExtractor.pdb
D:\CSharpProjects\agent4\tools\model-diagnostics\SectionBrepExtractor\bin\Release\net8.0-windows\SectionBrepExtractor.exe
D:\CSharpProjects\agent4\tools\model-diagnostics\SectionBrepExtractor\bin\Release\net8.0-windows\SectionBrepExtractor.deps.json
D:\CSharpProjects\agent4\tools\model-diagnostics\SectionBrepExtractor\bin\Release\net8.0-windows\SectionBrepExtractor.runtimeconfig.json
D:\CSharpProjects\agent4\tools\model-diagnostics\SectionBrepExtractor\bin\Release\net8.0-windows\SectionBrepExtractor.dll
D:\CSharpProjects\agent4\tools\model-diagnostics\SectionBrepExtractor\bin\Release\net8.0-windows\SectionBrepExtractor.pdb
D:\CSharpProjects\agent4\tools\model-diagnostics\SectionBrepExtractor\bin\Release\net8.0-windows\SolidWorks.Interop.sldworks.dll
D:\CSharpProjects\agent4\tools\model-diagnostics\SectionBrepExtractor\bin\Release\net8.0-windows\SolidWorks.Interop.swconst.dll
D:\CSharpProjects\agent4\tools\model-diagnostics\SectionBrepExtractor\obj\Release\net8.0-windows\SectionBrepExtractor.csproj.AssemblyReference.cache
D:\CSharpProjects\agent4\tools\model-diagnostics\SectionBrepExtractor\obj\Release\net8.0-windows\SectionBrepExtractor.GeneratedMSBuildEditorConfig.editorconfig
D:\CSharpProjects\agent4\tools\model-diagnostics\SectionBrepExtractor\obj\Release\net8.0-windows\SectionBrepExtractor.AssemblyInfoInputs.cache
D:\CSharpProjects\agent4\tools\model-diagnostics\SectionBrepExtractor\obj\Release\net8.0-windows\SectionBrepExtractor.AssemblyInfo.cs
D:\CSharpProjects\agent4\tools\model-diagnostics\SectionBrepExtractor\obj\Release\net8.0-windows\SectionBrepExtractor.csproj.CoreCompileInputs.cache
D:\CSharpProjects\agent4\tools\model-diagnostics\SectionBrepExtractor\obj\Release\net8.0-windows\SectionB.FFBBF4A1.Up2Date
D:\CSharpProjects\agent4\tools\model-diagnostics\SectionBrepExtractor\obj\Release\net8.0-windows\SectionBrepExtractor.dll
D:\CSharpProjects\agent4\tools\model-diagnostics\SectionBrepExtractor\obj\Release\net8.0-windows\refint\SectionBrepExtractor.dll
D:\CSharpProjects\agent4\tools\model-diagnostics\SectionBrepExtractor\obj\Release\net8.0-windows\SectionBrepExtractor.pdb
D:\CSharpProjects\agent4\tools\model-diagnostics\SectionBrepExtractor\obj\Release\net8.0-windows\SectionBrepExtractor.genruntimeconfig.cache
D:\CSharpProjects\agent4\tools\model-diagnostics\SectionBrepExtractor\obj\Release\net8.0-windows\ref\SectionBrepExtractor.dll
@@ -0,0 +1 @@
c093f8b9ea37fef8e8cdab30c112d4072c7c376c7c3e1dc0dc59d952791a9838
@@ -0,0 +1,81 @@
{
"format": 1,
"restore": {
"D:\\CSharpProjects\\agent4\\tools\\model-diagnostics\\SectionBrepExtractor\\SectionBrepExtractor.csproj": {}
},
"projects": {
"D:\\CSharpProjects\\agent4\\tools\\model-diagnostics\\SectionBrepExtractor\\SectionBrepExtractor.csproj": {
"version": "1.0.0",
"restore": {
"projectUniqueName": "D:\\CSharpProjects\\agent4\\tools\\model-diagnostics\\SectionBrepExtractor\\SectionBrepExtractor.csproj",
"projectName": "SectionBrepExtractor",
"projectPath": "D:\\CSharpProjects\\agent4\\tools\\model-diagnostics\\SectionBrepExtractor\\SectionBrepExtractor.csproj",
"packagesPath": "C:\\Users\\86182\\.nuget\\packages\\",
"outputPath": "D:\\CSharpProjects\\agent4\\tools\\model-diagnostics\\SectionBrepExtractor\\obj\\",
"projectStyle": "PackageReference",
"configFilePaths": [
"C:\\Users\\86182\\AppData\\Roaming\\NuGet\\NuGet.Config",
"C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config"
],
"originalTargetFrameworks": [
"net8.0-windows"
],
"sources": {
"C:\\Program Files (x86)\\Microsoft SDKs\\NuGetPackages\\": {},
"https://api.nuget.org/v3/index.json": {}
},
"frameworks": {
"net8.0-windows": {
"framework": "net8.0-windows7.0",
"targetAlias": "net8.0-windows",
"projectReferences": {}
}
},
"warningProperties": {
"warnAsError": [
"NU1605"
]
},
"restoreAuditProperties": {
"enableAudit": "true",
"auditLevel": "low",
"auditMode": "direct"
},
"SdkAnalysisLevel": "10.0.300"
},
"frameworks": {
"net8.0-windows": {
"framework": "net8.0-windows7.0",
"targetAlias": "net8.0-windows",
"dependencies": {
"SolidWorks.Interop.sldworks": {
"target": "Package",
"version": "[32.1.0, )"
},
"SolidWorks.Interop.swconst": {
"target": "Package",
"version": "[32.1.0, )"
}
},
"imports": [
"net461",
"net462",
"net47",
"net471",
"net472",
"net48",
"net481"
],
"assetTargetFallback": true,
"warn": true,
"frameworkReferences": {
"Microsoft.NETCore.App": {
"privateAssets": "all"
}
},
"runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\10.0.300/PortableRuntimeIdentifierGraph.json"
}
}
}
}
}
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<RestoreSuccess Condition=" '$(RestoreSuccess)' == '' ">True</RestoreSuccess>
<RestoreTool Condition=" '$(RestoreTool)' == '' ">NuGet</RestoreTool>
<ProjectAssetsFile Condition=" '$(ProjectAssetsFile)' == '' ">$(MSBuildThisFileDirectory)project.assets.json</ProjectAssetsFile>
<NuGetPackageRoot Condition=" '$(NuGetPackageRoot)' == '' ">$(UserProfile)\.nuget\packages\</NuGetPackageRoot>
<NuGetPackageFolders Condition=" '$(NuGetPackageFolders)' == '' ">C:\Users\86182\.nuget\packages\</NuGetPackageFolders>
<NuGetProjectStyle Condition=" '$(NuGetProjectStyle)' == '' ">PackageReference</NuGetProjectStyle>
<NuGetToolVersion Condition=" '$(NuGetToolVersion)' == '' ">7.0.0</NuGetToolVersion>
</PropertyGroup>
<ItemGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<SourceRoot Include="C:\Users\86182\.nuget\packages\" />
</ItemGroup>
</Project>
@@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" />
@@ -0,0 +1,133 @@
{
"version": 4,
"targets": {
"net8.0-windows": {
"SolidWorks.Interop.sldworks/32.1.0": {
"type": "package",
"compile": {
"lib/netstandard2.0/SolidWorks.Interop.sldworks.dll": {}
},
"runtime": {
"lib/netstandard2.0/SolidWorks.Interop.sldworks.dll": {}
}
},
"SolidWorks.Interop.swconst/32.1.0": {
"type": "package",
"compile": {
"lib/netstandard2.0/SolidWorks.Interop.swconst.dll": {}
},
"runtime": {
"lib/netstandard2.0/SolidWorks.Interop.swconst.dll": {}
}
}
}
},
"libraries": {
"SolidWorks.Interop.sldworks/32.1.0": {
"sha512": "lq3QmJwBbVE3K+pN5JFSGn1Bj7J1vUyTr4TtT23UAOtd8MXLElZROm9Iee2N8SP8AXsLTpXdBXGs7xYeJT53qw==",
"type": "package",
"path": "solidworks.interop.sldworks/32.1.0",
"files": [
".nupkg.metadata",
".signature.p7s",
"lib/netstandard2.0/SolidWorks.Interop.sldworks.dll",
"solidworks.interop.sldworks.32.1.0.nupkg.sha512",
"solidworks.interop.sldworks.nuspec"
]
},
"SolidWorks.Interop.swconst/32.1.0": {
"sha512": "mOLeWDKf0hX7iSNmdc22FmwoCaqH3KuNhODNGdWuT36KB/maGzQdfU+r9YS97n3mMIdWN3qaLBQ4eJG8z77rMw==",
"type": "package",
"path": "solidworks.interop.swconst/32.1.0",
"files": [
".nupkg.metadata",
".signature.p7s",
"lib/netstandard2.0/SolidWorks.Interop.swconst.dll",
"solidworks.interop.swconst.32.1.0.nupkg.sha512",
"solidworks.interop.swconst.nuspec"
]
}
},
"projectFileDependencyGroups": {
"net8.0-windows": [
"SolidWorks.Interop.sldworks >= 32.1.0",
"SolidWorks.Interop.swconst >= 32.1.0"
]
},
"packageFolders": {
"C:\\Users\\86182\\.nuget\\packages\\": {}
},
"project": {
"version": "1.0.0",
"restore": {
"projectUniqueName": "D:\\CSharpProjects\\agent4\\tools\\model-diagnostics\\SectionBrepExtractor\\SectionBrepExtractor.csproj",
"projectName": "SectionBrepExtractor",
"projectPath": "D:\\CSharpProjects\\agent4\\tools\\model-diagnostics\\SectionBrepExtractor\\SectionBrepExtractor.csproj",
"packagesPath": "C:\\Users\\86182\\.nuget\\packages\\",
"outputPath": "D:\\CSharpProjects\\agent4\\tools\\model-diagnostics\\SectionBrepExtractor\\obj\\",
"projectStyle": "PackageReference",
"configFilePaths": [
"C:\\Users\\86182\\AppData\\Roaming\\NuGet\\NuGet.Config",
"C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config"
],
"originalTargetFrameworks": [
"net8.0-windows"
],
"sources": {
"C:\\Program Files (x86)\\Microsoft SDKs\\NuGetPackages\\": {},
"https://api.nuget.org/v3/index.json": {}
},
"frameworks": {
"net8.0-windows": {
"framework": "net8.0-windows7.0",
"targetAlias": "net8.0-windows",
"projectReferences": {}
}
},
"warningProperties": {
"warnAsError": [
"NU1605"
]
},
"restoreAuditProperties": {
"enableAudit": "true",
"auditLevel": "low",
"auditMode": "direct"
},
"SdkAnalysisLevel": "10.0.300"
},
"frameworks": {
"net8.0-windows": {
"framework": "net8.0-windows7.0",
"targetAlias": "net8.0-windows",
"dependencies": {
"SolidWorks.Interop.sldworks": {
"target": "Package",
"version": "[32.1.0, )"
},
"SolidWorks.Interop.swconst": {
"target": "Package",
"version": "[32.1.0, )"
}
},
"imports": [
"net461",
"net462",
"net47",
"net471",
"net472",
"net48",
"net481"
],
"assetTargetFallback": true,
"warn": true,
"frameworkReferences": {
"Microsoft.NETCore.App": {
"privateAssets": "all"
}
},
"runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\10.0.300/PortableRuntimeIdentifierGraph.json"
}
}
}
}
@@ -0,0 +1,11 @@
{
"version": 2,
"dgSpecHash": "eeRaQVMf0fw=",
"success": true,
"projectFilePath": "D:\\CSharpProjects\\agent4\\tools\\model-diagnostics\\SectionBrepExtractor\\SectionBrepExtractor.csproj",
"expectedPackageFiles": [
"C:\\Users\\86182\\.nuget\\packages\\solidworks.interop.sldworks\\32.1.0\\solidworks.interop.sldworks.32.1.0.nupkg.sha512",
"C:\\Users\\86182\\.nuget\\packages\\solidworks.interop.swconst\\32.1.0\\solidworks.interop.swconst.32.1.0.nupkg.sha512"
],
"logs": []
}