// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "Core/CADEntity.h" #include "Math/Point.h" #include "Topo/TopologicalEntity.h" #include "UI/Message.h" namespace UE::CADKernel { class FTopologicalEdge; class FTopologicalVertex; template class CADKERNEL_API TTopologicalLink : public FTopologicalEntity { friend FEntity; protected: friend EntityType; EntityType* ActiveEntity; TArray TwinEntities; TTopologicalLink() : ActiveEntity(nullptr) { } TTopologicalLink(EntityType& Entity) : ActiveEntity(&Entity) { TwinEntities.Add(&Entity); } public: virtual ~TTopologicalLink() override { TTopologicalLink::Empty(); } virtual void Serialize(FCADKernelArchive& Ar) override { #ifdef CADKERNEL_DEV if (Ar.IsSaving()) { ensureCADKernel(ActiveEntity != nullptr); ensureCADKernel(!ActiveEntity->IsDeleted()); } #endif FEntity::Serialize(Ar); SerializeIdent(Ar, &ActiveEntity, false); SerializeIdents(Ar, TwinEntities, false); } virtual void Empty() override { TwinEntities.Empty(); ActiveEntity = nullptr; } const EntityType* GetActiveEntity() const { ensureCADKernel(ActiveEntity); return ActiveEntity; } EntityType* GetActiveEntity() { ensureCADKernel(ActiveEntity); return ActiveEntity; } int32 GetTwinEntityNum() const { return TwinEntities.Num(); } const TArray& GetTwinEntities() const { return TwinEntities; } void ActivateEntity(const EntityType& NewActiveEntity) { TFunction CheckEntityIsATwin = [&]() { for (EntityType* Entity : TwinEntities) { if (Entity == &NewActiveEntity) { return true; } } FMessage::Error(TEXT("FTopologicalLink::ActivateEntity, the topological entity is not found in the twins entities")); return false; }; ensureCADKernel(CheckEntityIsATwin()); ActiveEntity = &NewActiveEntity; } void RemoveEntity(TSharedPtr& Entity) { EntityType* EntityPtr = *Entity; RemoveEntity(*EntityPtr); } void RemoveEntity(EntityType& Entity) { TwinEntities.Remove(&Entity); if (&Entity == ActiveEntity && TwinEntities.Num() > 0) { ActiveEntity = TwinEntities.HeapTop(); } if (TwinEntities.Num() == 0) { ActiveEntity = nullptr; Delete(); } } //void UnlinkTwinEntities() //{ // for (EntityType* Entity : TwinsEntities) // { // Entity->ResetTopologicalLink(); // } // TwinsEntities.Empty(); //} #ifdef CADKERNEL_DEV virtual FInfoEntity& GetInfo(FInfoEntity& Info) const override; #endif virtual EEntity GetEntityType() const override { return EEntity::EdgeLink; } void AddEntity(EntityType* Entity) { TwinEntities.Add(Entity); } void AddEntity(EntityType& Entity) { TwinEntities.Add(&Entity); } template void AddEntity(const LinkableType* Entity) { TwinEntities.Add((EntityType*)Entity); } template void AddEntities(const ArrayType& Entities) { TwinEntities.Insert(Entities, TwinEntities.Num()); } /** * @return true if the Twin entity count link is modified */ virtual bool CleanLink() { TArray NewTwinsEntities; NewTwinsEntities.Reserve(TwinEntities.Num()); for (EntityType* Entity : TwinEntities) { if (Entity) { NewTwinsEntities.Add(Entity); } } if (NewTwinsEntities.Num() != TwinEntities.Num()) { Swap(NewTwinsEntities, TwinEntities); if (TwinEntities.Num()) { ActiveEntity = TwinEntities.HeapTop(); return true; } } return false; } void ResetMarkersRecursively() const { for (EntityType* Entity : TwinEntities) { if (Entity) { Entity->ResetMarkers(); } } } }; } // namespace UE::CADKernel