Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
ModelNodePath.cs
Go to the documentation of this file.
1 // Copyright (c) 2014 Silicon Studio Corp. (http://siliconstudio.co.jp)
2 // This file is distributed under GPL v3. See LICENSE.md for details.
3 using System;
4 using System.Collections.Generic;
5 using System.Linq;
6 
7 using SiliconStudio.Quantum.References;
8 
9 namespace SiliconStudio.Quantum
10 {
11  /// <summary>
12  /// A class describing the path of a node, relative to a root node. The path can cross references, array, etc.
13  /// </summary>
14  public class ModelNodePath
15  {
16  private class NodePathItemIndex
17  {
18  public object Value;
19  public override string ToString() { return string.Format("[{0}]", Value); }
20  }
21 
22  private class NodePathItemMember
23  {
24  public string Name;
25  public override string ToString() { return string.Format(".{0}", Name); } }
26 
27  private class NodePathItemTarget
28  {
29  public override string ToString() { return "-> (Target)"; }
30  }
31 
32  private readonly List<object> path = new List<object>();
33  private bool targetIsRootNode;
34 
35  private ModelNodePath()
36  {
37  }
38 
39  /// <summary>
40  /// Gets whether this path is a valid path.
41  /// </summary>
42  public bool IsValid { get { return path.Count > 0 || targetIsRootNode; } }
43 
44  /// <summary>
45  /// Gets the root node of this path.
46  /// </summary>
47  public IModelNode RootNode { get; private set; }
48 
49  /// <summary>
50  /// Gets the node corresponding to this path.
51  /// </summary>
52  /// <returns>The node corresponding to this path.</returns>
53  /// <exception cref="InvalidOperationException">The path is invalid.</exception>
55  {
56  if (!IsValid)
57  throw new InvalidOperationException("The node path is invalid.");
58 
59  IModelNode node = RootNode;
60  foreach (var itemPath in path)
61  {
62  var member = itemPath as NodePathItemMember;
63  var target = itemPath as NodePathItemTarget;
64  var index = itemPath as NodePathItemIndex;
65  if (member != null)
66  {
67  node = node.Children.Single(x => x.Name == member.Name);
68  }
69  else if (target != null)
70  {
71  var objectRefererence = (ObjectReference)node.Content.Reference;
72  node = objectRefererence.TargetNode;
73  }
74  else if (index != null)
75  {
76  var enumerableReference = (ReferenceEnumerable)node.Content.Reference;
77  var objectRefererence = enumerableReference.Single(x => Equals(x.Index, index.Value));
78  node = objectRefererence.TargetNode;
79  }
80  }
81  return node;
82  }
83 
84  /// <summary>
85  /// Gets a new instance of <see cref="ModelNodePath"/> corresponding to the path of the given target node relative to the given root node.
86  /// </summary>
87  /// <param name="rootNode">The root node of the path.</param>
88  /// <param name="target">The target node of the path.</param>
89  /// <returns>A new instance of the <see cref="ModelNodePath"/>. This instance may not be valid if no path lead to the target node from the root node.</returns>
90  public static ModelNodePath GetPath(IModelNode rootNode, IModelNode target)
91  {
92  var visitedNode = new HashSet<IModelNode>();
93  var result = GetPathRecursive(rootNode, target, visitedNode);
94  if (result != null)
95  {
96  result.RootNode = rootNode;
97  result.targetIsRootNode = rootNode == target;
98  }
99  return result;
100  }
101 
102  /// <inheritdoc/>
103  public override string ToString()
104  {
105  return IsValid ? "(root)" + path.Select(x => x.ToString()).Aggregate((current, next) => current + next) : "(invalid)";
106  }
107 
108  private void Prepend(object item)
109  {
110  path.Insert(0, item);
111  }
112 
113  private static ModelNodePath GetPathRecursive(IModelNode modelNode, IModelNode target, ICollection<IModelNode> visitedNode)
114  {
115  var member = modelNode.Children.Where(x => !visitedNode.Contains(x)).FirstOrDefault(x => x == target);
116  var objectReference = modelNode.Content.Reference as ObjectReference;
117  var enumerableReference = modelNode.Content.Reference as ReferenceEnumerable;
118  var result = new ModelNodePath();
119 
120  visitedNode.Add(modelNode);
121 
122  if (member != null)
123  {
124  // The target is a direct member of the ModelNode
125  result.path.Add(new NodePathItemMember { Name = member.Name });
126  }
127  else if (objectReference != null && objectReference.TargetNode != null)
128  {
129  // The target is the TargetNode of the ObjectReference contained in the ModelNode
130  if (objectReference.TargetNode != target)
131  result = GetPathRecursive(objectReference.TargetNode, target, visitedNode);
132 
133  if (result.IsValid || target == objectReference.TargetNode)
134  {
135  result.Prepend(new NodePathItemTarget());
136  }
137  }
138  else if (enumerableReference != null)
139  {
140  foreach (ObjectReference reference in enumerableReference.Where(x => x.TargetNode != null))
141  {
142  if (target != reference.TargetNode)
143  result = GetPathRecursive(reference.TargetNode, target, visitedNode);
144 
145  if (result.IsValid || target == reference.TargetNode)
146  {
147  // The target is the TargetNode of an item of the ReferenceEnumerable contained in the ModelNode
148  result.Prepend(new NodePathItemIndex { Value = reference.Index });
149  break;
150  }
151  }
152  }
153  else
154  {
155  // The target is not directly accessible. Let's invoke this method recursively on each of the child of the ModelNode
156  foreach (var child in modelNode.Children.Where(x => !visitedNode.Contains(x)))
157  {
158  result = GetPathRecursive(child, target, visitedNode);
159  if (result.IsValid)
160  {
161  result.Prepend(new NodePathItemMember { Name = child.Name });
162  break;
163  }
164  }
165  }
166  return result;
167  }
168  }
169 }
_Use_decl_annotations_ bool IsValid(DXGI_FORMAT fmt)
Definition: DirectXTex.inl:25
static ModelNodePath GetPath(IModelNode rootNode, IModelNode target)
Gets a new instance of ModelNodePath corresponding to the path of the given target node relative to t...
IContent Content
Gets the content of the IModelNode.
Definition: IModelNode.cs:41
A class representing an enumeration of references to multiple objects.
IModelNode GetNode()
Gets the node corresponding to this path.
IModelNode TargetNode
Gets the model node targeted by this reference, if available.
A class representing a reference to another object that has a different model.
The IModelNode interface represents a node in a model object. A model object is represented by a grap...
Definition: IModelNode.cs:16
A class describing the path of a node, relative to a root node. The path can cross references...