/// <summary> /// Merges the <paramref name="other"/> hierarchy into this hierarchy. /// </summary> /// <remarks> /// This method does not check whether the two hierarchies have independent parts and will fail otherwise. /// </remarks> /// <typeparam name="TAssetPartDesign">The type used for the design information of a part.</typeparam> /// <typeparam name="TAssetPart">The type used for the actual parts,</typeparam> /// <param name="asset">This hierarchy.</param> /// <param name="other">The other hierarchy which parts will added to this hierarchy.</param> public static void MergeInto <TAssetPartDesign, TAssetPart>([NotNull] this AssetCompositeHierarchyData <TAssetPartDesign, TAssetPart> asset, [NotNull] AssetCompositeHierarchyData <TAssetPartDesign, TAssetPart> other) where TAssetPartDesign : class, IAssetPartDesign <TAssetPart> where TAssetPart : class, IIdentifiable { if (asset == null) { throw new ArgumentNullException(nameof(asset)); } asset.RootParts.AddRange(other.RootParts); foreach (var part in other.Parts) { asset.Parts.Add(part.Value); } }
/// <summary> /// Clones a sub-hierarchy of this asset. /// </summary> /// <param name="sourceRootIds">The ids that are the roots of the sub-hierarchies to clone.</param> /// <param name="cleanReference">If true, any reference to a part external to the cloned hierarchy will be set to null.</param> /// <param name="idRemapping">A dictionary containing the mapping of ids from the source parts to the new parts.</param> /// <returns>A <see cref="AssetCompositeHierarchyData{TAssetPartDesign, TAssetPart}"/> corresponding to the cloned parts.</returns> /// <remarks>The parts passed to this methods must be independent in the hierarchy.</remarks> public AssetCompositeHierarchyData <TAssetPartDesign, TAssetPart> CloneSubHierarchies(IEnumerable <Guid> sourceRootIds, bool cleanReference, out Dictionary <Guid, Guid> idRemapping) { // Note: Instead of copying the whole asset (with its potentially big hierarchy), // we first copy the asset only (without the hierarchy), then the sub-hierarchy to extract. var subTreeHierarchy = new AssetCompositeHierarchyData <TAssetPartDesign, TAssetPart>(); foreach (var rootId in sourceRootIds) { if (!Hierarchy.Parts.ContainsKey(rootId)) { throw new ArgumentException(@"The source root parts must be parts of this asset.", nameof(sourceRootIds)); } subTreeHierarchy.RootPartIds.Add(rootId); subTreeHierarchy.Parts.Add(Hierarchy.Parts[rootId]); foreach (var subTreePart in EnumerateChildParts(Hierarchy.Parts[rootId].Part, true)) { subTreeHierarchy.Parts.Add(Hierarchy.Parts[subTreePart.Id]); } } // clone the parts of the sub-tree var clonedHierarchy = AssetCloner.Clone(subTreeHierarchy); foreach (var rootEntity in clonedHierarchy.RootPartIds) { PostClonePart(clonedHierarchy.Parts[rootEntity].Part); } if (cleanReference) { ClearPartReferences(clonedHierarchy); } // Generate part mapping idRemapping = new Dictionary <Guid, Guid>(); foreach (var partDesign in clonedHierarchy.Parts) { // Generate new Id var newId = Guid.NewGuid(); // Update mappings idRemapping.Add(partDesign.Part.Id, newId); // Update part with new id partDesign.Part.Id = newId; } // Rewrite part references // Should we nullify invalid references? AssetPartsAnalysis.RemapPartsId(clonedHierarchy, idRemapping); return(clonedHierarchy); }
public AssetCompositeHierarchyData <TAssetPartDesign, TAssetPart> GenerateHierarchyFromPart([NotNull] TAssetPartDesign partDesign) { if (partDesign == null) { throw new ArgumentNullException(nameof(partDesign)); } var result = new AssetCompositeHierarchyData <TAssetPartDesign, TAssetPart>(); foreach (var child in EnumerateChildParts(partDesign, Hierarchy, true)) { result.Parts.Add(child); } result.Parts.Add(partDesign); result.RootPartIds.Add(partDesign.Part.Id); return(result); }
/// <summary> /// Enumerates design parts that are children of the given design part. /// </summary> /// <param name="partDesign">The design part for which to enumerate child parts.</param> /// <param name="hierarchyData">The hierarchy data object in which the design parts can be retrieved.</param> /// <param name="isRecursive">If true, child design parts will be enumerated recursively.</param> /// <returns>A sequence containing the child design parts of the given design part.</returns> public IEnumerable<TAssetPartDesign> EnumerateChildParts(TAssetPartDesign partDesign, AssetCompositeHierarchyData<TAssetPartDesign, TAssetPart> hierarchyData, bool isRecursive) { return EnumerateChildParts(partDesign.Part, isRecursive).Select(e => hierarchyData.Parts[e.Id]); }
/// <summary> /// Clones a sub-hierarchy of this asset. /// </summary> /// <param name="sourceRootIds">The ids that are the roots of the sub-hierarchies to clone.</param> /// <param name="cleanReference">If true, any reference to a part external to the cloned hierarchy will be set to null.</param> /// <param name="generateNewIdsForIdentifiableObjects">If true, the cloned objects that implement <see cref="IIdentifiable"/> will have new ids.</param> /// <param name="idRemapping">A dictionary containing the remapping of <see cref="IIdentifiable.Id"/> if <see cref="AssetClonerFlags.GenerateNewIdsForIdentifiableObjects"/> has been passed to the cloner.</param> /// <returns>A <see cref="AssetCompositeHierarchyData{TAssetPartDesign, TAssetPart}"/> corresponding to the cloned parts.</returns> /// <remarks>The parts passed to this methods must be independent in the hierarchy.</remarks> public AssetCompositeHierarchyData <TAssetPartDesign, TAssetPart> CloneSubHierarchies(IEnumerable <Guid> sourceRootIds, bool cleanReference, bool generateNewIdsForIdentifiableObjects, bool generateNewBaseInstanceIds, out Dictionary <Guid, Guid> idRemapping) { // Note: Instead of copying the whole asset (with its potentially big hierarchy), // we first copy the asset only (without the hierarchy), then the sub-hierarchy to extract. var subTreeHierarchy = new AssetCompositeHierarchyData <TAssetPartDesign, TAssetPart>(); foreach (var rootId in sourceRootIds) { if (!Hierarchy.Parts.ContainsKey(rootId)) { throw new ArgumentException(@"The source root parts must be parts of this asset.", nameof(sourceRootIds)); } subTreeHierarchy.RootPartIds.Add(rootId); subTreeHierarchy.Parts.Add(Hierarchy.Parts[rootId]); foreach (var subTreePart in EnumerateChildParts(Hierarchy.Parts[rootId].Part, true)) { subTreeHierarchy.Parts.Add(Hierarchy.Parts[subTreePart.Id]); } } // clone the parts of the sub-tree var clonedHierarchy = AssetCloner.Clone(subTreeHierarchy, generateNewIdsForIdentifiableObjects ? AssetClonerFlags.GenerateNewIdsForIdentifiableObjects : AssetClonerFlags.None, out idRemapping); // Remap ids from the root id collection to the new ids generated during cloning AssetPartsAnalysis.RemapPartsId(clonedHierarchy, idRemapping); foreach (var rootEntity in clonedHierarchy.RootPartIds) { PostClonePart(clonedHierarchy.Parts[rootEntity].Part); } if (cleanReference) { // set to null reference outside of the sub-tree var tempAsset = (AssetCompositeHierarchy <TAssetPartDesign, TAssetPart>)Activator.CreateInstance(GetType()); tempAsset.Hierarchy = clonedHierarchy; tempAsset.FixupPartReferences(); } else { // restore initial ids for reference outside of the subtree, so they can be fixed up later. var tempAsset = (AssetCompositeHierarchy <TAssetPartDesign, TAssetPart>)Activator.CreateInstance(GetType()); tempAsset.Hierarchy = clonedHierarchy; var visitor = new AssetCompositePartReferenceCollector(); visitor.VisitAsset(tempAsset); var references = visitor.Result; var revertedIdMapping = idRemapping.ToDictionary(x => x.Value, x => x.Key); foreach (var referencedPart in references.Select(x => x.AssetPart).OfType <IIdentifiable>()) { var realPart = tempAsset.ResolvePartReference(referencedPart); if (realPart == null) { referencedPart.Id = revertedIdMapping[referencedPart.Id]; } } } if (generateNewBaseInstanceIds) { AssetPartsAnalysis.GenerateNewBaseInstanceIds(clonedHierarchy); } return(clonedHierarchy); }
/// <summary> /// Clears the part references on the cloned hierarchy. Called by <see cref="CloneSubHierarchies"/> when parameter <i>cleanReference</i> is <c>true</c>. /// </summary> /// <param name="clonedHierarchy">The cloned hierarchy.</param> protected virtual void ClearPartReferences(AssetCompositeHierarchyData <TAssetPartDesign, TAssetPart> clonedHierarchy) { // default implementation does nothing }
public static IEnumerable <TAssetPartDesign> EnumerateRootPartDesigns <TAssetPartDesign, TAssetPart>([NotNull] this AssetCompositeHierarchyData <TAssetPartDesign, TAssetPart> asset) where TAssetPartDesign : class, IAssetPartDesign <TAssetPart> where TAssetPart : class, IIdentifiable { if (asset == null) { throw new ArgumentNullException(nameof(asset)); } return(asset.RootParts.Select(x => asset.Parts[x.Id])); }