/
Instance.cs
164 lines (144 loc) · 4.52 KB
/
Instance.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
using System;
using System.Collections.Generic;
using System.Linq;
using Objects.Geometry;
using Speckle.Core.Kits;
using Speckle.Core.Models;
using Speckle.Core.Models.GraphTraversal;
using Speckle.Newtonsoft.Json;
namespace Objects.Other;
public abstract class Instance : Base
{
protected Instance(Transform transform)
{
this.transform = transform ?? new Transform();
}
protected Instance() { }
/// <summary>
/// The column-dominant 4x4 transform of this instance.
/// </summary>
/// <remarks>
/// Indicates transform from internal origin [0,0,0]
/// </remarks>
public Transform transform { get; set; }
public abstract Base definition { get; internal set; }
/// <summary>
/// The units of this Instance, should be the same as the instance transform units
/// </summary>
public string units { get; set; }
// helper method that scans an Instance for all transformable geometry and nested instances
protected virtual IEnumerable<Base> GetTransformableGeometry()
{
var displayValueRule = TraversalRule
.NewTraversalRule()
.When(DefaultTraversal.HasDisplayValue)
.ContinueTraversing(_ => DefaultTraversal.DisplayValueAndElementsPropAliases);
var instanceRule = TraversalRule
.NewTraversalRule()
.When(b => b is Instance instance && instance != null)
.ContinueTraversing(DefaultTraversal.None);
var traversal = new GraphTraversal(instanceRule, displayValueRule, DefaultTraversal.DefaultRule);
return traversal
.Traverse(definition)
.Select(tc => tc.Current)
.Where(b => b is ITransformable || b is Instance)
.Where(b => b != null);
}
[SchemaComputed("transformedGeometry")]
public virtual IEnumerable<ITransformable> GetTransformedGeometry()
{
return GetTransformableGeometry()
.SelectMany(b =>
{
switch (b)
{
case Instance i:
return i.GetTransformedGeometry()
.Select(b =>
{
b.TransformTo(transform, out var tranformed);
return tranformed;
});
case ITransformable bt:
var res = bt.TransformTo(transform, out var transformed);
return res ? new List<ITransformable> { transformed } : new();
default:
return new List<ITransformable>();
}
})
.Where(b => b != null);
}
}
/// <summary>
/// Generic instance class
/// </summary>
public abstract class Instance<T> : Instance
where T : Base
{
protected Instance(T definition, Transform transform)
: base(transform)
{
typedDefinition = definition;
}
protected Instance()
: base(new Transform()) { }
[JsonIgnore]
public T typedDefinition { get; set; }
[DetachProperty]
public override Base definition
{
get => typedDefinition;
internal set
{
if (value is T type)
{
typedDefinition = type;
}
}
}
}
/// <summary>
/// Block instance class
/// </summary>
public class BlockInstance : Instance<BlockDefinition>
{
public BlockInstance() { }
[SchemaInfo("Block Instance", "A Speckle Block Instance")]
public BlockInstance(BlockDefinition blockDefinition, Transform transform)
: base(blockDefinition, transform)
{
// OLD: TODO: need to verify
// Add base translation to transform. This assumes the transform is based on the world origin,
// whereas the instance transform assumes it contains the basePoint translation already.
//this.transform = transform * blockDefinition.GetBasePointTransform();
}
[DetachProperty, Obsolete("Use definition property", true), JsonIgnore]
public BlockDefinition blockDefinition
{
get => typedDefinition;
set => typedDefinition = value;
}
protected override IEnumerable<Base> GetTransformableGeometry()
{
return typedDefinition.geometry;
}
/// <summary>
/// Returns a plane representing the insertion point and orientation of this Block instance.
/// </summary>
/// <remarks>This method will skip scaling. If you need scaling, we recommend using the transform instead.</remarks>
/// <returns>A Plane on the insertion point of this Block Instance, with the correct 3-axis rotations.</returns>
[SchemaComputed("insertionPlane")]
public Plane GetInsertionPlane()
{
// TODO: UPDATE!
var plane = new Plane(
typedDefinition.basePoint ?? new Point(0, 0, 0, units),
new Vector(0, 0, 1, units),
new Vector(1, 0, 0, units),
new Vector(0, 1, 0, units),
units
);
plane.TransformTo(transform, out Plane tPlane);
return tPlane;
}
}