// Copyright Epic Games, Inc. All Rights Reserved. #include "Topo/Model.h" #include "Core/EntityGeom.h" #include "Topo/Body.h" #include "Topo/TopologicalEdge.h" #include "Topo/TopologicalFace.h" #include "Topo/TopologicalVertex.h" #ifdef CADKERNEL_DEV #include "Topo/TopologyReport.h" #endif namespace UE::CADKernel { void FModel::AddEntity(TSharedRef Entity) { switch (Entity->GetEntityType()) { case EEntity::Body: Add(StaticCastSharedRef(Entity)); break; default: break; } } bool FModel::Contains(TSharedPtr Entity) { switch(Entity->GetEntityType()) { case EEntity::Body: return Bodies.Find(StaticCastSharedPtr(Entity)) != INDEX_NONE; default: return false; } } void FModel::PrintBodyAndShellCount() { int32 NbBody = 0; int32 NbShell = 0; TArray> NewBodies; for (TSharedPtr Body : Bodies) { NbShell += Body->GetShells().Num(); NbBody++; } FMessage::Printf(Log, TEXT("Body count %d shell count %d \n"), NbBody, NbShell); } int32 FModel::FaceCount() const { int32 FaceCount = 0; for (const TSharedPtr& Body : Bodies) { FaceCount += Body->FaceCount(); } return FaceCount; } void FModel::RemoveEmptyBodies() { TArray> NewBodies; NewBodies.Reserve(Bodies.Num()); for (const TSharedPtr& Body : Bodies) { if (!Body->IsDeleted() && Body->ShellCount()) { NewBodies.Add(Body); } else { Body->Delete(); Body->ResetHost(); } } Bodies = MoveTemp(NewBodies); } void FModel::GetFaces(TArray& OutFaces) { for (const TSharedPtr& Body : Bodies) { Body->GetFaces(OutFaces); } } void FModel::PropagateBodyOrientation() { for (TSharedPtr& Body : Bodies) { Body->PropagateBodyOrientation(); } } void FModel::CompleteMetaData() { for (TSharedPtr& Body : Bodies) { Body->CompleteMetaData(); } } struct FBodyShell { TSharedPtr Body; TSharedPtr Shell; FBodyShell(TSharedPtr InBody, TSharedPtr InShell) : Body(InBody) , Shell(InShell) { } }; void FModel::CheckTopology() { TArray IsolatedBodies; IsolatedBodies.Reserve(Bodies.Num()*2); int32 ShellCount = 0; for (TSharedPtr Body : Bodies) { for (TSharedPtr Shell : Body->GetShells()) { ShellCount++; TArray SubShells; Shell->CheckTopology(SubShells); if (SubShells.Num() == 1 ) { if (Shell->FaceCount() < 3 ) { IsolatedBodies.Emplace(Body, Shell); } else { if (SubShells[0].BorderEdgeCount > 0 || SubShells[0].NonManifoldEdgeCount > 0) { #ifdef CORETECHBRIDGE_DEBUG FMessage::Printf(Log, TEXT("Body %d shell %d CADId %d is opened and has %d faces "), Body->GetKioId(), Shell->GetKioId(), Shell->GetId(), Shell->FaceCount()); #else FMessage::Printf(Log, TEXT("Body %d shell %d is opened and has %d faces "), Body->GetId(), Shell->GetId(), Shell->FaceCount()); #endif FMessage::Printf(Log, TEXT("and has %d border edges and %d nonManifold edges\n"), SubShells[0].BorderEdgeCount, SubShells[0].NonManifoldEdgeCount); } else { #ifdef CORETECHBRIDGE_DEBUG FMessage::Printf(Log, TEXT("Body %d shell %d CADId %d is closed and has %d faces\n"), Body->GetKioId(), Shell->GetKioId(), Shell->GetId(), Shell->FaceCount()); #else FMessage::Printf(Log, TEXT("Body %d shell %d is closed and has %d faces\n"), Body->GetId(), Shell->GetId(), Shell->FaceCount()); #endif } } } else { #ifdef CORETECHBRIDGE_DEBUG FMessage::Printf(Log, TEXT("Body %d shell %d CADId %d has %d subshells\n"), Body->GetKioId(), Shell->GetKioId(), Shell->GetId(), SubShells.Num()); #else FMessage::Printf(Log, TEXT("Body %d shell %d has %d subshells\n"), Body->GetId(), Shell->GetId(), SubShells.Num()); #endif for (const FFaceSubset& Subset : SubShells) { FMessage::Printf(Log, TEXT(" - Subshell of %d faces %d border edges and %d nonManifold edges\n"), Subset. Faces.Num(), Subset.BorderEdgeCount, Subset.NonManifoldEdgeCount); } } } } } #ifdef CADKERNEL_DEV void FModel::FillTopologyReport(FTopologyReport& Report) const { for (TSharedPtr Body : Bodies) { Body->FillTopologyReport(Report); } Report.ResetMarkers(); } #endif void FModel::Orient() { for (TSharedPtr Body : Bodies) { Body->Orient(); } } }