Compare commits
59 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2101a9831b | |||
| 64d1091b79 | |||
| a411aaa3f0 | |||
| 640cc92641 | |||
| ef9c23f7de | |||
| 04bd151da3 | |||
| edf3555289 | |||
| 03c1d4ed32 | |||
| b17f4b02aa | |||
| 03a780ffd5 | |||
| b1240cfbe8 | |||
| fed185fbed | |||
| 11212c946a | |||
| 2eee9561b4 | |||
| b221a69f76 | |||
| 6b0ed5c075 | |||
| da31864192 | |||
| f6239d279f | |||
| 7aff696bae | |||
| 371722f28c | |||
| d25c40bcd6 | |||
| 913acc7707 | |||
| 1d83c98077 | |||
| 2c2a7929bf | |||
| 5335329719 | |||
| cc010c8cc8 | |||
| 80b136b934 | |||
| e8f61f8dbf | |||
| bf2099f8a6 | |||
| f7f31263a6 | |||
| b8f65d4ade | |||
| 96b2eb1832 | |||
| b972a2f8bd | |||
| c504848e0b | |||
| 7d88e39272 | |||
| 82adf0e20e | |||
| 66de3f978a | |||
| 9031950868 | |||
| 4cef9efd51 | |||
| a40e9495e5 | |||
| afd59df48a | |||
| 42c3ca1ec3 | |||
| 44105d7d75 | |||
| 2aad40bd0a | |||
| d0058d7ee5 | |||
| 38c9077831 | |||
| 904e7ece88 | |||
| 267799d916 | |||
| 2eb872b5e5 | |||
| ce9a2c8807 | |||
| 729d1a4698 | |||
| 4f74328ffc | |||
| 54370f3188 | |||
| 4a51eae628 | |||
| 34241385f9 | |||
| 7ec01ed39f | |||
| 1ff861f9db | |||
| 4c125afd7b | |||
| e561980e7f |
@@ -314,6 +314,9 @@ dotnet_diagnostic.NUnit2037.severity = warning # Consider using Assert.That(coll
|
||||
dotnet_diagnostic.NUnit2038.severity = warning # Consider using Assert.That(actual, Is.InstanceOf(expected)) instead of Assert.IsInstanceOf(expected, actual)
|
||||
dotnet_diagnostic.NUnit2039.severity = warning # Consider using Assert.That(actual, Is.Not.InstanceOf(expected)) instead of Assert.IsNotInstanceOf(expected, actual)
|
||||
|
||||
# note: added to allow the copy paste from rhino inside of the ValueSet component
|
||||
dotnet_diagnostic.CA1033.severity = none
|
||||
|
||||
[*.{appxmanifest,asax,ascx,aspx,axaml,build,c,c++,cc,cginc,compute,cp,cpp,cs,cshtml,cu,cuh,cxx,dtd,fs,fsi,fsscript,fsx,fx,fxh,h,hh,hlsl,hlsli,hlslinc,hpp,hxx,inc,inl,ino,ipp,ixx,master,ml,mli,mpp,mq4,mq5,mqh,nuspec,paml,razor,resw,resx,shader,skin,tpp,usf,ush,vb,xaml,xamlx,xoml,xsd}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
@@ -132,11 +132,6 @@
|
||||
"Microsoft.Extensions.Configuration": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Options": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
@@ -287,6 +282,12 @@
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Logging": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[2.2.0, )",
|
||||
|
||||
@@ -130,11 +130,6 @@
|
||||
"Microsoft.Extensions.Configuration": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Options": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
@@ -306,6 +301,12 @@
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Logging": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[2.2.0, )",
|
||||
|
||||
@@ -130,11 +130,6 @@
|
||||
"Microsoft.Extensions.Configuration": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Options": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
@@ -306,6 +301,12 @@
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Logging": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[2.2.0, )",
|
||||
|
||||
@@ -130,11 +130,6 @@
|
||||
"Microsoft.Extensions.Configuration": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Options": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
@@ -307,6 +302,12 @@
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Logging": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[2.2.0, )",
|
||||
|
||||
@@ -121,11 +121,6 @@
|
||||
"Microsoft.Extensions.Configuration": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Options": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
@@ -263,6 +258,12 @@
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Logging": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[2.2.0, )",
|
||||
|
||||
@@ -139,11 +139,6 @@
|
||||
"Microsoft.Extensions.Configuration": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Options": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
@@ -316,6 +311,12 @@
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Logging": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[2.2.0, )",
|
||||
|
||||
@@ -139,11 +139,6 @@
|
||||
"Microsoft.Extensions.Configuration": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Options": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
@@ -316,6 +311,12 @@
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Logging": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[2.2.0, )",
|
||||
|
||||
@@ -139,11 +139,6 @@
|
||||
"Microsoft.Extensions.Configuration": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Options": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
@@ -316,6 +311,12 @@
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Logging": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[2.2.0, )",
|
||||
|
||||
@@ -130,11 +130,6 @@
|
||||
"Microsoft.Extensions.Configuration": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Options": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
@@ -273,6 +268,12 @@
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Logging": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[2.2.0, )",
|
||||
|
||||
@@ -130,11 +130,6 @@
|
||||
"Microsoft.Extensions.Configuration": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Options": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
@@ -305,6 +300,12 @@
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Logging": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[2.2.0, )",
|
||||
|
||||
@@ -121,11 +121,6 @@
|
||||
"Microsoft.Extensions.Configuration": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Options": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
@@ -261,6 +256,12 @@
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Logging": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[2.2.0, )",
|
||||
|
||||
@@ -130,11 +130,6 @@
|
||||
"Microsoft.Extensions.Configuration": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Options": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
@@ -307,6 +302,12 @@
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Logging": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[2.2.0, )",
|
||||
|
||||
@@ -130,11 +130,6 @@
|
||||
"Microsoft.Extensions.Configuration": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Options": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
@@ -307,6 +302,12 @@
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Logging": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[2.2.0, )",
|
||||
|
||||
@@ -130,11 +130,6 @@
|
||||
"Microsoft.Extensions.Configuration": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Options": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
@@ -307,6 +302,12 @@
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Logging": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[2.2.0, )",
|
||||
|
||||
@@ -130,11 +130,6 @@
|
||||
"Microsoft.Extensions.Configuration": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Options": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
@@ -307,6 +302,12 @@
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Logging": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[2.2.0, )",
|
||||
|
||||
@@ -130,11 +130,6 @@
|
||||
"Microsoft.Extensions.Configuration": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Options": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
@@ -307,6 +302,12 @@
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Logging": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[2.2.0, )",
|
||||
|
||||
@@ -136,11 +136,6 @@
|
||||
"Microsoft.Extensions.Configuration": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Options": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
@@ -313,6 +308,12 @@
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Logging": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[2.2.0, )",
|
||||
|
||||
@@ -158,11 +158,6 @@
|
||||
"Microsoft.Extensions.Configuration": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Options": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
@@ -327,6 +322,12 @@
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Logging": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[2.2.0, )",
|
||||
|
||||
@@ -158,11 +158,6 @@
|
||||
"Microsoft.Extensions.Configuration": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Options": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
@@ -327,6 +322,12 @@
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Logging": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[2.2.0, )",
|
||||
|
||||
@@ -158,11 +158,6 @@
|
||||
"Microsoft.Extensions.Configuration": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Options": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
@@ -327,6 +322,12 @@
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Logging": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[2.2.0, )",
|
||||
|
||||
@@ -143,11 +143,6 @@
|
||||
"Microsoft.Extensions.Configuration": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Options": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
@@ -277,6 +272,12 @@
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Logging": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[2.2.0, )",
|
||||
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Speckle.Connectors.Grasshopper8.Registration;
|
||||
|
||||
namespace Speckle.Connectors.Grasshopper8.Components.BaseComponents;
|
||||
|
||||
public abstract class SpeckleScopedTaskCapableComponent<TInput, TOutput>(
|
||||
string name,
|
||||
string nickname,
|
||||
string description,
|
||||
string category,
|
||||
string subCategory
|
||||
) : SpeckleTaskCapableComponent<TInput, TOutput>(name, nickname, description, category, subCategory)
|
||||
{
|
||||
protected override Task<TOutput> PerformTask(TInput input, CancellationToken cancellationToken = default)
|
||||
{
|
||||
/*using*/var scope = PriorityLoader.Container.CreateScope(); // NOTE: this component does not work as intended in e.g the receive component; the scope gets disposed before the task completes.
|
||||
return PerformScopedTask(input, scope, cancellationToken);
|
||||
}
|
||||
|
||||
protected abstract Task<TOutput> PerformScopedTask(
|
||||
TInput input,
|
||||
IServiceScope scope,
|
||||
CancellationToken cancellationToken = default
|
||||
);
|
||||
}
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
using Grasshopper.Kernel;
|
||||
using Speckle.Sdk;
|
||||
|
||||
namespace Speckle.Connectors.Grasshopper8.Components.BaseComponents;
|
||||
|
||||
public abstract class SpeckleTaskCapableComponent<TInput, TOutput>(
|
||||
string name,
|
||||
string nickname,
|
||||
string description,
|
||||
string category,
|
||||
string subCategory
|
||||
) : GH_TaskCapableComponent<TOutput>(name, nickname, description, category, subCategory)
|
||||
{
|
||||
protected override void SolveInstance(IGH_DataAccess da)
|
||||
{
|
||||
//TODO: We're missing activity and logging here. Will enable it for all inherited classes.
|
||||
|
||||
if (InPreSolve)
|
||||
{
|
||||
// Collect the data and create the task
|
||||
try
|
||||
{
|
||||
var input = GetInput(da);
|
||||
TaskList.Add(PerformTask(input, CancelToken));
|
||||
}
|
||||
catch (SpeckleException e)
|
||||
{
|
||||
Console.WriteLine(e);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!GetSolveResults(da, out TOutput result))
|
||||
{
|
||||
// INFO: This will run synchronously. Useful for Rhino.Compute runs, but can also be enabled by user.
|
||||
try
|
||||
{
|
||||
TInput input = GetInput(da);
|
||||
var syncResult = PerformTask(input).Result;
|
||||
result = syncResult;
|
||||
}
|
||||
catch (SpeckleException e)
|
||||
{
|
||||
Console.WriteLine(e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (result is not null)
|
||||
{
|
||||
SetOutput(da, result);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract TInput GetInput(IGH_DataAccess da);
|
||||
|
||||
protected abstract void SetOutput(IGH_DataAccess da, TOutput result);
|
||||
|
||||
protected abstract Task<TOutput> PerformTask(TInput input, CancellationToken cancellationToken = default);
|
||||
}
|
||||
+1860
File diff suppressed because it is too large
Load Diff
+71
@@ -0,0 +1,71 @@
|
||||
using Grasshopper.Kernel.Types;
|
||||
using Speckle.Connectors.Grasshopper8.Components.BaseComponents;
|
||||
using Speckle.Connectors.Grasshopper8.HostApp;
|
||||
using Speckle.Connectors.Grasshopper8.Parameters;
|
||||
using Speckle.Sdk.Models.Collections;
|
||||
|
||||
namespace Speckle.Connectors.Grasshopper8.Components.Collections;
|
||||
|
||||
public class CollectionPathsSelector : ValueSet<IGH_Goo>
|
||||
{
|
||||
public CollectionPathsSelector()
|
||||
: base(
|
||||
"Collection Paths Selector",
|
||||
"Paths",
|
||||
"Allows you to select a set of collection paths for filtering",
|
||||
"Speckle",
|
||||
"Collections"
|
||||
) { }
|
||||
|
||||
public override Guid ComponentGuid => new Guid("65FC4D58-2209-41B6-9B22-BE51C8B28604");
|
||||
|
||||
protected override void LoadVolatileData()
|
||||
{
|
||||
var collections = VolatileData
|
||||
.AllData(true)
|
||||
.OfType<SpeckleCollectionWrapperGoo>()
|
||||
.Select(goo => goo.Value)
|
||||
.ToList();
|
||||
if (collections.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// NOTE: supporting multiple collections? maybe? not really?
|
||||
var paths = new List<string>();
|
||||
foreach (SpeckleCollectionWrapper col in collections)
|
||||
{
|
||||
paths.AddRange(GetPaths(col.Collection));
|
||||
}
|
||||
m_data.AppendRange(paths.Select(s => new GH_String(s)));
|
||||
}
|
||||
|
||||
private List<string> GetPaths(Collection c)
|
||||
{
|
||||
var currentPath = new List<string>();
|
||||
var allPaths = new HashSet<string>();
|
||||
|
||||
void GetPathsInternal(Collection col)
|
||||
{
|
||||
currentPath.Add(col.name);
|
||||
var subCols = col.elements.OfType<SpeckleCollectionWrapper>().ToList();
|
||||
|
||||
// NOTE: here we're basically outputting only paths that correspond to a collection
|
||||
// that has values inside of it.
|
||||
if (subCols.Count != col.elements.Count)
|
||||
{
|
||||
allPaths.Add(string.Join(Constants.LAYER_PATH_DELIMITER, currentPath));
|
||||
}
|
||||
|
||||
foreach (var subCol in subCols)
|
||||
{
|
||||
GetPathsInternal(subCol.Collection);
|
||||
}
|
||||
currentPath.RemoveAt(currentPath.Count - 1);
|
||||
}
|
||||
|
||||
GetPathsInternal(c);
|
||||
|
||||
return allPaths.ToList();
|
||||
}
|
||||
}
|
||||
+178
@@ -0,0 +1,178 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using Grasshopper.Kernel;
|
||||
using Grasshopper.Kernel.Parameters;
|
||||
using Speckle.Connectors.Grasshopper8.HostApp;
|
||||
using Speckle.Connectors.Grasshopper8.HostApp.Extras;
|
||||
using Speckle.Connectors.Grasshopper8.Parameters;
|
||||
using Speckle.Sdk.Common;
|
||||
using Speckle.Sdk.Models.Collections;
|
||||
|
||||
namespace Speckle.Connectors.Grasshopper8.Components.Collections;
|
||||
|
||||
#pragma warning disable CA1711
|
||||
public class CreateCollection : GH_Component, IGH_VariableParameterComponent
|
||||
#pragma warning restore CA1711
|
||||
{
|
||||
public override Guid ComponentGuid => new("BDCE743E-7BDB-479B-AA81-19854AB5A254");
|
||||
|
||||
protected override Bitmap Icon => BitmapBuilder.CreateCircleIconBitmap("cC");
|
||||
|
||||
private readonly DebounceDispatcher _debounceDispatcher = new();
|
||||
|
||||
public CreateCollection()
|
||||
: base("Create collection", "Create collection", "Creates a new collection", "Speckle", "Collections") { }
|
||||
|
||||
protected override void RegisterInputParams(GH_InputParamManager pManager)
|
||||
{
|
||||
var p = CreateParameter(GH_ParameterSide.Input, 0);
|
||||
pManager.AddParameter(p);
|
||||
}
|
||||
|
||||
protected override void RegisterOutputParams(GH_OutputParamManager pManager)
|
||||
{
|
||||
pManager.AddGenericParameter("Layer", "L", "Collection that was created", GH_ParamAccess.tree);
|
||||
}
|
||||
|
||||
protected override void SolveInstance(IGH_DataAccess dataAccess)
|
||||
{
|
||||
string rootName = "Unnamed";
|
||||
Collection rootCollection = new() { name = rootName, applicationId = InstanceGuid.ToString() };
|
||||
SpeckleCollectionWrapper rootSpeckleCollectionWrapper = new(rootCollection, new() { rootName }, null);
|
||||
|
||||
foreach (var inputParam in Params.Input)
|
||||
{
|
||||
var data = inputParam.VolatileData.AllData(true).ToList();
|
||||
if (data.Count == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var inputCollections = data.OfType<SpeckleCollectionWrapperGoo>().Empty().ToList();
|
||||
var inputNonCollections = data.Where(t => t is not SpeckleCollectionWrapperGoo).Empty().ToList();
|
||||
if (inputCollections.Count != 0 && inputNonCollections.Count != 0)
|
||||
{
|
||||
// TODO: error out! we want to disallow setting objects and collections in the same parent collection
|
||||
AddRuntimeMessage(
|
||||
GH_RuntimeMessageLevel.Error,
|
||||
$"Parameter {inputParam.NickName} should not contain both objects and collections."
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
List<string> childPath = new() { rootName };
|
||||
childPath.Add(inputParam.NickName);
|
||||
Collection childCollection = new(inputParam.NickName) { applicationId = inputParam.InstanceGuid.ToString() };
|
||||
SpeckleCollectionWrapper childSpeckleCollectionWrapper =
|
||||
new(childCollection, childPath, null) { Topology = GrasshopperHelpers.GetParamTopology(inputParam) };
|
||||
|
||||
// if on this port we're only receiving collections, we should become "pass-through" to not create
|
||||
// needless nesting
|
||||
if (inputCollections.Count == data.Count)
|
||||
{
|
||||
var nameTest = new HashSet<string>();
|
||||
foreach (SpeckleCollectionWrapperGoo collection in inputCollections)
|
||||
{
|
||||
// update the speckle collection path
|
||||
collection.Value.Path = new ObservableCollection<string>(childPath);
|
||||
|
||||
foreach (
|
||||
string subCollectionName in collection
|
||||
.Value.Collection.elements.OfType<SpeckleCollectionWrapper>()
|
||||
.Select(v => v.Collection.name)
|
||||
)
|
||||
{
|
||||
var hasNotSeenNameBefore = nameTest.Add(subCollectionName);
|
||||
if (!hasNotSeenNameBefore)
|
||||
{
|
||||
AddRuntimeMessage(
|
||||
GH_RuntimeMessageLevel.Error,
|
||||
$"Duplicate collection name found: {subCollectionName} in input parameter {inputParam.NickName}. Please ensure collection names are unique per nesting level.\n See https://speckle.docs/grashopper/collections"
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
childSpeckleCollectionWrapper.Collection.elements.AddRange(collection.Value.Collection.elements);
|
||||
}
|
||||
|
||||
rootSpeckleCollectionWrapper.Collection.elements.Add(childSpeckleCollectionWrapper);
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (var obj in data)
|
||||
{
|
||||
SpeckleObjectWrapperGoo wrapperGoo = new();
|
||||
if (wrapperGoo.CastFrom(obj))
|
||||
{
|
||||
wrapperGoo.Value.Path = childPath;
|
||||
wrapperGoo.Value.Parent = childSpeckleCollectionWrapper;
|
||||
childSpeckleCollectionWrapper.Collection.elements.Add(wrapperGoo.Value);
|
||||
}
|
||||
}
|
||||
|
||||
rootSpeckleCollectionWrapper.Collection.elements.Add(childSpeckleCollectionWrapper);
|
||||
}
|
||||
|
||||
dataAccess.SetData(0, new SpeckleCollectionWrapperGoo(rootSpeckleCollectionWrapper));
|
||||
}
|
||||
|
||||
public bool CanInsertParameter(GH_ParameterSide side, int index)
|
||||
{
|
||||
return side == GH_ParameterSide.Input;
|
||||
}
|
||||
|
||||
public bool CanRemoveParameter(GH_ParameterSide side, int index)
|
||||
{
|
||||
return side == GH_ParameterSide.Input;
|
||||
}
|
||||
|
||||
public IGH_Param CreateParameter(GH_ParameterSide side, int index)
|
||||
{
|
||||
var myParam = new Param_GenericObject
|
||||
{
|
||||
Name = $"Layer {Params.Input.Count + 1}",
|
||||
MutableNickName = true,
|
||||
Optional = true,
|
||||
Access = GH_ParamAccess.tree // always tree
|
||||
};
|
||||
|
||||
myParam.NickName = myParam.Name;
|
||||
myParam.Optional = true;
|
||||
return myParam;
|
||||
}
|
||||
|
||||
public bool DestroyParameter(GH_ParameterSide side, int index)
|
||||
{
|
||||
return side == GH_ParameterSide.Input;
|
||||
}
|
||||
|
||||
public void VariableParameterMaintenance()
|
||||
{
|
||||
// TODO?
|
||||
}
|
||||
|
||||
public override void AddedToDocument(GH_Document document)
|
||||
{
|
||||
base.AddedToDocument(document);
|
||||
Params.ParameterChanged += (sender, args) =>
|
||||
{
|
||||
if (args.ParameterSide == GH_ParameterSide.Output)
|
||||
{
|
||||
return;
|
||||
}
|
||||
switch (args.OriginalArguments.Type)
|
||||
{
|
||||
case GH_ObjectEventType.NickName:
|
||||
// This means the user is typing characters, debounce until it stops for 400ms before expiring the solution.
|
||||
// Prevents UI from locking too soon while writing new names for inputs.
|
||||
args.Parameter.Name = args.Parameter.NickName;
|
||||
_debounceDispatcher.Debounce(500, e => ExpireSolution(true));
|
||||
break;
|
||||
case GH_ObjectEventType.NickNameAccepted:
|
||||
args.Parameter.Name = args.Parameter.NickName;
|
||||
ExpireSolution(true);
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
+268
@@ -0,0 +1,268 @@
|
||||
using System.Collections;
|
||||
using Grasshopper.Kernel;
|
||||
using Grasshopper.Kernel.Parameters;
|
||||
using Rhino.Geometry;
|
||||
using Speckle.Connectors.Grasshopper8.HostApp;
|
||||
using Speckle.Connectors.Grasshopper8.Parameters;
|
||||
using Speckle.Sdk.Common;
|
||||
using Speckle.Sdk.Models.Collections;
|
||||
|
||||
namespace Speckle.Connectors.Grasshopper8.Components.Collections;
|
||||
|
||||
#pragma warning disable CA1711
|
||||
public class ExpandCollection : GH_Component, IGH_VariableParameterComponent
|
||||
#pragma warning restore CA1711
|
||||
{
|
||||
public override Guid ComponentGuid => new("69BC8CFB-A72F-4A83-9263-F3399DDA2E5E");
|
||||
|
||||
protected override Bitmap Icon => BitmapBuilder.CreateCircleIconBitmap("eC");
|
||||
|
||||
public ExpandCollection()
|
||||
: base("Expand Collection", "expand", "Expands a new collection", "Speckle", "Collections") { }
|
||||
|
||||
protected override void RegisterInputParams(GH_InputParamManager pManager)
|
||||
{
|
||||
pManager.AddParameter(
|
||||
new SpeckleCollectionParam(GH_ParamAccess.item),
|
||||
"Data",
|
||||
"D",
|
||||
"The data you want to expand",
|
||||
GH_ParamAccess.item
|
||||
);
|
||||
}
|
||||
|
||||
protected override void RegisterOutputParams(GH_OutputParamManager pManager) { }
|
||||
|
||||
private List<SpeckleObjectWrapper> _previewObjects = new();
|
||||
|
||||
protected override void SolveInstance(IGH_DataAccess da)
|
||||
{
|
||||
SpeckleCollectionWrapperGoo res = new();
|
||||
da.GetData(0, ref res);
|
||||
var c = res.Value;
|
||||
if (c is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Name = c.Collection.name;
|
||||
NickName = c.Collection.name;
|
||||
|
||||
var objects = c
|
||||
.Collection.elements.Where(el => el is not SpeckleCollectionWrapper)
|
||||
.OfType<SpeckleObjectWrapper>()
|
||||
.Select(o => new SpeckleObjectWrapperGoo(o))
|
||||
.ToList();
|
||||
var collections = c
|
||||
.Collection.elements.Where(el => el is SpeckleCollectionWrapper)
|
||||
.OfType<SpeckleCollectionWrapper>()
|
||||
.ToList();
|
||||
|
||||
var outputParams = new List<OutputParamWrapper>();
|
||||
if (objects.Count != 0)
|
||||
{
|
||||
var param = new Param_GenericObject()
|
||||
{
|
||||
Name = "Inner objects",
|
||||
NickName = "Inner Objs",
|
||||
Description =
|
||||
"Some collections may contain a mix of objects and other collections. Here we output the atomic objects from within this collection.",
|
||||
Access = GH_ParamAccess.list
|
||||
};
|
||||
|
||||
outputParams.Add(new OutputParamWrapper(param, objects, null));
|
||||
}
|
||||
|
||||
foreach (SpeckleCollectionWrapper collection in collections)
|
||||
{
|
||||
// skip empty
|
||||
if (collection.Collection.elements.Count == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var hasInnerCollections = collection.Collection.elements.Any(el => el is SpeckleCollectionWrapper);
|
||||
var topology = collection.Topology; // Note: this is a reminder for the future
|
||||
var nickName = collection.Collection.name;
|
||||
if (collection.Collection.name.Length > 16)
|
||||
{
|
||||
nickName = collection.Collection.name[..3];
|
||||
nickName += "..." + collection.Collection.name[^3..];
|
||||
}
|
||||
|
||||
var param = new Param_GenericObject()
|
||||
{
|
||||
Name = collection.Collection.name,
|
||||
NickName = nickName,
|
||||
Access = hasInnerCollections
|
||||
? GH_ParamAccess.item
|
||||
: topology is null
|
||||
? GH_ParamAccess.list
|
||||
: GH_ParamAccess.tree // we will directly set objects out; note access can be list or tree based on whether it will be a path based collection
|
||||
};
|
||||
if (!hasInnerCollections)
|
||||
{
|
||||
_previewObjects.AddRange(collection.Collection.elements.Cast<SpeckleObjectWrapper>());
|
||||
}
|
||||
|
||||
outputParams.Add(
|
||||
new OutputParamWrapper(
|
||||
param,
|
||||
hasInnerCollections
|
||||
? new SpeckleCollectionWrapperGoo(collection)
|
||||
: collection
|
||||
.Collection.elements.OfType<SpeckleObjectWrapper>()
|
||||
.Select(o => new SpeckleObjectWrapperGoo(o))
|
||||
.ToList(),
|
||||
topology
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (da.Iteration == 0 && OutputMismatch(outputParams))
|
||||
{
|
||||
OnPingDocument()
|
||||
.ScheduleSolution(
|
||||
5,
|
||||
_ =>
|
||||
{
|
||||
CreateOutputs(outputParams);
|
||||
}
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
_previewObjects = new();
|
||||
|
||||
FlattenForPreview(c.Collection);
|
||||
for (int i = 0; i < outputParams.Count; i++)
|
||||
{
|
||||
var outParam = Params.Output[i];
|
||||
var outParamWrapper = outputParams[i];
|
||||
switch (outParam.Access)
|
||||
{
|
||||
case GH_ParamAccess.item:
|
||||
da.SetData(i, outParamWrapper.Values);
|
||||
break;
|
||||
case GH_ParamAccess.list:
|
||||
da.SetDataList(i, outParamWrapper.Values as IList);
|
||||
break;
|
||||
case GH_ParamAccess.tree:
|
||||
//TODO: means we need to convert the collection to a tree
|
||||
var topo = outParamWrapper.Topology.NotNull();
|
||||
var values = outParamWrapper.Values as IList;
|
||||
var tree = GrasshopperHelpers.CreateDataTreeFromTopologyAndItems(topo, values.NotNull());
|
||||
da.SetDataTree(i, tree);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private BoundingBox _clippingBox;
|
||||
public override BoundingBox ClippingBox => _clippingBox;
|
||||
|
||||
private void FlattenForPreview(Collection c)
|
||||
{
|
||||
_clippingBox = new BoundingBox();
|
||||
foreach (var element in c.elements)
|
||||
{
|
||||
if (element is Collection subCol)
|
||||
{
|
||||
FlattenForPreview(subCol);
|
||||
}
|
||||
|
||||
if (element is SpeckleObjectWrapper sg)
|
||||
{
|
||||
_previewObjects.Add(sg);
|
||||
var box = sg.GeometryBase.GetBoundingBox(false);
|
||||
_clippingBox.Union(box);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// public override void DrawViewportWires(IGH_PreviewArgs args) => base.DrawViewportWires(args);
|
||||
public override void DrawViewportMeshes(IGH_PreviewArgs args)
|
||||
{
|
||||
if (_previewObjects.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var isSelected = args.Document.SelectedObjects().Contains(this);
|
||||
foreach (var elem in _previewObjects)
|
||||
{
|
||||
elem.DrawPreview(args, isSelected);
|
||||
}
|
||||
}
|
||||
|
||||
private bool OutputMismatch(List<OutputParamWrapper> outputParams)
|
||||
{
|
||||
if (Params.Output.Count != outputParams.Count)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
var count = 0;
|
||||
foreach (var newParam in outputParams)
|
||||
{
|
||||
var oldParam = Params.Output[count];
|
||||
if (
|
||||
oldParam.NickName != newParam.Param.NickName
|
||||
|| oldParam.Name != newParam.Param.Name
|
||||
|| oldParam.Access != newParam.Param.Access
|
||||
)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
count++;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void CreateOutputs(List<OutputParamWrapper> outputParams)
|
||||
{
|
||||
// TODO: better, nicer handling of creation/removal
|
||||
while (Params.Output.Count > 0)
|
||||
{
|
||||
Params.UnregisterOutputParameter(Params.Output[^1]);
|
||||
}
|
||||
|
||||
foreach (var newParam in outputParams)
|
||||
{
|
||||
var param = new Param_GenericObject
|
||||
{
|
||||
Name = newParam.Param.Name,
|
||||
NickName = newParam.Param.NickName,
|
||||
MutableNickName = false,
|
||||
Access = newParam.Param.Access
|
||||
};
|
||||
Params.RegisterOutputParam(param);
|
||||
}
|
||||
|
||||
Params.OnParametersChanged();
|
||||
VariableParameterMaintenance();
|
||||
ExpireSolution(false);
|
||||
}
|
||||
|
||||
public void VariableParameterMaintenance() { }
|
||||
|
||||
public bool CanInsertParameter(GH_ParameterSide side, int index) => false;
|
||||
|
||||
public bool CanRemoveParameter(GH_ParameterSide side, int index) => false;
|
||||
|
||||
public IGH_Param CreateParameter(GH_ParameterSide side, int index)
|
||||
{
|
||||
var myParam = new Param_GenericObject
|
||||
{
|
||||
Name = GH_ComponentParamServer.InventUniqueNickname("ABCD", Params.Input),
|
||||
MutableNickName = true,
|
||||
Optional = true
|
||||
};
|
||||
myParam.NickName = myParam.Name;
|
||||
return myParam;
|
||||
}
|
||||
|
||||
public bool DestroyParameter(GH_ParameterSide side, int index) => side == GH_ParameterSide.Output;
|
||||
}
|
||||
|
||||
public record OutputParamWrapper(Param_GenericObject Param, object Values, string? Topology);
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
using Grasshopper.Kernel;
|
||||
using Speckle.Connectors.Grasshopper8.HostApp;
|
||||
using Speckle.Connectors.Grasshopper8.Parameters;
|
||||
using Speckle.Sdk;
|
||||
|
||||
namespace Speckle.Connectors.Grasshopper8.Components.Collections;
|
||||
|
||||
/// <summary>
|
||||
/// Given a collection and a path, this component will output the objects in the corresponding collection.
|
||||
/// Note: This component does not flatten the selected collection - if it contains sub collections those will not
|
||||
/// be outputted.
|
||||
///
|
||||
/// To extract those objects out, you should select that specific sub path as well.
|
||||
/// </summary>
|
||||
public class FilterObjectsByCollectionPaths : GH_Component
|
||||
{
|
||||
public override Guid ComponentGuid => new("77CAEE94-F0B9-4611-897C-71F2A22BA311");
|
||||
|
||||
public FilterObjectsByCollectionPaths()
|
||||
: base(
|
||||
"FilterObjectsByCollectionPaths",
|
||||
"ocF",
|
||||
"Filters model objects by their collection path",
|
||||
"Speckle",
|
||||
"Collections"
|
||||
) { }
|
||||
|
||||
protected override void RegisterInputParams(GH_InputParamManager pManager)
|
||||
{
|
||||
pManager.AddParameter(
|
||||
new SpeckleCollectionParam(),
|
||||
"Collection",
|
||||
"C",
|
||||
"Collection to filter objects from",
|
||||
GH_ParamAccess.item
|
||||
);
|
||||
pManager.AddTextParameter("Path", "P", "Collection path to filter by", GH_ParamAccess.item);
|
||||
}
|
||||
|
||||
protected override void RegisterOutputParams(GH_OutputParamManager pManager)
|
||||
{
|
||||
pManager.AddParameter(
|
||||
new SpeckleObjectParam(),
|
||||
"Objects",
|
||||
"O",
|
||||
"The contents of the selected collection",
|
||||
GH_ParamAccess.tree
|
||||
);
|
||||
}
|
||||
|
||||
protected override void SolveInstance(IGH_DataAccess dataAccess)
|
||||
{
|
||||
string path = "";
|
||||
dataAccess.GetData(1, ref path);
|
||||
|
||||
if (string.IsNullOrEmpty(path))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SpeckleCollectionWrapperGoo collectionWrapperGoo = new();
|
||||
dataAccess.GetData(0, ref collectionWrapperGoo);
|
||||
|
||||
if (collectionWrapperGoo.Value == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SpeckleCollectionWrapper targetCollectionWrapper = FindCollection(collectionWrapperGoo.Value, path);
|
||||
if (string.IsNullOrEmpty(targetCollectionWrapper.Topology))
|
||||
{
|
||||
dataAccess.SetDataList(0, targetCollectionWrapper.Collection.elements);
|
||||
}
|
||||
else
|
||||
{
|
||||
var tree = GrasshopperHelpers.CreateDataTreeFromTopologyAndItems(
|
||||
targetCollectionWrapper.Topology,
|
||||
targetCollectionWrapper.Collection.elements
|
||||
);
|
||||
dataAccess.SetDataTree(0, tree);
|
||||
}
|
||||
}
|
||||
|
||||
private SpeckleCollectionWrapper FindCollection(SpeckleCollectionWrapper root, string unifiedPath)
|
||||
{
|
||||
// POC: SpeckleCollections now have a full list<string> path prop on them always. Is this easier to use?
|
||||
List<string> paths = unifiedPath.Split([Constants.LAYER_PATH_DELIMITER], StringSplitOptions.None).Skip(1).ToList();
|
||||
SpeckleCollectionWrapper currentCollectionWrapper = root;
|
||||
while (paths.Count != 0)
|
||||
{
|
||||
currentCollectionWrapper = currentCollectionWrapper
|
||||
.Collection.elements.OfType<SpeckleCollectionWrapper>()
|
||||
.First(col => col.Collection.name == paths.First());
|
||||
paths.RemoveAt(0);
|
||||
if (paths.Count == 0)
|
||||
{
|
||||
return currentCollectionWrapper;
|
||||
}
|
||||
}
|
||||
|
||||
throw new SpeckleException("Did not find collection");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
namespace Speckle.Connectors.Grasshopper8.Components;
|
||||
|
||||
// NOTE: The number of spaces determines the order in which they display in the ribbon (nice hack)
|
||||
public static class ComponentCategories
|
||||
{
|
||||
public const string OPERATIONS = " Operations";
|
||||
public const string MODELS = " Model Management";
|
||||
public const string PARAMETERS = "Parameters";
|
||||
public const string COLLECTIONS = " Collections";
|
||||
public const string PRIMARY_RIBBON = "Speckle";
|
||||
public const string OBJECTS = " Objects";
|
||||
}
|
||||
|
||||
public enum ComponentState
|
||||
{
|
||||
Cancelled,
|
||||
Expired,
|
||||
NeedsInput,
|
||||
Receiving,
|
||||
Ready,
|
||||
Sending,
|
||||
UpToDate
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using Grasshopper.Kernel;
|
||||
|
||||
namespace Speckle.Connectors.Grasshopper8.Components;
|
||||
|
||||
public class GhContextMenuButton(
|
||||
string name,
|
||||
string nickname,
|
||||
string description,
|
||||
Func<ToolStripDropDown, bool>? populateMenuAction = null
|
||||
) : GH_DocumentObject(name, nickname, description, "Speckle", "UI")
|
||||
{
|
||||
public bool Enabled { get; set; } = true;
|
||||
|
||||
public override void CreateAttributes() => Attributes = new GhContextMenuButtonAttributes(this);
|
||||
|
||||
public override Guid ComponentGuid => new("B01FFD91-F4EC-4332-A9AA-F917AEDAA51D");
|
||||
|
||||
public override bool AppendMenuItems(ToolStripDropDown menu) => populateMenuAction?.Invoke(menu) ?? false;
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
using Grasshopper.GUI;
|
||||
using Grasshopper.GUI.Canvas;
|
||||
using Grasshopper.Kernel;
|
||||
|
||||
namespace Speckle.Connectors.Grasshopper8.Components;
|
||||
|
||||
public class GhContextMenuButtonAttributes(GhContextMenuButton owner) : GH_Attributes<GhContextMenuButton>(owner)
|
||||
{
|
||||
protected override void Render(GH_Canvas canvas, Graphics graphics, GH_CanvasChannel channel)
|
||||
{
|
||||
base.Render(canvas, graphics, channel);
|
||||
if (channel != GH_CanvasChannel.Objects)
|
||||
{
|
||||
return; // No wires or other layers are being drawn in this component.
|
||||
}
|
||||
|
||||
using var button1 = GH_Capsule.CreateTextCapsule(
|
||||
Bounds,
|
||||
Bounds,
|
||||
Owner.Enabled ? GH_Palette.Black : GH_Palette.Grey,
|
||||
Owner.Name,
|
||||
2,
|
||||
0
|
||||
);
|
||||
button1.Render(graphics, Parent.Selected, false, false);
|
||||
}
|
||||
|
||||
public override GH_ObjectResponse RespondToMouseUp(GH_Canvas sender, GH_CanvasMouseEvent e)
|
||||
{
|
||||
if (!Owner.Enabled && e.Button == MouseButtons.Right)
|
||||
{
|
||||
// Prevents canvas from triggering the right-click behaviour, and showing the context menu.
|
||||
return GH_ObjectResponse.Handled;
|
||||
}
|
||||
|
||||
// Allowing event to bubble up to canvas will handle the event and show the context menu.
|
||||
return base.RespondToMouseUp(sender, e);
|
||||
}
|
||||
}
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
using Speckle.Connectors.Grasshopper8.Parameters;
|
||||
using Speckle.Sdk.Models.Collections;
|
||||
|
||||
namespace Speckle.Connectors.Grasshopper8.Components.Operations.Receive;
|
||||
|
||||
internal sealed class GrasshopperCollectionRebuilder
|
||||
{
|
||||
public SpeckleCollectionWrapper RootCollectionWrapper { get; }
|
||||
|
||||
// a cache of collection path (no delimiter) to the speckle collection
|
||||
private readonly Dictionary<string, SpeckleCollectionWrapper> _cache = new();
|
||||
|
||||
public GrasshopperCollectionRebuilder(Collection baseCollection)
|
||||
{
|
||||
Collection newCollection = new() { name = baseCollection.name, applicationId = baseCollection.applicationId };
|
||||
RootCollectionWrapper = new SpeckleCollectionWrapper(newCollection, new() { baseCollection.name }, null);
|
||||
}
|
||||
|
||||
public void AppendSpeckleGrasshopperObject(
|
||||
SpeckleObjectWrapper speckleGrasshopperObjectWrapper,
|
||||
List<Collection> collectionPath
|
||||
)
|
||||
{
|
||||
var collection = GetOrCreateSpeckleCollectionFromPath(collectionPath);
|
||||
collection.Collection.elements.Add(speckleGrasshopperObjectWrapper);
|
||||
}
|
||||
|
||||
public SpeckleCollectionWrapper GetOrCreateSpeckleCollectionFromPath(List<Collection> path)
|
||||
{
|
||||
// first check if cache already has this collection
|
||||
string fullPath = string.Concat(path);
|
||||
if (_cache.TryGetValue(fullPath, out SpeckleCollectionWrapper col))
|
||||
{
|
||||
return col;
|
||||
}
|
||||
|
||||
// otherwise, iterate through the path and create speckle collections as needed
|
||||
SpeckleCollectionWrapper previousCollectionWrapper = RootCollectionWrapper;
|
||||
List<string> currentLayerPath = new();
|
||||
foreach (var collection in path)
|
||||
{
|
||||
var collectionName = collection.name;
|
||||
currentLayerPath.Add(collectionName);
|
||||
string key = string.Concat(currentLayerPath);
|
||||
|
||||
// check cache
|
||||
if (_cache.TryGetValue(key, out SpeckleCollectionWrapper currentCol))
|
||||
{
|
||||
previousCollectionWrapper = currentCol;
|
||||
continue;
|
||||
}
|
||||
|
||||
// create and cache if needed
|
||||
Collection newCollection = new() { name = collectionName };
|
||||
SpeckleCollectionWrapper newSpeckleCollectionWrapper = new(newCollection, currentLayerPath, null);
|
||||
|
||||
if (collection["topology"] is string topology)
|
||||
{
|
||||
newSpeckleCollectionWrapper.Topology = topology;
|
||||
newCollection["topology"] = topology;
|
||||
}
|
||||
|
||||
_cache[key] = newSpeckleCollectionWrapper;
|
||||
previousCollectionWrapper.Collection.elements.Add(newSpeckleCollectionWrapper);
|
||||
|
||||
previousCollectionWrapper = newSpeckleCollectionWrapper;
|
||||
}
|
||||
|
||||
return previousCollectionWrapper;
|
||||
}
|
||||
}
|
||||
+725
@@ -0,0 +1,725 @@
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
using Grasshopper.GUI;
|
||||
using Grasshopper.GUI.Canvas;
|
||||
using Grasshopper.Kernel;
|
||||
using Grasshopper.Kernel.Attributes;
|
||||
using GrasshopperAsyncComponent;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Rhino;
|
||||
using Rhino.Geometry;
|
||||
using Speckle.Connectors.Common.Instances;
|
||||
using Speckle.Connectors.Common.Operations;
|
||||
using Speckle.Connectors.Common.Operations.Receive;
|
||||
using Speckle.Connectors.Grasshopper8.HostApp;
|
||||
using Speckle.Connectors.Grasshopper8.Operations.Receive;
|
||||
using Speckle.Connectors.Grasshopper8.Parameters;
|
||||
using Speckle.Connectors.Grasshopper8.Registration;
|
||||
using Speckle.Sdk;
|
||||
using Speckle.Sdk.Api;
|
||||
using Speckle.Sdk.Api.GraphQL.Models;
|
||||
using Speckle.Sdk.Common.Exceptions;
|
||||
using Speckle.Sdk.Credentials;
|
||||
using Speckle.Sdk.Models;
|
||||
using Speckle.Sdk.Models.Collections;
|
||||
using Speckle.Sdk.Models.Extensions;
|
||||
|
||||
namespace Speckle.Connectors.Grasshopper8.Components.Operations.Receive;
|
||||
|
||||
[Guid("1587DF34-83E5-4AFE-B42E-F7C5C37ECD68")]
|
||||
public class ReceiveAsyncComponent : GH_AsyncComponent
|
||||
{
|
||||
public ReceiveAsyncComponent()
|
||||
: base(
|
||||
"Async Receive",
|
||||
"aR",
|
||||
"Receive objects async from speckle",
|
||||
ComponentCategories.PRIMARY_RIBBON,
|
||||
ComponentCategories.OPERATIONS
|
||||
)
|
||||
{
|
||||
BaseWorker = new ReceiveComponentWorker(this);
|
||||
Attributes = new ReceiveAsyncComponentAttributes(this);
|
||||
}
|
||||
|
||||
public override Guid ComponentGuid => GetType().GUID;
|
||||
|
||||
protected override Bitmap Icon => BitmapBuilder.CreateSquareIconBitmap("aR");
|
||||
|
||||
public string InputType { get; set; }
|
||||
public bool AutoReceive { get; set; }
|
||||
public bool ReceiveOnOpen { get; set; }
|
||||
public string ReceivedVersionId { get; set; }
|
||||
public ComponentState CurrentComponentState { get; set; } = ComponentState.NeedsInput;
|
||||
public bool JustPastedIn { get; set; }
|
||||
public string LastVersionDate { get; set; }
|
||||
public string LastInfoMessage { get; set; }
|
||||
public HostApp.SpeckleUrlModelResource? UrlModelResource { get; set; }
|
||||
|
||||
// DI props
|
||||
public Client ApiClient { get; private set; }
|
||||
public GrasshopperReceiveOperation ReceiveOperation { get; private set; }
|
||||
public RootObjectUnpacker RootObjectUnpacker { get; private set; }
|
||||
public static IServiceScope? Scope { get; private set; }
|
||||
public AccountService AccountManager { get; private set; }
|
||||
public IClientFactory ClientFactory { get; private set; }
|
||||
|
||||
protected override void RegisterInputParams(GH_InputParamManager pManager)
|
||||
{
|
||||
pManager.AddParameter(new SpeckleUrlModelResourceParam(GH_ParamAccess.item));
|
||||
}
|
||||
|
||||
protected override void RegisterOutputParams(GH_OutputParamManager pManager)
|
||||
{
|
||||
pManager.AddParameter(
|
||||
new SpeckleCollectionParam(GH_ParamAccess.item),
|
||||
"Model",
|
||||
"model",
|
||||
"The model object for the received version",
|
||||
GH_ParamAccess.item
|
||||
);
|
||||
}
|
||||
|
||||
protected override void SolveInstance(IGH_DataAccess da)
|
||||
{
|
||||
da.DisableGapLogic();
|
||||
|
||||
// Dependency Injection
|
||||
Scope = PriorityLoader.Container.CreateScope();
|
||||
ReceiveOperation = Scope.ServiceProvider.GetRequiredService<GrasshopperReceiveOperation>();
|
||||
RootObjectUnpacker = Scope.ServiceProvider.GetService<RootObjectUnpacker>();
|
||||
AccountManager = Scope.ServiceProvider.GetRequiredService<AccountService>();
|
||||
ClientFactory = Scope.ServiceProvider.GetRequiredService<IClientFactory>();
|
||||
|
||||
// We need to call this always in here to be able to react and set events :/
|
||||
ParseInput(da);
|
||||
|
||||
if (
|
||||
(
|
||||
AutoReceive
|
||||
|| CurrentComponentState == ComponentState.Ready
|
||||
|| CurrentComponentState == ComponentState.Receiving
|
||||
) && !JustPastedIn
|
||||
)
|
||||
{
|
||||
CurrentComponentState = ComponentState.Receiving;
|
||||
|
||||
// Delegate control to parent async component.
|
||||
base.SolveInstance(da);
|
||||
return;
|
||||
}
|
||||
|
||||
if (JustPastedIn)
|
||||
{
|
||||
// This ensures that we actually do a run. The worker will check and determine if it needs to pull an existing object or not.
|
||||
OnDisplayExpired(true);
|
||||
base.SolveInstance(da);
|
||||
}
|
||||
else
|
||||
{
|
||||
CurrentComponentState = ComponentState.Expired;
|
||||
Message = "Expired";
|
||||
OnDisplayExpired(true);
|
||||
}
|
||||
}
|
||||
|
||||
public override void AppendAdditionalMenuItems(ToolStripDropDown menu)
|
||||
{
|
||||
base.AppendAdditionalMenuItems(menu);
|
||||
|
||||
Menu_AppendSeparator(menu);
|
||||
if (InputType == "Model")
|
||||
{
|
||||
var autoReceiveMi = Menu_AppendItem(
|
||||
menu,
|
||||
"Load automatically",
|
||||
(s, e) =>
|
||||
{
|
||||
AutoReceive = !AutoReceive;
|
||||
RhinoApp.InvokeOnUiThread(
|
||||
(Action)
|
||||
delegate
|
||||
{
|
||||
OnDisplayExpired(true);
|
||||
}
|
||||
);
|
||||
},
|
||||
true,
|
||||
AutoReceive
|
||||
);
|
||||
autoReceiveMi.ToolTipText =
|
||||
"Toggle automatic loading. If set, any new version will be loaded instantly. This only is applicable when receiving from a model url.";
|
||||
}
|
||||
else
|
||||
{
|
||||
var autoReceiveMi = Menu_AppendItem(menu, "Automatic loading is disabled because you have specified a version.");
|
||||
autoReceiveMi.ToolTipText = "To enable automatic loading, select a model without selecting a specific version.";
|
||||
}
|
||||
|
||||
var receivOnOpenMi = Menu_AppendItem(
|
||||
menu,
|
||||
"Load when Document opened",
|
||||
(sender, args) =>
|
||||
{
|
||||
ReceiveOnOpen = !ReceiveOnOpen;
|
||||
RhinoApp.InvokeOnUiThread(
|
||||
(Action)
|
||||
delegate
|
||||
{
|
||||
OnDisplayExpired(true);
|
||||
}
|
||||
);
|
||||
},
|
||||
!AutoReceive,
|
||||
AutoReceive || ReceiveOnOpen
|
||||
);
|
||||
receivOnOpenMi.ToolTipText =
|
||||
"The node will automatically perform a load operation as soon as the document is open, or the node is copy/pasted into a new document.";
|
||||
|
||||
Menu_AppendSeparator(menu);
|
||||
|
||||
if (CurrentComponentState == ComponentState.Receiving)
|
||||
{
|
||||
Menu_AppendItem(
|
||||
menu,
|
||||
"Cancel Load",
|
||||
(s, e) =>
|
||||
{
|
||||
CurrentComponentState = ComponentState.Expired;
|
||||
RequestCancellation();
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleNewCommit()
|
||||
{
|
||||
Message = "Expired";
|
||||
CurrentComponentState = ComponentState.Expired;
|
||||
AddRuntimeMessage(GH_RuntimeMessageLevel.Remark, $"There is a newer version available for this {InputType}");
|
||||
RhinoApp.InvokeOnUiThread(
|
||||
(Action)
|
||||
delegate
|
||||
{
|
||||
if (AutoReceive)
|
||||
{
|
||||
ExpireSolution(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
OnDisplayExpired(true);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public override void RemovedFromDocument(GH_Document document)
|
||||
{
|
||||
RequestCancellation();
|
||||
Scope?.Dispose();
|
||||
base.RemovedFromDocument(document);
|
||||
}
|
||||
|
||||
public override void DocumentContextChanged(GH_Document document, GH_DocumentContext context)
|
||||
{
|
||||
switch (context)
|
||||
{
|
||||
case GH_DocumentContext.Loaded:
|
||||
{
|
||||
// Will execute every time a document becomes active (from background or opening file.).
|
||||
if (UrlModelResource != null)
|
||||
{
|
||||
Task.Run(async () =>
|
||||
{
|
||||
// Ensure fresh instance of client.
|
||||
ResetApiClient(UrlModelResource);
|
||||
|
||||
// Get last commit from the branch
|
||||
var b = UrlModelResource.GetReceiveInfo(ApiClient);
|
||||
await b;
|
||||
|
||||
// Compare version ids. If they don't match, notify user or fetch data if in auto mode
|
||||
if (b.Result.SelectedVersionId != ReceivedVersionId)
|
||||
{
|
||||
HandleNewCommit();
|
||||
}
|
||||
|
||||
OnDisplayExpired(true);
|
||||
});
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case GH_DocumentContext.Unloaded:
|
||||
// Will execute every time a document becomes inactive (in background or closing file.)
|
||||
// Correctly dispose of the client when changing documents to prevent subscription handlers being called in background.
|
||||
CurrentComponentState = ComponentState.Expired;
|
||||
RequestCancellation();
|
||||
ApiClient?.Dispose();
|
||||
break;
|
||||
}
|
||||
|
||||
base.DocumentContextChanged(document, context);
|
||||
}
|
||||
|
||||
private void ParseInput(IGH_DataAccess da)
|
||||
{
|
||||
HostApp.SpeckleUrlModelResource? dataInput = null;
|
||||
da.GetData(0, ref dataInput);
|
||||
if (dataInput is null)
|
||||
{
|
||||
UrlModelResource = null;
|
||||
TriggerAutoSave();
|
||||
return;
|
||||
}
|
||||
|
||||
// set the type of url input
|
||||
switch (dataInput)
|
||||
{
|
||||
case SpeckleUrlModelVersionResource:
|
||||
InputType = "Version";
|
||||
AutoReceive = false;
|
||||
LastInfoMessage = "";
|
||||
ResetApiClient(dataInput);
|
||||
return;
|
||||
case SpeckleUrlModelResource:
|
||||
InputType = "Model";
|
||||
// handled in do work
|
||||
break;
|
||||
default:
|
||||
InputType = "Invalid";
|
||||
break;
|
||||
}
|
||||
|
||||
if (UrlModelResource != null && UrlModelResource.Equals(dataInput) && !JustPastedIn)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
UrlModelResource = dataInput;
|
||||
|
||||
ResetApiClient(UrlModelResource);
|
||||
}
|
||||
|
||||
private void ApiClient_OnVersionCreated(object sender, ProjectVersionsUpdatedMessage e)
|
||||
{
|
||||
HandleNewCommit();
|
||||
}
|
||||
|
||||
public void ResetApiClient(SpeckleUrlModelResource urlResource)
|
||||
{
|
||||
try
|
||||
{
|
||||
// TODO: Get any account for this server, as we don't have a mechanism yet to pass accountIds through
|
||||
Account account = AccountManager.GetAccountWithServerUrlFallback("", new Uri(urlResource.Server));
|
||||
if (account is null)
|
||||
{
|
||||
throw new SpeckleAccountManagerException($"No default account was found");
|
||||
}
|
||||
|
||||
ApiClient?.Dispose();
|
||||
ApiClient = ClientFactory.Create(account);
|
||||
ApiClient.Subscription.CreateProjectVersionsUpdatedSubscription(urlResource.ProjectId).Listeners +=
|
||||
ApiClient_OnVersionCreated;
|
||||
}
|
||||
catch (Exception e) when (!e.IsFatal())
|
||||
{
|
||||
AddRuntimeMessage(GH_RuntimeMessageLevel.Error, e.ToFormattedString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class ReceiveComponentWorker : WorkerInstance
|
||||
{
|
||||
public ReceiveComponentWorker(GH_Component p)
|
||||
: base(p) { }
|
||||
|
||||
public Base Root { get; set; }
|
||||
public SpeckleUrlModelResource? UrlModelResource { get; set; }
|
||||
public SpeckleCollectionWrapperGoo Result { get; set; }
|
||||
private List<(GH_RuntimeMessageLevel, string)> RuntimeMessages { get; } = new();
|
||||
|
||||
public override WorkerInstance Duplicate()
|
||||
{
|
||||
return new ReceiveComponentWorker(Parent);
|
||||
}
|
||||
|
||||
public override void GetData(IGH_DataAccess da, GH_ComponentParamServer p)
|
||||
{
|
||||
UrlModelResource = ((ReceiveAsyncComponent)Parent).UrlModelResource;
|
||||
}
|
||||
|
||||
public override void SetData(IGH_DataAccess da)
|
||||
{
|
||||
if (CancellationToken.IsCancellationRequested)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var (level, message) in RuntimeMessages)
|
||||
{
|
||||
Parent.AddRuntimeMessage(level, message);
|
||||
}
|
||||
|
||||
var parent = (ReceiveAsyncComponent)Parent;
|
||||
|
||||
parent.CurrentComponentState = ComponentState.UpToDate;
|
||||
|
||||
parent.JustPastedIn = false;
|
||||
|
||||
if (Result == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
da.SetData(0, Result);
|
||||
}
|
||||
|
||||
#pragma warning disable CA1506
|
||||
public override void DoWork(Action<string, double> reportProgress, Action done)
|
||||
{
|
||||
var receiveComponent = (ReceiveAsyncComponent)Parent;
|
||||
|
||||
try
|
||||
{
|
||||
if (UrlModelResource is null)
|
||||
{
|
||||
throw new InvalidOperationException("Url Resource was null");
|
||||
}
|
||||
|
||||
// Means it's a copy paste of an empty non-init component; set the record and exit fast unless ReceiveOnOpen is true.
|
||||
if (receiveComponent.JustPastedIn && !receiveComponent.AutoReceive)
|
||||
{
|
||||
receiveComponent.JustPastedIn = false;
|
||||
if (!receiveComponent.ReceiveOnOpen)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
receiveComponent.CurrentComponentState = ComponentState.Receiving;
|
||||
RhinoApp.InvokeOnUiThread(
|
||||
(Action)
|
||||
delegate
|
||||
{
|
||||
receiveComponent.OnDisplayExpired(true);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
var t = Task.Run(async () =>
|
||||
{
|
||||
// Step 1 - RECEIVE FROM SERVER
|
||||
var receiveInfo = await UrlModelResource
|
||||
.GetReceiveInfo(receiveComponent.ApiClient, CancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
var progress = new Progress<CardProgress>(p =>
|
||||
{
|
||||
reportProgress(Id, p.Progress ?? 0);
|
||||
//eceiveComponent.Message = $"{p.Status}";
|
||||
});
|
||||
|
||||
if (CancellationToken.IsCancellationRequested)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (receiveInfo == null)
|
||||
{
|
||||
done();
|
||||
return;
|
||||
}
|
||||
|
||||
Root = await receiveComponent
|
||||
.ReceiveOperation.ReceiveCommitObject(receiveInfo, progress, CancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
if (CancellationToken.IsCancellationRequested)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Step 2 - CONVERT
|
||||
//receiveComponent.Message = $"Unpacking...";
|
||||
var localToGlobalUnpacker = new LocalToGlobalUnpacker();
|
||||
var traversalContextUnpacker = new TraversalContextUnpacker();
|
||||
var unpackedRoot = receiveComponent.RootObjectUnpacker.Unpack(Root);
|
||||
|
||||
// "flatten" block instances
|
||||
var localToGlobalMaps = localToGlobalUnpacker.Unpack(
|
||||
unpackedRoot.DefinitionProxies,
|
||||
unpackedRoot.ObjectsToConvert.ToList()
|
||||
);
|
||||
|
||||
// TODO: unpack colors and render materials
|
||||
|
||||
var collectionRebuilder = new GrasshopperCollectionRebuilder(
|
||||
(Root as Collection) ?? new Collection() { name = "unnamed" }
|
||||
);
|
||||
|
||||
int count = 0;
|
||||
int total = localToGlobalMaps.Count;
|
||||
|
||||
foreach (var map in localToGlobalMaps)
|
||||
{
|
||||
try
|
||||
{
|
||||
List<GeometryBase> converted = Convert(map.AtomicObject);
|
||||
var path = traversalContextUnpacker.GetCollectionPath(map.TraversalContext).ToList();
|
||||
|
||||
foreach (var matrix in map.Matrix)
|
||||
{
|
||||
var mat = GrasshopperHelpers.MatrixToTransform(matrix, "meters");
|
||||
converted.ForEach(res => res.Transform(mat));
|
||||
}
|
||||
|
||||
// get the collection
|
||||
SpeckleCollectionWrapper objectCollection = collectionRebuilder.GetOrCreateSpeckleCollectionFromPath(path);
|
||||
|
||||
// get the name and properties
|
||||
SpecklePropertyGroupGoo propertyGroup = new();
|
||||
string name = "";
|
||||
if (map.AtomicObject is Speckle.Objects.Data.DataObject da)
|
||||
{
|
||||
propertyGroup.CastFrom(da.properties);
|
||||
name = da.name;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (map.AtomicObject["properties"] is Dictionary<string, object?> props)
|
||||
{
|
||||
propertyGroup.CastFrom(props);
|
||||
}
|
||||
|
||||
if (map.AtomicObject["name"] is string n)
|
||||
{
|
||||
name = n;
|
||||
}
|
||||
}
|
||||
|
||||
// create objects for every value in converted. This is where one to many is not handled very nicely.
|
||||
foreach (var geometryBase in converted)
|
||||
{
|
||||
var gh = new SpeckleObjectWrapper()
|
||||
{
|
||||
Base = map.AtomicObject,
|
||||
Path = path.Select(p => p.name).ToList(),
|
||||
Parent = objectCollection,
|
||||
GeometryBase = geometryBase,
|
||||
Properties = propertyGroup,
|
||||
Name = name
|
||||
};
|
||||
|
||||
collectionRebuilder.AppendSpeckleGrasshopperObject(gh, path);
|
||||
}
|
||||
}
|
||||
catch (ConversionException)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
//reportProgress(Id, (double)count / total);
|
||||
count++;
|
||||
}
|
||||
|
||||
Result = new SpeckleCollectionWrapperGoo(collectionRebuilder.RootCollectionWrapper);
|
||||
|
||||
// DONE
|
||||
done();
|
||||
});
|
||||
t.Wait();
|
||||
}
|
||||
catch (Exception ex) when (!ex.IsFatal())
|
||||
{
|
||||
RuntimeMessages.Add((GH_RuntimeMessageLevel.Error, ex.ToFormattedString()));
|
||||
done();
|
||||
}
|
||||
}
|
||||
#pragma warning restore CA1506
|
||||
|
||||
private List<GeometryBase> Convert(Base input)
|
||||
{
|
||||
var result = ToSpeckleConversionContext.ToHostConverter.Convert(input);
|
||||
|
||||
if (result is GeometryBase geometry)
|
||||
{
|
||||
return [geometry];
|
||||
}
|
||||
if (result is List<GeometryBase> geometryList)
|
||||
{
|
||||
return geometryList;
|
||||
}
|
||||
if (result is IEnumerable<(GeometryBase, Base)> fallbackConversionResult)
|
||||
{
|
||||
// note special handling for proxying render materials OR we don't care about revit
|
||||
return fallbackConversionResult.Select(t => t.Item1).ToList();
|
||||
}
|
||||
|
||||
throw new SpeckleException("Failed to convert input to rhino");
|
||||
}
|
||||
}
|
||||
|
||||
public class ReceiveAsyncComponentAttributes : GH_ComponentAttributes
|
||||
{
|
||||
private bool _selected;
|
||||
|
||||
private class SpeckleComponentButton
|
||||
{
|
||||
public int Height { get; set; } = 26;
|
||||
public Rectangle ButtonBounds { get; set; }
|
||||
public GH_Palette Palette { get; set; }
|
||||
public string Text { get; set; }
|
||||
}
|
||||
|
||||
private List<SpeckleComponentButton> Buttons { get; set; }
|
||||
|
||||
public ReceiveAsyncComponentAttributes(GH_Component owner)
|
||||
: base(owner)
|
||||
{
|
||||
Buttons = new List<SpeckleComponentButton>()
|
||||
{
|
||||
new SpeckleComponentButton()
|
||||
{
|
||||
Text = "Select project",
|
||||
Palette = GH_Palette.Blue,
|
||||
Height = 18
|
||||
},
|
||||
new SpeckleComponentButton()
|
||||
{
|
||||
Text = "Select model",
|
||||
Palette = GH_Palette.Blue,
|
||||
Height = 18
|
||||
},
|
||||
new SpeckleComponentButton()
|
||||
{
|
||||
Text = "Select version",
|
||||
Palette = GH_Palette.Blue,
|
||||
Height = 18
|
||||
},
|
||||
new SpeckleComponentButton() { Text = "Test 2", Palette = GH_Palette.Black },
|
||||
};
|
||||
}
|
||||
|
||||
public override bool Selected
|
||||
{
|
||||
get => _selected;
|
||||
set => _selected = value;
|
||||
}
|
||||
|
||||
protected override void Layout()
|
||||
{
|
||||
base.Layout();
|
||||
|
||||
var baseRec = GH_Convert.ToRectangle(Bounds);
|
||||
|
||||
for (int i = 0; i < Buttons.Count; i++)
|
||||
{
|
||||
var button = Buttons[i];
|
||||
|
||||
var buttonBounds = i == 0 ? baseRec : Buttons[i - 1].ButtonBounds;
|
||||
buttonBounds.Y = buttonBounds.Bottom;
|
||||
buttonBounds.Height = button.Height;
|
||||
buttonBounds.Width = baseRec.Width;
|
||||
button.ButtonBounds = buttonBounds;
|
||||
baseRec.Height += button.Height;
|
||||
Bounds = baseRec;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Render(GH_Canvas canvas, Graphics graphics, GH_CanvasChannel channel)
|
||||
{
|
||||
base.Render(canvas, graphics, channel);
|
||||
|
||||
var state = ((ReceiveAsyncComponent)Owner).CurrentComponentState;
|
||||
|
||||
if (channel == GH_CanvasChannel.Objects)
|
||||
{
|
||||
// if (((ReceiveAsyncComponent)Owner).AutoReceive)
|
||||
// {
|
||||
// var autoReceiveButton = GH_Capsule.CreateTextCapsule(
|
||||
// ButtonBounds,
|
||||
// ButtonBounds,
|
||||
// GH_Palette.Blue,
|
||||
// "Auto Receive",
|
||||
// 2,
|
||||
// 0
|
||||
// );
|
||||
//
|
||||
// autoReceiveButton.Render(graphics, Selected, Owner.Locked, false);
|
||||
// autoReceiveButton.Dispose();
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// var palette =
|
||||
// state == ComponentState.Expired || state == ComponentState.UpToDate || state == ComponentState.Cancelled
|
||||
// ? GH_Palette.Black
|
||||
// : GH_Palette.Transparent;
|
||||
// var text = state != ComponentState.Receiving ? "Receive" : "Receiving...";
|
||||
//
|
||||
// var button = GH_Capsule.CreateTextCapsule(
|
||||
// ButtonBounds,
|
||||
// ButtonBounds,
|
||||
// palette,
|
||||
// text,
|
||||
// 2,
|
||||
// state == ComponentState.Expired ? 10 : 0
|
||||
// );
|
||||
// button.Render(graphics, Selected, Owner.Locked, false);
|
||||
// button.Dispose();
|
||||
// }
|
||||
|
||||
foreach (var button in Buttons)
|
||||
{
|
||||
using var b = GH_Capsule.CreateTextCapsule(
|
||||
button.ButtonBounds,
|
||||
button.ButtonBounds,
|
||||
button.Palette,
|
||||
button.Text,
|
||||
2,
|
||||
0
|
||||
);
|
||||
b.Render(graphics, Selected, Owner.Locked, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override GH_ObjectResponse RespondToMouseDown(GH_Canvas sender, GH_CanvasMouseEvent e)
|
||||
{
|
||||
if (e.Button != MouseButtons.Left)
|
||||
{
|
||||
return base.RespondToMouseDown(sender, e);
|
||||
}
|
||||
|
||||
foreach (var button in Buttons)
|
||||
{
|
||||
if (((RectangleF)button.ButtonBounds).Contains(e.CanvasLocation))
|
||||
{
|
||||
Debug.WriteLine($"Button was pressed: {button.Text}");
|
||||
return GH_ObjectResponse.Handled;
|
||||
}
|
||||
}
|
||||
|
||||
return base.RespondToMouseDown(sender, e);
|
||||
|
||||
// if (!((RectangleF)ButtonBounds).Contains(e.CanvasLocation))
|
||||
// {
|
||||
// return base.RespondToMouseDown(sender, e);
|
||||
// }
|
||||
//
|
||||
// if (((ReceiveAsyncComponent)Owner).CurrentComponentState == ComponentState.Receiving)
|
||||
// {
|
||||
// return GH_ObjectResponse.Handled;
|
||||
// }
|
||||
//
|
||||
// if (((ReceiveAsyncComponent)Owner).AutoReceive)
|
||||
// {
|
||||
// ((ReceiveAsyncComponent)Owner).AutoReceive = false;
|
||||
// Owner.OnDisplayExpired(true);
|
||||
// return GH_ObjectResponse.Handled;
|
||||
// }
|
||||
//
|
||||
// // TODO: check if owner has null account/client, and call the reset thing SYNC
|
||||
// ((ReceiveAsyncComponent)Owner).CurrentComponentState = ComponentState.Ready;
|
||||
// Owner.ExpireSolution(true);
|
||||
// return GH_ObjectResponse.Handled;
|
||||
}
|
||||
}
|
||||
+208
@@ -0,0 +1,208 @@
|
||||
using Grasshopper.Kernel;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Rhino.Geometry;
|
||||
using Speckle.Connectors.Common.Instances;
|
||||
using Speckle.Connectors.Common.Operations;
|
||||
using Speckle.Connectors.Common.Operations.Receive;
|
||||
using Speckle.Connectors.Grasshopper8.Components.BaseComponents;
|
||||
using Speckle.Connectors.Grasshopper8.HostApp;
|
||||
using Speckle.Connectors.Grasshopper8.Operations.Receive;
|
||||
using Speckle.Connectors.Grasshopper8.Parameters;
|
||||
using Speckle.Sdk;
|
||||
using Speckle.Sdk.Api;
|
||||
using Speckle.Sdk.Common.Exceptions;
|
||||
using Speckle.Sdk.Credentials;
|
||||
using Speckle.Sdk.Models;
|
||||
using Speckle.Sdk.Models.Collections;
|
||||
|
||||
namespace Speckle.Connectors.Grasshopper8.Components.Operations.Receive;
|
||||
|
||||
public class ReceiveComponentOutput
|
||||
{
|
||||
public SpeckleCollectionWrapperGoo RootObject { get; set; }
|
||||
}
|
||||
|
||||
public class ReceiveComponent : SpeckleScopedTaskCapableComponent<SpeckleUrlModelResource, ReceiveComponentOutput>
|
||||
{
|
||||
public ReceiveComponent()
|
||||
: base(
|
||||
"Receive from Speckle",
|
||||
"RFS",
|
||||
"Receive objects from speckle",
|
||||
ComponentCategories.PRIMARY_RIBBON,
|
||||
ComponentCategories.OPERATIONS
|
||||
) { }
|
||||
|
||||
public override Guid ComponentGuid => new("74954F59-B1B7-41FD-97DE-4C6B005F2801");
|
||||
protected override Bitmap Icon => BitmapBuilder.CreateSquareIconBitmap("R");
|
||||
|
||||
protected override void RegisterInputParams(GH_InputParamManager pManager)
|
||||
{
|
||||
pManager.AddParameter(new SpeckleUrlModelResourceParam(GH_ParamAccess.item));
|
||||
}
|
||||
|
||||
protected override void RegisterOutputParams(GH_OutputParamManager pManager)
|
||||
{
|
||||
pManager.AddParameter(
|
||||
new SpeckleCollectionParam(GH_ParamAccess.item),
|
||||
"Model",
|
||||
"model",
|
||||
"The model object for the received version",
|
||||
GH_ParamAccess.item
|
||||
);
|
||||
}
|
||||
|
||||
protected override SpeckleUrlModelResource GetInput(IGH_DataAccess da)
|
||||
{
|
||||
SpeckleUrlModelResource? url = null;
|
||||
da.GetData(0, ref url);
|
||||
if (url is null)
|
||||
{
|
||||
throw new SpeckleException("Speckle url is null");
|
||||
}
|
||||
|
||||
return url;
|
||||
}
|
||||
|
||||
protected override void SetOutput(IGH_DataAccess da, ReceiveComponentOutput result)
|
||||
{
|
||||
da.SetData(0, result.RootObject);
|
||||
Message = "Done";
|
||||
}
|
||||
|
||||
protected override async Task<ReceiveComponentOutput> PerformScopedTask(
|
||||
SpeckleUrlModelResource input,
|
||||
IServiceScope scope,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
// TODO: Resolving dependencies here may be overkill in most cases. Must re-evaluate.
|
||||
var accountManager = scope.ServiceProvider.GetRequiredService<AccountService>();
|
||||
var clientFactory = scope.ServiceProvider.GetRequiredService<IClientFactory>();
|
||||
var receiveOperation = scope.ServiceProvider.GetRequiredService<GrasshopperReceiveOperation>();
|
||||
|
||||
// Do the thing 👇🏼
|
||||
|
||||
// TODO: Get any account for this server, as we don't have a mechanism yet to pass accountIds through
|
||||
var account = accountManager.GetAccountWithServerUrlFallback("", new Uri(input.Server));
|
||||
|
||||
if (account is null)
|
||||
{
|
||||
throw new SpeckleAccountManagerException($"No default account was found");
|
||||
}
|
||||
|
||||
using var client = clientFactory.Create(account);
|
||||
var receiveInfo = await input.GetReceiveInfo(client, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var progress = new Progress<CardProgress>(_ =>
|
||||
{
|
||||
// TODO: Progress only makes sense in non-blocking async receive, which is not supported yet.
|
||||
// Message = $"{progress.Status}: {progress.Progress}";
|
||||
});
|
||||
|
||||
var root = await receiveOperation
|
||||
.ReceiveCommitObject(receiveInfo, progress, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
// We need to rethink these lovely unpackers, there's a bit too many of 'em
|
||||
var rootObjectUnpacker = scope.ServiceProvider.GetService<RootObjectUnpacker>();
|
||||
var localToGlobalUnpacker = new LocalToGlobalUnpacker();
|
||||
var traversalContextUnpacker = new TraversalContextUnpacker();
|
||||
|
||||
var unpackedRoot = rootObjectUnpacker.Unpack(root);
|
||||
|
||||
// "flatten" block instances
|
||||
var localToGlobalMaps = localToGlobalUnpacker.Unpack(
|
||||
unpackedRoot.DefinitionProxies,
|
||||
unpackedRoot.ObjectsToConvert.ToList()
|
||||
);
|
||||
|
||||
var collectionRebuilder = new GrasshopperCollectionRebuilder(
|
||||
(root as Collection) ?? new Collection() { name = "unnamed" }
|
||||
);
|
||||
|
||||
foreach (var map in localToGlobalMaps)
|
||||
{
|
||||
try
|
||||
{
|
||||
List<GeometryBase> converted = Convert(map.AtomicObject);
|
||||
List<Collection> path = traversalContextUnpacker.GetCollectionPath(map.TraversalContext).ToList();
|
||||
|
||||
foreach (var matrix in map.Matrix)
|
||||
{
|
||||
var mat = GrasshopperHelpers.MatrixToTransform(matrix, "meters");
|
||||
converted.ForEach(res => res.Transform(mat));
|
||||
}
|
||||
|
||||
// get the collection
|
||||
SpeckleCollectionWrapper objectCollection = collectionRebuilder.GetOrCreateSpeckleCollectionFromPath(path);
|
||||
|
||||
// get the name and properties
|
||||
SpecklePropertyGroupGoo propertyGroup = new();
|
||||
string name = "";
|
||||
if (map.AtomicObject is Speckle.Objects.Data.DataObject da)
|
||||
{
|
||||
propertyGroup.CastFrom(da.properties);
|
||||
name = da.name;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (map.AtomicObject["properties"] is Dictionary<string, object?> props)
|
||||
{
|
||||
propertyGroup.CastFrom(props);
|
||||
}
|
||||
|
||||
if (map.AtomicObject["name"] is string n)
|
||||
{
|
||||
name = n;
|
||||
}
|
||||
}
|
||||
|
||||
// create objects for every value in converted. This is where one to many is not handled very nicely.
|
||||
foreach (var geometryBase in converted)
|
||||
{
|
||||
var gh = new SpeckleObjectWrapper()
|
||||
{
|
||||
Base = map.AtomicObject,
|
||||
Path = path.Select(p => p.name).ToList(),
|
||||
Parent = objectCollection,
|
||||
GeometryBase = geometryBase,
|
||||
Properties = propertyGroup,
|
||||
Name = name
|
||||
};
|
||||
|
||||
collectionRebuilder.AppendSpeckleGrasshopperObject(gh, path);
|
||||
}
|
||||
}
|
||||
catch (ConversionException)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
|
||||
// var x = new SpeckleCollectionGoo { Value = collGen.RootCollection };
|
||||
var goo = new SpeckleCollectionWrapperGoo(collectionRebuilder.RootCollectionWrapper);
|
||||
return new ReceiveComponentOutput { RootObject = goo };
|
||||
}
|
||||
|
||||
private List<GeometryBase> Convert(Base input)
|
||||
{
|
||||
var result = ToSpeckleConversionContext.ToHostConverter.Convert(input);
|
||||
|
||||
if (result is GeometryBase geometry)
|
||||
{
|
||||
return [geometry];
|
||||
}
|
||||
if (result is List<GeometryBase> geometryList)
|
||||
{
|
||||
return geometryList;
|
||||
}
|
||||
if (result is List<(GeometryBase, Base)> fallbackConversionResult)
|
||||
{
|
||||
// note special handling for proxying render materials OR we don't care about revit
|
||||
return fallbackConversionResult.Select(t => t.Item1).ToList();
|
||||
}
|
||||
|
||||
throw new SpeckleException("Failed to convert input to rhino");
|
||||
}
|
||||
}
|
||||
+503
@@ -0,0 +1,503 @@
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Timers;
|
||||
using Grasshopper.GUI;
|
||||
using Grasshopper.GUI.Canvas;
|
||||
using Grasshopper.Kernel;
|
||||
using Grasshopper.Kernel.Attributes;
|
||||
using GrasshopperAsyncComponent;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Rhino;
|
||||
using Speckle.Connectors.Common.Operations;
|
||||
using Speckle.Connectors.Grasshopper8.HostApp;
|
||||
using Speckle.Connectors.Grasshopper8.Parameters;
|
||||
using Speckle.Connectors.Grasshopper8.Registration;
|
||||
using Speckle.Converters.Common;
|
||||
using Speckle.Converters.Rhino;
|
||||
using Speckle.Sdk;
|
||||
using Speckle.Sdk.Api;
|
||||
using Speckle.Sdk.Credentials;
|
||||
using Speckle.Sdk.Models.Extensions;
|
||||
|
||||
namespace Speckle.Connectors.Grasshopper8.Components.Operations.Send;
|
||||
|
||||
[Guid("52481972-7867-404F-8D9F-E1481183F355")]
|
||||
public class SendAsyncComponent : GH_AsyncComponent
|
||||
{
|
||||
public SendAsyncComponent()
|
||||
: base(
|
||||
"Async Send",
|
||||
"aS",
|
||||
"Send objects async to speckle",
|
||||
ComponentCategories.PRIMARY_RIBBON,
|
||||
ComponentCategories.OPERATIONS
|
||||
)
|
||||
{
|
||||
BaseWorker = new SendComponentWorker(this);
|
||||
Attributes = new SendAsyncComponentAttributes(this);
|
||||
}
|
||||
|
||||
public override Guid ComponentGuid => GetType().GUID;
|
||||
|
||||
protected override Bitmap Icon => BitmapBuilder.CreateSquareIconBitmap("aS");
|
||||
|
||||
public ComponentState CurrentComponentState { get; set; } = ComponentState.NeedsInput;
|
||||
public bool AutoSend { get; set; }
|
||||
public bool JustPastedIn { get; set; }
|
||||
public double OverallProgress { get; set; }
|
||||
public string? Url { get; set; }
|
||||
public Client ApiClient { get; set; }
|
||||
public HostApp.SpeckleUrlModelResource? UrlModelResource { get; set; }
|
||||
public SpeckleCollectionWrapperGoo? RootCollectionWrapper { get; set; }
|
||||
|
||||
public SpeckleUrlModelResource? OutputParam { get; set; }
|
||||
public SendOperation<SpeckleCollectionWrapperGoo> SendOperation { get; private set; }
|
||||
public static IServiceScope? Scope { get; set; }
|
||||
|
||||
protected override void RegisterInputParams(GH_InputParamManager pManager)
|
||||
{
|
||||
pManager.AddParameter(new SpeckleUrlModelResourceParam());
|
||||
pManager.AddParameter(
|
||||
new SpeckleCollectionParam(GH_ParamAccess.item),
|
||||
"Model",
|
||||
"model",
|
||||
"The collection model object to send",
|
||||
GH_ParamAccess.item
|
||||
);
|
||||
}
|
||||
|
||||
protected override void RegisterOutputParams(GH_OutputParamManager pManager)
|
||||
{
|
||||
pManager.AddParameter(new SpeckleUrlModelResourceParam());
|
||||
}
|
||||
|
||||
public override void AppendAdditionalMenuItems(ToolStripDropDown menu)
|
||||
{
|
||||
static void Open(string url)
|
||||
{
|
||||
var psi = new ProcessStartInfo { FileName = url, UseShellExecute = true };
|
||||
Process.Start(psi);
|
||||
}
|
||||
|
||||
base.AppendAdditionalMenuItems(menu);
|
||||
|
||||
Menu_AppendSeparator(menu);
|
||||
|
||||
var autoSendMi = Menu_AppendItem(
|
||||
menu,
|
||||
"Send automatically",
|
||||
(s, e) =>
|
||||
{
|
||||
AutoSend = !AutoSend;
|
||||
RhinoApp.InvokeOnUiThread(
|
||||
(Action)
|
||||
delegate
|
||||
{
|
||||
OnDisplayExpired(true);
|
||||
}
|
||||
);
|
||||
},
|
||||
true,
|
||||
AutoSend
|
||||
);
|
||||
autoSendMi.ToolTipText =
|
||||
"Toggle automatic data sending. If set, any change in any of the input parameters of this component will start sending.\n Please be aware that if a new send starts before an old one is finished, the previous operation is cancelled.";
|
||||
|
||||
if (Url != null)
|
||||
{
|
||||
Menu_AppendSeparator(menu);
|
||||
|
||||
Menu_AppendItem(menu, $"View created version online ↗", (s, e) => Open(Url));
|
||||
}
|
||||
|
||||
Menu_AppendSeparator(menu);
|
||||
|
||||
if (CurrentComponentState == ComponentState.Sending)
|
||||
{
|
||||
Menu_AppendItem(
|
||||
menu,
|
||||
"Cancel Send",
|
||||
(s, e) =>
|
||||
{
|
||||
CurrentComponentState = ComponentState.Expired;
|
||||
RequestCancellation();
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void SolveInstance(IGH_DataAccess da)
|
||||
{
|
||||
// Dependency Injection
|
||||
Scope = PriorityLoader.Container.CreateScope();
|
||||
SendOperation = Scope.ServiceProvider.GetRequiredService<SendOperation<SpeckleCollectionWrapperGoo>>();
|
||||
var rhinoConversionSettingsFactory = Scope.ServiceProvider.GetRequiredService<IRhinoConversionSettingsFactory>();
|
||||
Scope
|
||||
.ServiceProvider.GetRequiredService<IConverterSettingsStore<RhinoConversionSettings>>()
|
||||
.Initialize(rhinoConversionSettingsFactory.Create(RhinoDoc.ActiveDoc));
|
||||
|
||||
var accountManager = Scope.ServiceProvider.GetRequiredService<AccountService>();
|
||||
var clientFactory = Scope.ServiceProvider.GetRequiredService<IClientFactory>();
|
||||
|
||||
// We need to call this always in here to be able to react and set events :/
|
||||
ParseInput(da, accountManager, clientFactory);
|
||||
|
||||
if (
|
||||
(AutoSend || CurrentComponentState == ComponentState.Ready || CurrentComponentState == ComponentState.Sending)
|
||||
&& !JustPastedIn
|
||||
)
|
||||
{
|
||||
CurrentComponentState = ComponentState.Sending;
|
||||
|
||||
// Delegate control to parent async component.
|
||||
base.SolveInstance(da);
|
||||
return;
|
||||
}
|
||||
|
||||
if (JustPastedIn)
|
||||
{
|
||||
// Set output data in a "first run" event. Note: we are not persisting the actual "sent" object as it can be very big.
|
||||
base.SolveInstance(da);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
da.SetData(0, OutputParam);
|
||||
CurrentComponentState = ComponentState.Expired;
|
||||
Message = "Expired";
|
||||
OnDisplayExpired(true);
|
||||
}
|
||||
}
|
||||
|
||||
public override void RemovedFromDocument(GH_Document document)
|
||||
{
|
||||
RequestCancellation();
|
||||
Scope?.Dispose();
|
||||
base.RemovedFromDocument(document);
|
||||
}
|
||||
|
||||
public override void DisplayProgress(object sender, ElapsedEventArgs e)
|
||||
{
|
||||
if (Workers.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Message = "";
|
||||
var total = 0.0;
|
||||
foreach (var kvp in ProgressReports)
|
||||
{
|
||||
Message += $"{kvp.Key}: {kvp.Value}\n";
|
||||
total += kvp.Value;
|
||||
}
|
||||
|
||||
OverallProgress = total / ProgressReports.Keys.Count;
|
||||
|
||||
RhinoApp.InvokeOnUiThread(
|
||||
(Action)
|
||||
delegate
|
||||
{
|
||||
OnDisplayExpired(true);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public override void DocumentContextChanged(GH_Document document, GH_DocumentContext context)
|
||||
{
|
||||
switch (context)
|
||||
{
|
||||
case GH_DocumentContext.Loaded:
|
||||
OnDisplayExpired(true);
|
||||
break;
|
||||
|
||||
case GH_DocumentContext.Unloaded:
|
||||
// Will execute every time a document becomes inactive (in background or closing file.)
|
||||
//Correctly dispose of the client when changing documents to prevent subscription handlers being called in background.
|
||||
RequestCancellation();
|
||||
break;
|
||||
}
|
||||
|
||||
base.DocumentContextChanged(document, context);
|
||||
}
|
||||
|
||||
private void ParseInput(IGH_DataAccess da, AccountService accountManager, IClientFactory clientFactory)
|
||||
{
|
||||
HostApp.SpeckleUrlModelResource? dataInput = null;
|
||||
da.GetData(0, ref dataInput);
|
||||
if (dataInput is null)
|
||||
{
|
||||
UrlModelResource = null;
|
||||
TriggerAutoSave();
|
||||
return;
|
||||
}
|
||||
|
||||
UrlModelResource = dataInput;
|
||||
try
|
||||
{
|
||||
// TODO: Get any account for this server, as we don't have a mechanism yet to pass accountIds through
|
||||
Account account = accountManager.GetAccountWithServerUrlFallback("", new Uri(dataInput.Server));
|
||||
if (account is null)
|
||||
{
|
||||
throw new SpeckleAccountManagerException($"No default account was found");
|
||||
}
|
||||
|
||||
ApiClient?.Dispose();
|
||||
ApiClient = clientFactory.Create(account);
|
||||
}
|
||||
catch (Exception e) when (!e.IsFatal())
|
||||
{
|
||||
AddRuntimeMessage(GH_RuntimeMessageLevel.Error, e.ToFormattedString());
|
||||
}
|
||||
|
||||
SpeckleCollectionWrapperGoo rootCollectionWrapper = new();
|
||||
da.GetData(1, ref rootCollectionWrapper);
|
||||
if (rootCollectionWrapper is null)
|
||||
{
|
||||
RootCollectionWrapper = null;
|
||||
TriggerAutoSave();
|
||||
return;
|
||||
}
|
||||
RootCollectionWrapper = rootCollectionWrapper;
|
||||
}
|
||||
}
|
||||
|
||||
public class SendComponentWorker : WorkerInstance
|
||||
{
|
||||
public SendComponentWorker(GH_Component p)
|
||||
: base(p) { }
|
||||
|
||||
private Stopwatch _stopwatch;
|
||||
public SpeckleUrlModelResource? OutputParam { get; set; }
|
||||
private List<(GH_RuntimeMessageLevel, string)> RuntimeMessages { get; } = new();
|
||||
|
||||
public override WorkerInstance Duplicate()
|
||||
{
|
||||
return new SendComponentWorker(Parent);
|
||||
}
|
||||
|
||||
public override void GetData(IGH_DataAccess da, GH_ComponentParamServer p)
|
||||
{
|
||||
_stopwatch = new Stopwatch();
|
||||
_stopwatch.Start();
|
||||
}
|
||||
|
||||
public override void SetData(IGH_DataAccess da)
|
||||
{
|
||||
_stopwatch.Stop();
|
||||
|
||||
if (((SendAsyncComponent)Parent).JustPastedIn)
|
||||
{
|
||||
((SendAsyncComponent)Parent).JustPastedIn = false;
|
||||
da.SetData(0, ((SendAsyncComponent)Parent).OutputParam);
|
||||
return;
|
||||
}
|
||||
|
||||
if (CancellationToken.IsCancellationRequested)
|
||||
{
|
||||
((SendAsyncComponent)Parent).CurrentComponentState = ComponentState.Expired;
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var (level, message) in RuntimeMessages)
|
||||
{
|
||||
Parent.AddRuntimeMessage(level, message);
|
||||
}
|
||||
|
||||
da.SetData(0, OutputParam);
|
||||
|
||||
((SendAsyncComponent)Parent).CurrentComponentState = ComponentState.UpToDate;
|
||||
((SendAsyncComponent)Parent).OutputParam = OutputParam; // ref the outputs in the parent too, so we can serialise them on write/read
|
||||
((SendAsyncComponent)Parent).OverallProgress = 0;
|
||||
|
||||
var hasWarnings = RuntimeMessages.Count > 0;
|
||||
if (!hasWarnings)
|
||||
{
|
||||
Parent.AddRuntimeMessage(
|
||||
GH_RuntimeMessageLevel.Remark,
|
||||
$"Successfully sent {((SendAsyncComponent)Parent).RootCollectionWrapper?.Value.GetTotalChildrenCount()} objects to Speckle."
|
||||
);
|
||||
Parent.AddRuntimeMessage(
|
||||
GH_RuntimeMessageLevel.Remark,
|
||||
$"Send duration: {_stopwatch.ElapsedMilliseconds / 1000f}s"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public override void DoWork(Action<string, double> reportProgress, Action done)
|
||||
{
|
||||
var sendComponent = (SendAsyncComponent)Parent;
|
||||
|
||||
if (sendComponent.JustPastedIn)
|
||||
{
|
||||
done();
|
||||
return;
|
||||
}
|
||||
|
||||
if (CancellationToken.IsCancellationRequested)
|
||||
{
|
||||
sendComponent.CurrentComponentState = ComponentState.Expired;
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
SpeckleUrlModelResource? urlModelResource = sendComponent.UrlModelResource;
|
||||
if (urlModelResource is null)
|
||||
{
|
||||
throw new InvalidOperationException("Url Resource was null");
|
||||
}
|
||||
|
||||
SpeckleCollectionWrapperGoo? rootCollectionWrapper = sendComponent.RootCollectionWrapper;
|
||||
if (rootCollectionWrapper is null)
|
||||
{
|
||||
throw new InvalidOperationException("Root Collection was null");
|
||||
}
|
||||
|
||||
var t = Task.Run(async () =>
|
||||
{
|
||||
if (CancellationToken.IsCancellationRequested)
|
||||
{
|
||||
sendComponent.CurrentComponentState = ComponentState.Expired;
|
||||
return;
|
||||
}
|
||||
|
||||
// Step 1 - SEND TO SERVER
|
||||
var sendInfo = await urlModelResource
|
||||
.GetSendInfo(sendComponent.ApiClient, CancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
var progress = new Progress<CardProgress>(p =>
|
||||
{
|
||||
reportProgress(Id, p.Progress ?? 0);
|
||||
//sendComponent.Message = $"{p.Status}";
|
||||
});
|
||||
|
||||
var result = await sendComponent
|
||||
.SendOperation.Execute(
|
||||
new List<SpeckleCollectionWrapperGoo>() { rootCollectionWrapper },
|
||||
sendInfo,
|
||||
progress,
|
||||
CancellationToken
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
// TODO: need the created version id here from the send result, not the rootobj id
|
||||
SpeckleUrlModelVersionResource? createdVersion =
|
||||
new(sendInfo.ServerUrl.ToString(), sendInfo.ProjectId, sendInfo.ModelId, result.RootObjId);
|
||||
OutputParam = createdVersion;
|
||||
sendComponent.Url = $"{createdVersion.Server}projects/{sendInfo.ProjectId}/models/{sendInfo.ModelId}"; // TODO: missing "@VersionId"
|
||||
|
||||
// DONE
|
||||
done();
|
||||
});
|
||||
t.Wait();
|
||||
}
|
||||
catch (Exception ex) when (!ex.IsFatal())
|
||||
{
|
||||
RuntimeMessages.Add((GH_RuntimeMessageLevel.Error, ex.ToFormattedString()));
|
||||
done();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class SendAsyncComponentAttributes : GH_ComponentAttributes
|
||||
{
|
||||
private bool _selected;
|
||||
|
||||
public SendAsyncComponentAttributes(GH_Component owner)
|
||||
: base(owner) { }
|
||||
|
||||
private Rectangle ButtonBounds { get; set; }
|
||||
|
||||
public override bool Selected
|
||||
{
|
||||
get => _selected;
|
||||
set => _selected = value;
|
||||
}
|
||||
|
||||
protected override void Layout()
|
||||
{
|
||||
base.Layout();
|
||||
|
||||
var baseRec = GH_Convert.ToRectangle(Bounds);
|
||||
baseRec.Height += 26;
|
||||
|
||||
var btnRec = baseRec;
|
||||
btnRec.Y = btnRec.Bottom - 26;
|
||||
btnRec.Height = 26;
|
||||
btnRec.Inflate(-2, -2);
|
||||
|
||||
Bounds = baseRec;
|
||||
ButtonBounds = btnRec;
|
||||
}
|
||||
|
||||
protected override void Render(GH_Canvas canvas, Graphics graphics, GH_CanvasChannel channel)
|
||||
{
|
||||
base.Render(canvas, graphics, channel);
|
||||
|
||||
var state = ((SendAsyncComponent)Owner).CurrentComponentState;
|
||||
|
||||
if (channel == GH_CanvasChannel.Objects)
|
||||
{
|
||||
if (((SendAsyncComponent)Owner).AutoSend)
|
||||
{
|
||||
var autoSendButton = GH_Capsule.CreateTextCapsule(
|
||||
ButtonBounds,
|
||||
ButtonBounds,
|
||||
GH_Palette.Blue,
|
||||
"Auto Send",
|
||||
2,
|
||||
0
|
||||
);
|
||||
|
||||
autoSendButton.Render(graphics, Selected, Owner.Locked, false);
|
||||
autoSendButton.Dispose();
|
||||
}
|
||||
else
|
||||
{
|
||||
var palette =
|
||||
state == ComponentState.Expired || state == ComponentState.UpToDate
|
||||
? GH_Palette.Black
|
||||
: GH_Palette.Transparent;
|
||||
|
||||
var text = state == ComponentState.Sending ? "Sending..." : "Send";
|
||||
|
||||
var button = GH_Capsule.CreateTextCapsule(
|
||||
ButtonBounds,
|
||||
ButtonBounds,
|
||||
palette,
|
||||
text,
|
||||
2,
|
||||
state == ComponentState.Expired ? 10 : 0
|
||||
);
|
||||
button.Render(graphics, Selected, Owner.Locked, false);
|
||||
button.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override GH_ObjectResponse RespondToMouseDown(GH_Canvas sender, GH_CanvasMouseEvent e)
|
||||
{
|
||||
if (e.Button == MouseButtons.Left)
|
||||
{
|
||||
if (((RectangleF)ButtonBounds).Contains(e.CanvasLocation))
|
||||
{
|
||||
if (((SendAsyncComponent)Owner).AutoSend)
|
||||
{
|
||||
((SendAsyncComponent)Owner).AutoSend = false;
|
||||
Owner.OnDisplayExpired(true);
|
||||
return GH_ObjectResponse.Handled;
|
||||
}
|
||||
if (((SendAsyncComponent)Owner).CurrentComponentState == ComponentState.Sending)
|
||||
{
|
||||
return GH_ObjectResponse.Handled;
|
||||
}
|
||||
((SendAsyncComponent)Owner).CurrentComponentState = ComponentState.Ready;
|
||||
Owner.ExpireSolution(true);
|
||||
return GH_ObjectResponse.Handled;
|
||||
}
|
||||
}
|
||||
|
||||
return base.RespondToMouseDown(sender, e);
|
||||
}
|
||||
}
|
||||
+153
@@ -0,0 +1,153 @@
|
||||
using System.Diagnostics;
|
||||
using Grasshopper.Kernel;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Rhino;
|
||||
using Speckle.Connectors.Common.Operations;
|
||||
using Speckle.Connectors.Grasshopper8.Components.BaseComponents;
|
||||
using Speckle.Connectors.Grasshopper8.HostApp;
|
||||
using Speckle.Connectors.Grasshopper8.Parameters;
|
||||
using Speckle.Converters.Common;
|
||||
using Speckle.Converters.Rhino;
|
||||
using Speckle.Sdk;
|
||||
using Speckle.Sdk.Api;
|
||||
using Speckle.Sdk.Common;
|
||||
using Speckle.Sdk.Credentials;
|
||||
|
||||
namespace Speckle.Connectors.Grasshopper8.Components.Operations.Send;
|
||||
|
||||
public class SendComponentInput
|
||||
{
|
||||
public SpeckleUrlModelResource Resource { get; }
|
||||
public SpeckleCollectionWrapperGoo Input { get; }
|
||||
|
||||
public SendComponentInput(SpeckleUrlModelResource resource, SpeckleCollectionWrapperGoo input)
|
||||
{
|
||||
Resource = resource;
|
||||
Input = input;
|
||||
}
|
||||
}
|
||||
|
||||
public class SendComponentOutput(SpeckleUrlModelResource resource)
|
||||
{
|
||||
public SpeckleUrlModelResource Resource { get; } = resource;
|
||||
}
|
||||
|
||||
public class SendComponent : SpeckleScopedTaskCapableComponent<SendComponentInput, SendComponentOutput>
|
||||
{
|
||||
public SendComponent()
|
||||
: base(
|
||||
"Send to Speckle",
|
||||
"STS",
|
||||
"Send objects to speckle",
|
||||
ComponentCategories.PRIMARY_RIBBON,
|
||||
ComponentCategories.OPERATIONS
|
||||
) { }
|
||||
|
||||
public override Guid ComponentGuid => new("0CF0D173-BDF0-4AC2-9157-02822B90E9FB");
|
||||
|
||||
public string? Url { get; private set; }
|
||||
|
||||
protected override Bitmap Icon => BitmapBuilder.CreateSquareIconBitmap("S");
|
||||
|
||||
protected override void RegisterInputParams(GH_InputParamManager pManager)
|
||||
{
|
||||
pManager.AddParameter(new SpeckleUrlModelResourceParam());
|
||||
pManager.AddParameter(
|
||||
new SpeckleCollectionParam(GH_ParamAccess.item),
|
||||
"Model",
|
||||
"model",
|
||||
"The collection model object to send",
|
||||
GH_ParamAccess.item
|
||||
);
|
||||
}
|
||||
|
||||
protected override void RegisterOutputParams(GH_OutputParamManager pManager)
|
||||
{
|
||||
pManager.AddParameter(new SpeckleUrlModelResourceParam());
|
||||
}
|
||||
|
||||
protected override SendComponentInput GetInput(IGH_DataAccess da)
|
||||
{
|
||||
if (da.Iteration != 0)
|
||||
{
|
||||
throw new SpeckleException("No more than 1 resource allowed");
|
||||
}
|
||||
|
||||
SpeckleUrlModelResource? resource = null;
|
||||
if (!da.GetData(0, ref resource))
|
||||
{
|
||||
throw new SpeckleException("Failed to get resource");
|
||||
}
|
||||
|
||||
SpeckleCollectionWrapperGoo rootCollectionWrapper = new();
|
||||
da.GetData(1, ref rootCollectionWrapper);
|
||||
|
||||
return new SendComponentInput(resource.NotNull(), rootCollectionWrapper);
|
||||
}
|
||||
|
||||
protected override void SetOutput(IGH_DataAccess da, SendComponentOutput result)
|
||||
{
|
||||
da.SetData(0, result.Resource);
|
||||
}
|
||||
|
||||
public override void AppendAdditionalMenuItems(ToolStripDropDown menu)
|
||||
{
|
||||
base.AppendAdditionalMenuItems(menu);
|
||||
|
||||
Menu_AppendSeparator(menu);
|
||||
if (Url != null)
|
||||
{
|
||||
Menu_AppendSeparator(menu);
|
||||
|
||||
Menu_AppendItem(menu, $"View created version online ↗", (s, e) => Open(Url));
|
||||
}
|
||||
|
||||
static void Open(string url)
|
||||
{
|
||||
var psi = new ProcessStartInfo { FileName = url, UseShellExecute = true };
|
||||
Process.Start(psi);
|
||||
}
|
||||
}
|
||||
|
||||
protected override async Task<SendComponentOutput> PerformScopedTask(
|
||||
SendComponentInput input,
|
||||
IServiceScope scope,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
var rhinoConversionSettingsFactory = scope.ServiceProvider.GetRequiredService<IRhinoConversionSettingsFactory>();
|
||||
scope
|
||||
.ServiceProvider.GetRequiredService<IConverterSettingsStore<RhinoConversionSettings>>()
|
||||
.Initialize(rhinoConversionSettingsFactory.Create(RhinoDoc.ActiveDoc));
|
||||
|
||||
var accountManager = scope.ServiceProvider.GetRequiredService<AccountService>();
|
||||
var clientFactory = scope.ServiceProvider.GetRequiredService<IClientFactory>();
|
||||
var sendOperation = scope.ServiceProvider.GetRequiredService<SendOperation<SpeckleCollectionWrapperGoo>>();
|
||||
|
||||
// TODO: Get any account for this server, as we don't have a mechanism yet to pass accountIds through
|
||||
var account = accountManager.GetAccountWithServerUrlFallback("", new Uri(input.Resource.Server));
|
||||
|
||||
if (account is null)
|
||||
{
|
||||
throw new SpeckleAccountManagerException($"No default account was found");
|
||||
}
|
||||
|
||||
var progress = new Progress<CardProgress>(_ =>
|
||||
{
|
||||
// TODO: Progress only makes sense in non-blocking async receive, which is not supported yet.
|
||||
// Message = $"{progress.Status}: {progress.Progress}";
|
||||
});
|
||||
|
||||
using var client = clientFactory.Create(account);
|
||||
var sendInfo = await input.Resource.GetSendInfo(client, cancellationToken).ConfigureAwait(false);
|
||||
var result = await sendOperation
|
||||
.Execute(new List<SpeckleCollectionWrapperGoo>() { input.Input }, sendInfo, progress, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
SpeckleUrlLatestModelVersionResource createdVersionResource =
|
||||
new(sendInfo.ServerUrl.ToString(), sendInfo.ProjectId, sendInfo.ModelId);
|
||||
Url = $"{createdVersionResource.Server}projects/{sendInfo.ProjectId}/models/{sendInfo.ModelId}"; // TODO: missing "@VersionId"
|
||||
|
||||
return new SendComponentOutput(createdVersionResource);
|
||||
}
|
||||
}
|
||||
+507
@@ -0,0 +1,507 @@
|
||||
using GH_IO.Serialization;
|
||||
using Grasshopper.Kernel;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Speckle.Connectors.Common.Operations;
|
||||
using Speckle.Connectors.Grasshopper8.HostApp;
|
||||
using Speckle.Connectors.Grasshopper8.Parameters;
|
||||
using Speckle.Connectors.Grasshopper8.Registration;
|
||||
using Speckle.Sdk;
|
||||
using Speckle.Sdk.Api;
|
||||
using Speckle.Sdk.Api.GraphQL.Models;
|
||||
using Speckle.Sdk.Credentials;
|
||||
using Version = Speckle.Sdk.Api.GraphQL.Models.Version;
|
||||
|
||||
namespace Speckle.Connectors.Grasshopper8.Components.Operations;
|
||||
|
||||
public class SpeckleSelectModelComponent : GH_Component
|
||||
{
|
||||
private Project? _project;
|
||||
private Model? _model;
|
||||
private Version? _version;
|
||||
private Account? _account;
|
||||
|
||||
private bool _justPastedIn;
|
||||
|
||||
private string? _storedUserId;
|
||||
private string? _storedServer;
|
||||
private string? _storedProjectId;
|
||||
private string? _storedModelId;
|
||||
private string? _storedVersionId;
|
||||
|
||||
private readonly AccountService _accountService;
|
||||
private readonly AccountManager _accountManager;
|
||||
private readonly IClientFactory _clientFactory;
|
||||
|
||||
public ResourceCollection<Project>? LastFetchedProjects { get; set; }
|
||||
public ResourceCollection<Model>? LastFetchedModels { get; set; }
|
||||
public ResourceCollection<Version>? LastFetchedVersions { get; set; }
|
||||
|
||||
public GhContextMenuButton ProjectContextMenuButton { get; set; }
|
||||
public GhContextMenuButton ModelContextMenuButton { get; set; }
|
||||
public GhContextMenuButton VersionContextMenuButton { get; set; }
|
||||
|
||||
protected override Bitmap Icon => BitmapBuilder.CreateSquareIconBitmap("URL");
|
||||
|
||||
public SpeckleSelectModelComponent()
|
||||
: base("Speckle Model URL", "URL", "User selectable model from speckle", "Speckle", "Models")
|
||||
{
|
||||
ProjectContextMenuButton = new GhContextMenuButton(
|
||||
"Select Project",
|
||||
"Select Project",
|
||||
"Right-click to select project",
|
||||
PopulateProjectMenu
|
||||
);
|
||||
ModelContextMenuButton = new GhContextMenuButton(
|
||||
"Select Model",
|
||||
"Select Project",
|
||||
"Right-click to select a model",
|
||||
PopulateModelMenu
|
||||
);
|
||||
VersionContextMenuButton = new GhContextMenuButton(
|
||||
"Select Version",
|
||||
"Select Version",
|
||||
"Right-click to select a version",
|
||||
PopulateVersionMenu
|
||||
);
|
||||
|
||||
Attributes = new SpeckleSelectModelComponentAttributes(this);
|
||||
_accountService = PriorityLoader.Container.GetRequiredService<AccountService>();
|
||||
_accountManager = PriorityLoader.Container.GetRequiredService<AccountManager>();
|
||||
_clientFactory = PriorityLoader.Container.GetRequiredService<IClientFactory>();
|
||||
var account = _accountManager.GetDefaultAccount();
|
||||
OnAccountSelected(account);
|
||||
}
|
||||
|
||||
private bool PopulateVersionMenu(ToolStripDropDown menu)
|
||||
{
|
||||
if (LastFetchedVersions is null)
|
||||
{
|
||||
Menu_AppendItem(menu, "No versions were fetched");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (LastFetchedVersions.items.Count == 0)
|
||||
{
|
||||
Menu_AppendItem(menu, "Model has no versions");
|
||||
return true;
|
||||
}
|
||||
|
||||
Menu_AppendItem(menu, "Search...", null, null, false, false);
|
||||
Menu_AppendSeparator(menu);
|
||||
Menu_AppendItem(
|
||||
menu,
|
||||
"Latest Version",
|
||||
(_, _) => OnVersionSelected(null),
|
||||
null,
|
||||
_version != null,
|
||||
_version == null
|
||||
);
|
||||
|
||||
foreach (var version in LastFetchedVersions.items)
|
||||
{
|
||||
var desc = string.IsNullOrEmpty(version.message) ? "No description" : version.message;
|
||||
|
||||
Menu_AppendItem(
|
||||
menu,
|
||||
$"{version.id} - {desc}",
|
||||
(_, _) => OnVersionSelected(version),
|
||||
null,
|
||||
_version?.id != version.id,
|
||||
_version?.id == version.id
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool PopulateModelMenu(ToolStripDropDown menu)
|
||||
{
|
||||
if (LastFetchedModels == null)
|
||||
{
|
||||
Menu_AppendItem(menu, "No models were fetched");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (LastFetchedModels.items.Count == 0)
|
||||
{
|
||||
Menu_AppendItem(menu, "Project has no models");
|
||||
return true;
|
||||
}
|
||||
|
||||
Menu_AppendItem(menu, "Search...", null, null, false, false);
|
||||
Menu_AppendSeparator(menu);
|
||||
|
||||
foreach (var model in LastFetchedModels.items)
|
||||
{
|
||||
var desc = string.IsNullOrEmpty(model.description) ? "No description" : model.description;
|
||||
|
||||
Menu_AppendItem(
|
||||
menu,
|
||||
$"{model.name} - {desc}",
|
||||
(_, _) => OnModelSelected(model),
|
||||
null,
|
||||
_model?.id != model.id,
|
||||
_model?.id == model.id
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool PopulateProjectMenu(ToolStripDropDown menu)
|
||||
{
|
||||
if (LastFetchedProjects == null)
|
||||
{
|
||||
Menu_AppendItem(menu, "No projects were fetched");
|
||||
return true;
|
||||
}
|
||||
|
||||
Menu_AppendItem(menu, "Search...", null, null, false, false);
|
||||
Menu_AppendSeparator(menu);
|
||||
|
||||
foreach (var project in LastFetchedProjects.items)
|
||||
{
|
||||
var desc = string.IsNullOrEmpty(project.description) ? "No description" : project.description;
|
||||
Menu_AppendItem(
|
||||
menu,
|
||||
$"{project.name} - {desc}",
|
||||
(_, _) => OnProjectSelected(project),
|
||||
_project?.id != project.id,
|
||||
_project?.id == project.id
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void OnAccountSelected(Account? account, bool expire = true, bool redraw = true)
|
||||
{
|
||||
_account = account;
|
||||
Message = _account != null ? $"{_account.serverInfo.url}\n{_account.userInfo.email}" : null;
|
||||
LastFetchedProjects = null;
|
||||
OnProjectSelected(null, expire, redraw);
|
||||
}
|
||||
|
||||
private void OnProjectSelected(Project? project, bool expire = true, bool redraw = true)
|
||||
{
|
||||
_project = project;
|
||||
var suffix = ProjectContextMenuButton.Enabled
|
||||
? "Right-click to select another project."
|
||||
: "Selection is disabled due to component input.";
|
||||
if (_project != null)
|
||||
{
|
||||
ProjectContextMenuButton.Name = _project.name;
|
||||
ProjectContextMenuButton.NickName = _project.id;
|
||||
ProjectContextMenuButton.Description = $"{_project.description ?? "No description"}\n\n{suffix}";
|
||||
}
|
||||
else
|
||||
{
|
||||
ProjectContextMenuButton.Name = "Select Project";
|
||||
ProjectContextMenuButton.NickName = "Project";
|
||||
ProjectContextMenuButton.Description = "Right-click to select project";
|
||||
}
|
||||
LastFetchedModels = null;
|
||||
OnModelSelected(null, expire, redraw);
|
||||
}
|
||||
|
||||
private void OnModelSelected(Model? model, bool expire = true, bool redraw = true)
|
||||
{
|
||||
_model = model;
|
||||
var suffix = ModelContextMenuButton.Enabled
|
||||
? "Right-click to select another model."
|
||||
: "Selection is disabled due to component input.";
|
||||
if (_model != null)
|
||||
{
|
||||
ModelContextMenuButton.Name = _model.name;
|
||||
ModelContextMenuButton.NickName = _model.id;
|
||||
ModelContextMenuButton.Description = $"{_model.description ?? "No description"}\n\n{suffix}";
|
||||
}
|
||||
else
|
||||
{
|
||||
ModelContextMenuButton.Name = "Select Model";
|
||||
ModelContextMenuButton.NickName = "Model";
|
||||
ModelContextMenuButton.Description = "Right-click to select model";
|
||||
}
|
||||
LastFetchedVersions = null;
|
||||
OnVersionSelected(null, expire, redraw);
|
||||
}
|
||||
|
||||
private void OnVersionSelected(Version? version, bool expire = true, bool redraw = true)
|
||||
{
|
||||
_version = version;
|
||||
var suffix = VersionContextMenuButton.Enabled
|
||||
? "Right-click to select another version."
|
||||
: "Selection is disabled due to component input.";
|
||||
if (_version != null)
|
||||
{
|
||||
VersionContextMenuButton.Name = _version.id;
|
||||
VersionContextMenuButton.NickName = _version.id;
|
||||
VersionContextMenuButton.Description = $"{_version.message ?? "No message"}\n\n{suffix}";
|
||||
}
|
||||
else if (_model != null)
|
||||
{
|
||||
VersionContextMenuButton.NickName = "Latest Version";
|
||||
VersionContextMenuButton.Name = "Latest Version";
|
||||
VersionContextMenuButton.Description = "Gets the latest version from the selected model";
|
||||
}
|
||||
else
|
||||
{
|
||||
VersionContextMenuButton.Name = "Select Version";
|
||||
VersionContextMenuButton.NickName = "Version";
|
||||
VersionContextMenuButton.Description = "Right-click to select version";
|
||||
}
|
||||
if (expire)
|
||||
{
|
||||
ExpirePreview(redraw);
|
||||
ExpireSolution(true);
|
||||
}
|
||||
}
|
||||
|
||||
public override Guid ComponentGuid => new("9638B3B5-C469-4570-B69F-686D8DA5C48D");
|
||||
|
||||
protected override void RegisterInputParams(GH_InputParamManager pManager)
|
||||
{
|
||||
var urlIndex = pManager.AddTextParameter("Speckle Url", "Url", "Speckle URL", GH_ParamAccess.item);
|
||||
pManager[urlIndex].Optional = true;
|
||||
}
|
||||
|
||||
protected override void RegisterOutputParams(GH_OutputParamManager pManager)
|
||||
{
|
||||
pManager.AddParameter(new SpeckleUrlModelResourceParam());
|
||||
}
|
||||
|
||||
protected override void SolveInstance(IGH_DataAccess da)
|
||||
{
|
||||
// Deal with inputs
|
||||
string? urlInput = null;
|
||||
|
||||
// OPTION 1: Component has input wire connected
|
||||
if (da.GetData(0, ref urlInput))
|
||||
{
|
||||
//Lock button interactions before anything else, to ensure any input (even invalid ones) lock the state.
|
||||
SetComponentButtonsState(false);
|
||||
|
||||
if (urlInput == null || string.IsNullOrEmpty(urlInput))
|
||||
{
|
||||
AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Input url was empty or null");
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var resource = SolveInstanceWithUrlInput(urlInput);
|
||||
da.SetData(0, resource);
|
||||
}
|
||||
catch (SpeckleException e)
|
||||
{
|
||||
AddRuntimeMessage(GH_RuntimeMessageLevel.Error, e.Message);
|
||||
}
|
||||
return; // Fast exit!
|
||||
}
|
||||
|
||||
// OPTION 2: Component is running with no wires connected to input.
|
||||
|
||||
// Unlock button interactions when no input data is provided (no wires connected)
|
||||
SetComponentButtonsState(true);
|
||||
|
||||
if (_justPastedIn && _storedUserId != null && !string.IsNullOrEmpty(_storedUserId))
|
||||
{
|
||||
try
|
||||
{
|
||||
var account = _accountManager.GetAccount(_storedUserId);
|
||||
OnAccountSelected(account, false);
|
||||
}
|
||||
catch (SpeckleAccountManagerException e)
|
||||
{
|
||||
// Swallow and move onto checking server.
|
||||
Console.WriteLine(e);
|
||||
}
|
||||
|
||||
if (_storedServer != null && _account == null)
|
||||
{
|
||||
var account = _accountService.GetAccountWithServerUrlFallback(_storedUserId ?? "", new Uri(_storedServer));
|
||||
OnAccountSelected(account, false);
|
||||
}
|
||||
}
|
||||
|
||||
// Validate backing data
|
||||
if (_account == null)
|
||||
{
|
||||
AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Please select an account in the right click menu");
|
||||
ProjectContextMenuButton.Enabled = false;
|
||||
ModelContextMenuButton.Enabled = false;
|
||||
VersionContextMenuButton.Enabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
Client client = _clientFactory.Create(_account);
|
||||
|
||||
LastFetchedProjects = client.ActiveUser.GetProjects(10, null, null).Result;
|
||||
ProjectContextMenuButton.Enabled = true;
|
||||
|
||||
if (_justPastedIn && !string.IsNullOrEmpty(_storedProjectId))
|
||||
{
|
||||
var project = client.Project.Get(_storedProjectId!).Result;
|
||||
OnProjectSelected(project, false);
|
||||
}
|
||||
|
||||
if (_project == null)
|
||||
{
|
||||
ModelContextMenuButton.Enabled = false;
|
||||
VersionContextMenuButton.Enabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
LastFetchedModels = client.Project.GetWithModels(_project.id, 10).Result.models;
|
||||
ModelContextMenuButton.Enabled = true;
|
||||
|
||||
if (_justPastedIn && !string.IsNullOrEmpty(_storedModelId))
|
||||
{
|
||||
var model = client.Model.Get(_storedModelId!, _project.id).Result;
|
||||
OnModelSelected(model, false);
|
||||
}
|
||||
|
||||
if (_model == null)
|
||||
{
|
||||
VersionContextMenuButton.Enabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
LastFetchedVersions = client.Model.GetWithVersions(_model.id, _project.id, 10).Result.versions;
|
||||
VersionContextMenuButton.Enabled = true;
|
||||
|
||||
if (_justPastedIn && !string.IsNullOrEmpty(_storedVersionId))
|
||||
{
|
||||
var version = client.Version.Get(_storedVersionId!, _project.id).Result;
|
||||
OnVersionSelected(version);
|
||||
}
|
||||
if (_version == null)
|
||||
{
|
||||
// If no version selected, output `latest` resource
|
||||
da.SetData(0, new SpeckleUrlLatestModelVersionResource(_account.serverInfo.url, _project.id, _model.id));
|
||||
return;
|
||||
}
|
||||
|
||||
// If all data points are selected, output specific version.
|
||||
da.SetData(0, new SpeckleUrlModelVersionResource(_account.serverInfo.url, _project.id, _model.id, _version.id));
|
||||
}
|
||||
|
||||
protected override void AfterSolveInstance()
|
||||
{
|
||||
// If the component runs once till the end, then it's no longer "just pasted in".
|
||||
_justPastedIn = false;
|
||||
base.AfterSolveInstance();
|
||||
}
|
||||
|
||||
private void SetComponentButtonsState(bool enabled)
|
||||
{
|
||||
ProjectContextMenuButton.Enabled = enabled;
|
||||
ModelContextMenuButton.Enabled = enabled;
|
||||
VersionContextMenuButton.Enabled = enabled;
|
||||
}
|
||||
|
||||
private SpeckleUrlModelResource SolveInstanceWithUrlInput(string urlInput)
|
||||
{
|
||||
// When input is provided, lock interaction of buttons so only text is shown (no context menu)
|
||||
// Should perform validation, fill in all internal data of the component (project, model, version, account)
|
||||
// Should notify user if any of this goes wrong.
|
||||
|
||||
var resources = SpeckleResourceBuilder.FromUrlString(urlInput);
|
||||
if (resources.Length == 0)
|
||||
{
|
||||
throw new SpeckleException($"Input url string was empty");
|
||||
}
|
||||
|
||||
if (resources.Length > 1)
|
||||
{
|
||||
throw new SpeckleException($"Input multi-model url is not supported");
|
||||
}
|
||||
|
||||
var resource = resources.First();
|
||||
|
||||
var account = _accountService.GetAccountWithServerUrlFallback(string.Empty, new Uri(resource.Server));
|
||||
OnAccountSelected(account, false);
|
||||
|
||||
if (_account == null)
|
||||
{
|
||||
throw new SpeckleException("No account found for server URL");
|
||||
}
|
||||
|
||||
Client client = _clientFactory.Create(_account);
|
||||
|
||||
var project = client.Project.Get(resource.ProjectId).Result;
|
||||
OnProjectSelected(project, false);
|
||||
|
||||
switch (resource)
|
||||
{
|
||||
case SpeckleUrlLatestModelVersionResource latestVersionResource:
|
||||
var model = client.Model.Get(latestVersionResource.ModelId, latestVersionResource.ProjectId).Result;
|
||||
OnModelSelected(model, false);
|
||||
break;
|
||||
case SpeckleUrlModelVersionResource versionResource:
|
||||
var m = client.Model.Get(versionResource.ModelId, versionResource.ProjectId).Result;
|
||||
OnModelSelected(m, false);
|
||||
var v = client.Version.Get(versionResource.VersionId, versionResource.ProjectId).Result;
|
||||
OnVersionSelected(v, false);
|
||||
break;
|
||||
case SpeckleUrlModelObjectResource:
|
||||
throw new SpeckleException("Object URLs are not supported");
|
||||
default:
|
||||
throw new SpeckleException("Unknown Speckle resource type");
|
||||
}
|
||||
|
||||
return resource;
|
||||
}
|
||||
|
||||
public override void AppendAdditionalMenuItems(ToolStripDropDown menu)
|
||||
{
|
||||
base.AppendAdditionalMenuItems(menu);
|
||||
var accountsMenu = Menu_AppendItem(menu, "Account");
|
||||
|
||||
foreach (var account in _accountManager.GetAccounts())
|
||||
{
|
||||
Menu_AppendItem(
|
||||
accountsMenu.DropDown,
|
||||
account.ToString(),
|
||||
(_, _) => OnAccountSelected(account),
|
||||
null,
|
||||
_account?.id != account.id,
|
||||
_account?.id == account.id
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Write(GH_IWriter writer)
|
||||
{
|
||||
var baseRes = base.Write(writer);
|
||||
writer.SetString("Server", _account?.serverInfo.url);
|
||||
writer.SetString("User", _account?.id);
|
||||
writer.SetString("Project", _project?.id);
|
||||
writer.SetString("Model", _model?.id);
|
||||
writer.SetString("Version", _version?.id);
|
||||
|
||||
return baseRes;
|
||||
}
|
||||
|
||||
public override bool Read(GH_IReader reader)
|
||||
{
|
||||
var readRes = base.Read(reader);
|
||||
|
||||
reader.TryGetString("Server", ref _storedServer);
|
||||
reader.TryGetString("User", ref _storedUserId);
|
||||
reader.TryGetString("Project", ref _storedProjectId);
|
||||
reader.TryGetString("Model", ref _storedModelId);
|
||||
reader.TryGetString("Version", ref _storedVersionId);
|
||||
|
||||
_justPastedIn = true;
|
||||
return readRes;
|
||||
}
|
||||
|
||||
public override void ExpirePreview(bool redraw)
|
||||
{
|
||||
ProjectContextMenuButton.ExpirePreview(redraw);
|
||||
ModelContextMenuButton.ExpirePreview(redraw);
|
||||
VersionContextMenuButton.ExpirePreview(redraw);
|
||||
base.ExpirePreview(redraw);
|
||||
}
|
||||
}
|
||||
+97
@@ -0,0 +1,97 @@
|
||||
using Grasshopper.GUI.Canvas;
|
||||
using Grasshopper.Kernel;
|
||||
using Grasshopper.Kernel.Attributes;
|
||||
|
||||
namespace Speckle.Connectors.Grasshopper8.Components.Operations;
|
||||
|
||||
public class SpeckleSelectModelComponentAttributes : GH_ComponentAttributes
|
||||
{
|
||||
private readonly SpeckleSelectModelComponent _typedOwner;
|
||||
|
||||
public SpeckleSelectModelComponentAttributes(IGH_Component component)
|
||||
: base(component)
|
||||
{
|
||||
_typedOwner = (SpeckleSelectModelComponent)component;
|
||||
}
|
||||
|
||||
public override void AppendToAttributeTree(List<IGH_Attributes> attributes)
|
||||
{
|
||||
base.AppendToAttributeTree(attributes);
|
||||
_typedOwner.ProjectContextMenuButton.Attributes?.AppendToAttributeTree(attributes);
|
||||
_typedOwner.ModelContextMenuButton.Attributes?.AppendToAttributeTree(attributes);
|
||||
_typedOwner.VersionContextMenuButton.Attributes?.AppendToAttributeTree(attributes);
|
||||
}
|
||||
|
||||
private void InitialiseAttributes()
|
||||
{
|
||||
if (_typedOwner.ProjectContextMenuButton.Attributes == null)
|
||||
{
|
||||
_typedOwner.ProjectContextMenuButton.Attributes = new GhContextMenuButtonAttributes(
|
||||
_typedOwner.ProjectContextMenuButton
|
||||
)
|
||||
{
|
||||
Parent = this,
|
||||
};
|
||||
}
|
||||
|
||||
if (_typedOwner.ModelContextMenuButton.Attributes == null)
|
||||
{
|
||||
_typedOwner.ModelContextMenuButton.Attributes = new GhContextMenuButtonAttributes(
|
||||
_typedOwner.ModelContextMenuButton
|
||||
)
|
||||
{
|
||||
Parent = this,
|
||||
Pivot = Pivot
|
||||
};
|
||||
}
|
||||
|
||||
if (_typedOwner.VersionContextMenuButton.Attributes == null)
|
||||
{
|
||||
_typedOwner.VersionContextMenuButton.Attributes = new GhContextMenuButtonAttributes(
|
||||
_typedOwner.VersionContextMenuButton
|
||||
)
|
||||
{
|
||||
Parent = this,
|
||||
Pivot = Pivot
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Layout()
|
||||
{
|
||||
base.Layout();
|
||||
var baseRec = GH_Convert.ToRectangle(Bounds);
|
||||
baseRec.Height += 26 * 3;
|
||||
|
||||
var btnRec = baseRec;
|
||||
btnRec.Y = baseRec.Bottom - 26 * 3;
|
||||
btnRec.Height = 26;
|
||||
btnRec.Inflate(-2, -2);
|
||||
|
||||
var btnRec2 = btnRec;
|
||||
btnRec2.Y = btnRec.Bottom + 2;
|
||||
|
||||
var btnRec3 = btnRec;
|
||||
btnRec3.Y = btnRec2.Bottom + 2;
|
||||
|
||||
Bounds = baseRec;
|
||||
InitialiseAttributes();
|
||||
// Both pivot and bounds require updating to proper render buttons on location
|
||||
_typedOwner.ProjectContextMenuButton.Attributes.Pivot = btnRec.Location;
|
||||
_typedOwner.ProjectContextMenuButton.Attributes.Bounds = btnRec;
|
||||
_typedOwner.ModelContextMenuButton.Attributes.Pivot = btnRec2.Location;
|
||||
_typedOwner.ModelContextMenuButton.Attributes.Bounds = btnRec2;
|
||||
_typedOwner.VersionContextMenuButton.Attributes.Pivot = btnRec3.Location;
|
||||
_typedOwner.VersionContextMenuButton.Attributes.Bounds = btnRec3;
|
||||
}
|
||||
|
||||
protected override void Render(GH_Canvas canvas, Graphics graphics, GH_CanvasChannel channel)
|
||||
{
|
||||
base.Render(canvas, graphics, channel);
|
||||
// Draw custom buttons and dropdowns
|
||||
|
||||
_typedOwner.ProjectContextMenuButton.Attributes.RenderToCanvas(canvas, channel);
|
||||
_typedOwner.ModelContextMenuButton.Attributes.RenderToCanvas(canvas, channel);
|
||||
_typedOwner.VersionContextMenuButton.Attributes.RenderToCanvas(canvas, channel);
|
||||
}
|
||||
}
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
using System.Runtime.InteropServices;
|
||||
using Grasshopper.Kernel;
|
||||
using Grasshopper.Kernel.Types;
|
||||
using Rhino.Geometry;
|
||||
using Speckle.Connectors.Grasshopper8.HostApp;
|
||||
using Speckle.Connectors.Grasshopper8.Parameters;
|
||||
using Speckle.Sdk.Models;
|
||||
|
||||
namespace Speckle.Connectors.Grasshopper8.Components.Properties;
|
||||
|
||||
[Guid("F9418610-ACAE-4417-B010-19EBEA6A121F")]
|
||||
public class CreateSpeckleObject : GH_Component
|
||||
{
|
||||
public CreateSpeckleObject()
|
||||
: base(
|
||||
"Create Speckle Object",
|
||||
"CSO",
|
||||
"Creates a Speckle Object",
|
||||
ComponentCategories.PRIMARY_RIBBON,
|
||||
ComponentCategories.OBJECTS
|
||||
) { }
|
||||
|
||||
public override Guid ComponentGuid => GetType().GUID;
|
||||
|
||||
protected override Bitmap Icon => BitmapBuilder.CreateCircleIconBitmap("cO");
|
||||
|
||||
protected override void RegisterInputParams(GH_InputParamManager pManager)
|
||||
{
|
||||
pManager.AddGenericParameter("Geometry", "G", "The geometry of the new Speckle Object", GH_ParamAccess.item);
|
||||
|
||||
pManager.AddTextParameter("Name", "N", "Name of the new Speckle Object", GH_ParamAccess.item);
|
||||
Params.Input[1].Optional = true;
|
||||
|
||||
pManager.AddParameter(
|
||||
new SpecklePropertyGroupParam(),
|
||||
"Properties",
|
||||
"P",
|
||||
"The properties of the new Speckle Object",
|
||||
GH_ParamAccess.item
|
||||
);
|
||||
Params.Input[2].Optional = true;
|
||||
|
||||
// TODO: add render material and color
|
||||
}
|
||||
|
||||
protected override void RegisterOutputParams(GH_OutputParamManager pManager)
|
||||
{
|
||||
pManager.AddGenericParameter("Speckle Object", "SO", "The created Speckle Object", GH_ParamAccess.item);
|
||||
}
|
||||
|
||||
protected override void SolveInstance(IGH_DataAccess da)
|
||||
{
|
||||
object gooGeometry = new();
|
||||
da.GetData(0, ref gooGeometry);
|
||||
GeometryBase geometry = ((IGH_GeometricGoo)gooGeometry).GeometricGooToGeometryBase();
|
||||
|
||||
string name = "";
|
||||
da.GetData(1, ref name);
|
||||
|
||||
SpecklePropertyGroupGoo properties = new();
|
||||
da.GetData(2, ref properties);
|
||||
|
||||
// convert the properties
|
||||
Dictionary<string, object?> props = new();
|
||||
properties.CastTo(ref props);
|
||||
|
||||
// convert the geometries
|
||||
Base converted = ToSpeckleConversionContext.ToSpeckleConverter.Convert(geometry);
|
||||
|
||||
Objects.Data.DataObject grasshopperObject =
|
||||
new()
|
||||
{
|
||||
name = name,
|
||||
displayValue = new() { converted },
|
||||
properties = props
|
||||
};
|
||||
|
||||
SpeckleObjectWrapper so =
|
||||
new()
|
||||
{
|
||||
Base = grasshopperObject,
|
||||
GeometryBase = geometry,
|
||||
Properties = properties,
|
||||
Name = name
|
||||
};
|
||||
|
||||
da.SetData(0, new SpeckleObjectWrapperGoo(so));
|
||||
}
|
||||
}
|
||||
+208
@@ -0,0 +1,208 @@
|
||||
using Grasshopper;
|
||||
using Grasshopper.Kernel;
|
||||
using Grasshopper.Kernel.Data;
|
||||
using Grasshopper.Kernel.Parameters;
|
||||
using Speckle.Connectors.Grasshopper8.Parameters;
|
||||
|
||||
namespace Speckle.Connectors.Grasshopper8.Components.Properties;
|
||||
|
||||
public class FilterPropertiesByPropertyGroupPaths : GH_Component, IGH_VariableParameterComponent
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the unique ID for this component. Do not change this ID after release.
|
||||
/// </summary>
|
||||
public override Guid ComponentGuid => new Guid("BF517D60-B853-4C61-9574-AD8A718B995B");
|
||||
|
||||
public FilterPropertiesByPropertyGroupPaths()
|
||||
: base(
|
||||
"FilterPropertiesByPropertyGroupPaths",
|
||||
"pgF",
|
||||
"Filters object properties by their property group path",
|
||||
"Speckle",
|
||||
"Properties"
|
||||
) { }
|
||||
|
||||
protected override void RegisterInputParams(GH_Component.GH_InputParamManager pManager)
|
||||
{
|
||||
pManager.AddParameter(
|
||||
new SpeckleObjectParam(),
|
||||
"Objects",
|
||||
"O",
|
||||
"Speckle Objects to filter properties from",
|
||||
GH_ParamAccess.list
|
||||
);
|
||||
pManager.AddTextParameter("Paths", "P", "Property Group paths to filter by", GH_ParamAccess.list);
|
||||
}
|
||||
|
||||
protected override void RegisterOutputParams(GH_Component.GH_OutputParamManager pManager)
|
||||
{
|
||||
// pManager.AddParameter( new SpecklePropertyParam(), "Properties", "P", "The properties of the selected Object", GH_ParamAccess.tree );
|
||||
}
|
||||
|
||||
protected override void SolveInstance(IGH_DataAccess da)
|
||||
{
|
||||
List<string> paths = new();
|
||||
da.GetDataList(1, paths);
|
||||
|
||||
if (paths.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
List<SpeckleObjectWrapperGoo> objectWrapperGoos = new();
|
||||
da.GetDataList(0, objectWrapperGoos);
|
||||
|
||||
if (objectWrapperGoos.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// we're creating an output param for every property path selected
|
||||
// we're creating a branch in the output tree for every object for that property
|
||||
|
||||
List<OutputParamWrapper> outputParams = new();
|
||||
foreach (string path in paths)
|
||||
{
|
||||
// create the output for this path
|
||||
DataTree<object?> paramResult = new();
|
||||
Param_GenericObject param =
|
||||
new()
|
||||
{
|
||||
Name = path,
|
||||
NickName = path,
|
||||
Access = GH_ParamAccess.tree
|
||||
};
|
||||
|
||||
// get the branch and property value for each input object
|
||||
for (int i = 0; i < objectWrapperGoos.Count; i++)
|
||||
{
|
||||
// create the result branch for this object
|
||||
SpeckleObjectWrapperGoo objectGoo = objectWrapperGoos[i];
|
||||
GH_Path objectPath = new GH_Path(i);
|
||||
|
||||
SpecklePropertyGroupGoo properties = objectGoo.Value.Properties;
|
||||
if (properties.Value.Count == 0)
|
||||
{
|
||||
paramResult.Add(null, objectPath);
|
||||
continue;
|
||||
}
|
||||
|
||||
SpecklePropertyGoo objectProperty = FindProperty(properties, path);
|
||||
paramResult.Add(string.IsNullOrEmpty((string)objectProperty.Value) ? null : objectProperty.Value, objectPath);
|
||||
}
|
||||
|
||||
outputParams.Add(new OutputParamWrapper(param, paramResult));
|
||||
}
|
||||
|
||||
if (da.Iteration == 0 && OutputMismatch(outputParams))
|
||||
{
|
||||
OnPingDocument()
|
||||
.ScheduleSolution(
|
||||
5,
|
||||
_ =>
|
||||
{
|
||||
CreateOutputs(outputParams);
|
||||
}
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < outputParams.Count; i++)
|
||||
{
|
||||
var outParam = Params.Output[i];
|
||||
var outParamWrapper = outputParams[i];
|
||||
switch (outParam.Access)
|
||||
{
|
||||
case GH_ParamAccess.item:
|
||||
da.SetData(i, outParamWrapper.Values);
|
||||
break;
|
||||
case GH_ParamAccess.tree:
|
||||
da.SetDataTree(i, (DataTree<object?>)outParamWrapper.Values);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private SpecklePropertyGoo FindProperty(SpecklePropertyGroupGoo root, string unifiedPath)
|
||||
{
|
||||
if (!root.Value.TryGetValue(unifiedPath, out SpecklePropertyGoo currentGoo))
|
||||
{
|
||||
return new() { Path = unifiedPath, Value = "" };
|
||||
}
|
||||
|
||||
return currentGoo;
|
||||
}
|
||||
|
||||
private bool OutputMismatch(List<OutputParamWrapper> outputParams)
|
||||
{
|
||||
if (Params.Output.Count != outputParams.Count)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
var count = 0;
|
||||
foreach (var newParam in outputParams)
|
||||
{
|
||||
var oldParam = Params.Output[count];
|
||||
if (
|
||||
oldParam.NickName != newParam.Param.NickName
|
||||
|| oldParam.Name != newParam.Param.Name
|
||||
|| oldParam.Access != newParam.Param.Access
|
||||
)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
count++;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void CreateOutputs(List<OutputParamWrapper> outputParams)
|
||||
{
|
||||
// TODO: better, nicer handling of creation/removal
|
||||
while (Params.Output.Count > 0)
|
||||
{
|
||||
Params.UnregisterOutputParameter(Params.Output[^1]);
|
||||
}
|
||||
|
||||
foreach (var newParam in outputParams)
|
||||
{
|
||||
var param = new Param_GenericObject
|
||||
{
|
||||
Name = newParam.Param.Name,
|
||||
NickName = newParam.Param.NickName,
|
||||
MutableNickName = false,
|
||||
Access = newParam.Param.Access
|
||||
};
|
||||
Params.RegisterOutputParam(param);
|
||||
}
|
||||
|
||||
Params.OnParametersChanged();
|
||||
VariableParameterMaintenance();
|
||||
ExpireSolution(false);
|
||||
}
|
||||
|
||||
public bool CanInsertParameter(GH_ParameterSide side, int index) => false;
|
||||
|
||||
public bool CanRemoveParameter(GH_ParameterSide side, int index) => false;
|
||||
|
||||
public IGH_Param CreateParameter(GH_ParameterSide side, int index)
|
||||
{
|
||||
var myParam = new Param_GenericObject
|
||||
{
|
||||
Name = GH_ComponentParamServer.InventUniqueNickname("ABCD", Params.Input),
|
||||
MutableNickName = true,
|
||||
Optional = true
|
||||
};
|
||||
myParam.NickName = myParam.Name;
|
||||
return myParam;
|
||||
}
|
||||
|
||||
public bool DestroyParameter(GH_ParameterSide side, int index) => side == GH_ParameterSide.Output;
|
||||
|
||||
public void VariableParameterMaintenance() { }
|
||||
}
|
||||
|
||||
public record OutputParamWrapper(Param_GenericObject Param, object Values);
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
using Grasshopper.Kernel.Types;
|
||||
using Grasshopper.Rhinoceros.Model;
|
||||
using Speckle.Connectors.Common.Extensions;
|
||||
using Speckle.Connectors.Grasshopper8.Components.BaseComponents;
|
||||
using Speckle.Connectors.Grasshopper8.Parameters;
|
||||
|
||||
namespace Speckle.Connectors.Grasshopper8.Components.Properties;
|
||||
|
||||
public class PropertyGroupPathsSelector : ValueSet<IGH_Goo>
|
||||
{
|
||||
public PropertyGroupPathsSelector()
|
||||
: base(
|
||||
"Property Group Paths Selector",
|
||||
"Paths",
|
||||
"Allows you to select a set of property group paths for filtering",
|
||||
"Speckle",
|
||||
"Properties"
|
||||
) { }
|
||||
|
||||
public override Guid ComponentGuid => new Guid("8882BE3A-81F1-4416-B420-58D69E4CC8F1");
|
||||
|
||||
protected override void LoadVolatileData()
|
||||
{
|
||||
var objectPropertyGroups = VolatileData
|
||||
.AllData(true)
|
||||
.OfType<SpeckleObjectWrapperGoo>()
|
||||
.Select(goo => goo.Value.Properties.Value)
|
||||
.ToList();
|
||||
|
||||
// support model objects direct piping also
|
||||
if (objectPropertyGroups.Count != VolatileData.DataCount)
|
||||
{
|
||||
var modelObjects = VolatileData
|
||||
.AllData(true)
|
||||
.OfType<ModelObject>()
|
||||
.Select(mo => new SpeckleObjectWrapperGoo(mo).Value.Properties.Value)
|
||||
.ToList();
|
||||
objectPropertyGroups.AddRange(modelObjects);
|
||||
}
|
||||
|
||||
if (objectPropertyGroups.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var paths = GetPropertyPaths(objectPropertyGroups);
|
||||
m_data.AppendRange(paths.Select(s => new GH_String(s)));
|
||||
}
|
||||
|
||||
private static List<string> GetPropertyPaths(List<Dictionary<string, SpecklePropertyGoo>> objectPropertyGroups)
|
||||
{
|
||||
var result = new HashSet<string>();
|
||||
foreach (var dict in objectPropertyGroups)
|
||||
{
|
||||
result.AddRange(
|
||||
dict.Keys.Where(k => !(k.EndsWith(".name") || k.EndsWith(".units") || k.EndsWith(".internalDefinitionName")))
|
||||
);
|
||||
}
|
||||
return result.ToList();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
using System.Drawing.Drawing2D;
|
||||
|
||||
namespace Speckle.Connectors.Grasshopper8.HostApp;
|
||||
|
||||
public static class BitmapBuilder
|
||||
{
|
||||
public static Bitmap CreateSquareIconBitmap(string text, int width = 24, int height = 24)
|
||||
{
|
||||
Bitmap bitmap = new(width, height);
|
||||
using Graphics graphics = Graphics.FromImage(bitmap);
|
||||
|
||||
// Enable high-quality rendering
|
||||
graphics.SmoothingMode = SmoothingMode.AntiAlias;
|
||||
|
||||
// Set background to transparent
|
||||
graphics.Clear(Color.Transparent);
|
||||
|
||||
// Rectangle with a 1px offset
|
||||
Rectangle squareRect = new(1, 1, width - 2, height - 2);
|
||||
|
||||
using (Brush blueBrush = new SolidBrush(Color.Blue))
|
||||
{
|
||||
graphics.FillRectangle(blueBrush, squareRect);
|
||||
}
|
||||
|
||||
// Draw white letters in the center
|
||||
using (Font font = new("Arial", 8, FontStyle.Bold, GraphicsUnit.Pixel))
|
||||
using (Brush whiteBrush = new SolidBrush(Color.White))
|
||||
{
|
||||
StringFormat format = new() { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center };
|
||||
|
||||
graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
|
||||
graphics.DrawString(text, font, whiteBrush, new RectangleF(1, 1, width - 2, height - 2), format);
|
||||
}
|
||||
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
public static Bitmap CreateCircleIconBitmap(string text, int width = 24, int height = 24)
|
||||
{
|
||||
Bitmap bitmap = new(width, height);
|
||||
using Graphics graphics = Graphics.FromImage(bitmap);
|
||||
|
||||
// Enable high-quality rendering
|
||||
graphics.SmoothingMode = SmoothingMode.AntiAlias;
|
||||
|
||||
// Set background to transparent
|
||||
graphics.Clear(Color.Transparent);
|
||||
|
||||
// Rectangle with a 1px offset
|
||||
Rectangle squareRect = new(1, 1, width - 2, height - 2);
|
||||
|
||||
using (Brush blueBrush = new SolidBrush(Color.Blue))
|
||||
{
|
||||
graphics.FillEllipse(blueBrush, squareRect);
|
||||
}
|
||||
|
||||
// Draw white letters in the center
|
||||
using (Font font = new("Arial", 8, FontStyle.Bold, GraphicsUnit.Pixel))
|
||||
using (Brush whiteBrush = new SolidBrush(Color.White))
|
||||
{
|
||||
StringFormat format = new() { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center };
|
||||
|
||||
graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
|
||||
graphics.DrawString(text, font, whiteBrush, new RectangleF(1, 1, width - 2, height - 2), format);
|
||||
}
|
||||
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
public static Bitmap CreateHexagonalBitmap(string text, int width = 24, int height = 24)
|
||||
{
|
||||
Bitmap bitmap = new(width, height);
|
||||
using Graphics graphics = Graphics.FromImage(bitmap);
|
||||
|
||||
// Enable high-quality rendering
|
||||
graphics.SmoothingMode = SmoothingMode.AntiAlias;
|
||||
|
||||
// Set background to transparent
|
||||
graphics.Clear(Color.Transparent);
|
||||
|
||||
// Calculate hexagon points centered within the bitmap
|
||||
float side = (width - 2) / 2.236f; // 2.236f approximates 4 / √3 for regular hex dimensions
|
||||
float h = side * (float)Math.Sqrt(3) / 2;
|
||||
float centerX = width / 2f;
|
||||
float centerY = height / 2f;
|
||||
|
||||
Point[] hexagonPoints =
|
||||
[
|
||||
new((int)(centerX - side / 2), (int)(centerY - h)),
|
||||
new((int)(centerX + side / 2), (int)(centerY - h)),
|
||||
new((int)(centerX + side), (int)centerY),
|
||||
new((int)(centerX + side / 2), (int)(centerY + h)),
|
||||
new((int)(centerX - side / 2), (int)(centerY + h)),
|
||||
new((int)(centerX - side), (int)centerY)
|
||||
];
|
||||
|
||||
using (Brush blueBrush = new SolidBrush(Color.Blue))
|
||||
{
|
||||
graphics.FillPolygon(blueBrush, hexagonPoints);
|
||||
}
|
||||
|
||||
// Draw white letters in the center
|
||||
using Font font = new("Monospace", 10, FontStyle.Bold, GraphicsUnit.Pixel);
|
||||
using Brush whiteBrush = new SolidBrush(Color.White);
|
||||
StringFormat format = new() { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center };
|
||||
|
||||
graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
|
||||
graphics.DrawString(text, font, whiteBrush, new RectangleF(0, 1, width, height), format);
|
||||
|
||||
return bitmap;
|
||||
}
|
||||
}
|
||||
+136
@@ -0,0 +1,136 @@
|
||||
using System.Windows.Threading;
|
||||
|
||||
namespace Speckle.Connectors.Grasshopper8.HostApp.Extras;
|
||||
|
||||
/// <summary>
|
||||
/// Provides Debounce() and Throttle() methods.
|
||||
/// Use these methods to ensure that events aren't handled too frequently.
|
||||
///
|
||||
/// Throttle() ensures that events are throttled by the interval specified.
|
||||
/// Only the last event in the interval sequence of events fires.
|
||||
///
|
||||
/// Debounce() fires an event only after the specified interval has passed
|
||||
/// in which no other pending event has fired. Only the last event in the
|
||||
/// sequence is fired.
|
||||
/// </summary>
|
||||
public class DebounceDispatcher
|
||||
{
|
||||
private DispatcherTimer? _timer;
|
||||
private DateTime TimerStarted { get; set; } = DateTime.UtcNow.AddYears(-1);
|
||||
|
||||
/// <summary>
|
||||
/// Debounce an event by resetting the event timeout every time the event is
|
||||
/// fired. The behavior is that the Action passed is fired only after events
|
||||
/// stop firing for the given timeout period.
|
||||
///
|
||||
/// Use Debounce when you want events to fire only after events stop firing
|
||||
/// after the given interval timeout period.
|
||||
///
|
||||
/// Wrap the logic you would normally use in your event code into
|
||||
/// the Action you pass to this method to debounce the event.
|
||||
/// Example: https://gist.github.com/RickStrahl/0519b678f3294e27891f4d4f0608519a
|
||||
/// </summary>
|
||||
/// <param name="interval">Timeout in Milliseconds</param>
|
||||
/// <param name="action">Action<object> to fire when debounced event fires</object></param>
|
||||
/// <param name="param">optional parameter</param>
|
||||
/// <param name="priority">optional priorty for the dispatcher</param>
|
||||
/// <param name="disp">optional dispatcher. If not passed or null CurrentDispatcher is used.</param>
|
||||
public void Debounce(
|
||||
int interval,
|
||||
Action<object?> action,
|
||||
object? param = null,
|
||||
DispatcherPriority priority = DispatcherPriority.ApplicationIdle,
|
||||
Dispatcher? disp = null
|
||||
)
|
||||
{
|
||||
// kill pending timer and pending ticks
|
||||
_timer?.Stop();
|
||||
_timer = null;
|
||||
|
||||
if (disp == null)
|
||||
{
|
||||
disp = Dispatcher.CurrentDispatcher;
|
||||
}
|
||||
|
||||
// timer is recreated for each event and effectively
|
||||
// resets the timeout. Action only fires after timeout has fully
|
||||
// elapsed without other events firing in between
|
||||
_timer = new DispatcherTimer(
|
||||
TimeSpan.FromMilliseconds(interval),
|
||||
priority,
|
||||
(s, e) =>
|
||||
{
|
||||
if (_timer == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_timer?.Stop();
|
||||
_timer = null;
|
||||
action.Invoke(param);
|
||||
},
|
||||
disp
|
||||
);
|
||||
|
||||
_timer.Start();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method throttles events by allowing only 1 event to fire for the given
|
||||
/// timeout period. Only the last event fired is handled - all others are ignored.
|
||||
/// Throttle will fire events every timeout ms even if additional events are pending.
|
||||
///
|
||||
/// Use Throttle where you need to ensure that events fire at given intervals.
|
||||
/// </summary>
|
||||
/// <param name="interval">Timeout in Milliseconds</param>
|
||||
/// <param name="action">Action<object> to fire when debounced event fires</object></param>
|
||||
/// <param name="param">optional parameter</param>
|
||||
/// <param name="priority">optional priorty for the dispatcher</param>
|
||||
/// <param name="disp">optional dispatcher. If not passed or null CurrentDispatcher is used.</param>
|
||||
public void Throttle(
|
||||
int interval,
|
||||
Action<object?> action,
|
||||
object? param = null,
|
||||
DispatcherPriority priority = DispatcherPriority.ApplicationIdle,
|
||||
Dispatcher? disp = null
|
||||
)
|
||||
{
|
||||
// kill pending timer and pending ticks
|
||||
_timer?.Stop();
|
||||
_timer = null;
|
||||
|
||||
if (disp == null)
|
||||
{
|
||||
disp = Dispatcher.CurrentDispatcher;
|
||||
}
|
||||
|
||||
var curTime = DateTime.UtcNow;
|
||||
|
||||
// if timeout is not up yet - adjust timeout to fire
|
||||
// with potentially new Action parameters
|
||||
if (curTime.Subtract(TimerStarted).TotalMilliseconds < interval)
|
||||
{
|
||||
interval -= (int)curTime.Subtract(TimerStarted).TotalMilliseconds;
|
||||
}
|
||||
|
||||
_timer = new DispatcherTimer(
|
||||
TimeSpan.FromMilliseconds(interval),
|
||||
priority,
|
||||
(s, e) =>
|
||||
{
|
||||
if (_timer == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_timer?.Stop();
|
||||
_timer = null;
|
||||
action.Invoke(param);
|
||||
},
|
||||
disp
|
||||
);
|
||||
|
||||
_timer.Start();
|
||||
TimerStarted = curTime;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace Speckle.Connectors.Grasshopper8.HostApp;
|
||||
|
||||
public static class Constants
|
||||
{
|
||||
public const string LAYER_PATH_DELIMITER = "::";
|
||||
public const string PROPERTY_PATH_DELIMITER = ".";
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
using Grasshopper;
|
||||
using Grasshopper.Kernel;
|
||||
using Grasshopper.Kernel.Data;
|
||||
using Grasshopper.Kernel.Types;
|
||||
using Rhino;
|
||||
using Rhino.Geometry;
|
||||
using Speckle.DoubleNumerics;
|
||||
using Speckle.Sdk;
|
||||
using Speckle.Sdk.Common;
|
||||
using Speckle.Sdk.Common.Exceptions;
|
||||
|
||||
namespace Speckle.Connectors.Grasshopper8.HostApp;
|
||||
|
||||
public static class GrasshopperHelpers
|
||||
{
|
||||
public static string ToSpeckleString(this UnitSystem unitSystem)
|
||||
{
|
||||
switch (unitSystem)
|
||||
{
|
||||
case UnitSystem.None:
|
||||
return Units.Meters;
|
||||
case UnitSystem.Millimeters:
|
||||
return Units.Millimeters;
|
||||
case UnitSystem.Centimeters:
|
||||
return Units.Centimeters;
|
||||
case UnitSystem.Meters:
|
||||
return Units.Meters;
|
||||
case UnitSystem.Kilometers:
|
||||
return Units.Kilometers;
|
||||
case UnitSystem.Inches:
|
||||
return Units.Inches;
|
||||
case UnitSystem.Feet:
|
||||
return Units.Feet;
|
||||
case UnitSystem.Yards:
|
||||
return Units.Yards;
|
||||
case UnitSystem.Miles:
|
||||
return Units.Miles;
|
||||
case UnitSystem.Unset:
|
||||
return Units.Meters;
|
||||
default:
|
||||
throw new UnitNotSupportedException($"The Unit System \"{unitSystem}\" is unsupported.");
|
||||
}
|
||||
}
|
||||
|
||||
public static Transform MatrixToTransform(Matrix4x4 matrix, string units)
|
||||
{
|
||||
var currentDoc = RhinoDoc.ActiveDoc; // POC: too much right now to interface around
|
||||
var conversionFactor = Units.GetConversionFactor(units, currentDoc.ModelUnitSystem.ToSpeckleString());
|
||||
|
||||
var t = Transform.Identity;
|
||||
t.M00 = matrix.M11;
|
||||
t.M01 = matrix.M12;
|
||||
t.M02 = matrix.M13;
|
||||
t.M03 = matrix.M14 * conversionFactor;
|
||||
|
||||
t.M10 = matrix.M21;
|
||||
t.M11 = matrix.M22;
|
||||
t.M12 = matrix.M23;
|
||||
t.M13 = matrix.M24 * conversionFactor;
|
||||
|
||||
t.M20 = matrix.M31;
|
||||
t.M21 = matrix.M32;
|
||||
t.M22 = matrix.M33;
|
||||
t.M23 = matrix.M34 * conversionFactor;
|
||||
|
||||
t.M30 = matrix.M41;
|
||||
t.M31 = matrix.M42;
|
||||
t.M32 = matrix.M43;
|
||||
t.M33 = matrix.M44;
|
||||
return t;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to cast the goo to a geometry base object.
|
||||
/// </summary>
|
||||
/// <param name="geoGeo"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="SpeckleException">If it fails to cast</exception>
|
||||
public static GeometryBase GeometricGooToGeometryBase(this IGH_GeometricGoo geoGeo)
|
||||
{
|
||||
var value = geoGeo.GetType().GetProperty("Value")?.GetValue(geoGeo);
|
||||
switch (value)
|
||||
{
|
||||
case GeometryBase gb:
|
||||
return gb;
|
||||
case Point3d pt:
|
||||
return new Rhino.Geometry.Point(pt);
|
||||
case Line ln:
|
||||
return new LineCurve(ln);
|
||||
case Rectangle3d rec:
|
||||
return rec.ToNurbsCurve();
|
||||
case Circle c:
|
||||
return new ArcCurve(c);
|
||||
case Arc ac:
|
||||
return new ArcCurve(ac);
|
||||
case Ellipse el:
|
||||
return el.ToNurbsCurve();
|
||||
case Sphere sp:
|
||||
return sp.ToBrep();
|
||||
}
|
||||
|
||||
throw new SpeckleException("Failed to cast IGH_GeometricGoo to geometry base");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a tree based of a string that encodes the grasshopper topology.
|
||||
/// </summary>
|
||||
/// <param name="topology"></param>
|
||||
/// <param name="subset"></param>
|
||||
/// <returns></returns>
|
||||
public static DataTree<object> CreateDataTreeFromTopologyAndItems(string topology, System.Collections.IList subset)
|
||||
{
|
||||
var tree = new DataTree<object>();
|
||||
var treeTopo = topology.Split(' ');
|
||||
int subsetCount = 0;
|
||||
foreach (var branch in treeTopo)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(branch))
|
||||
{
|
||||
var branchTopo = branch.Split('-')[0].Split(';');
|
||||
var branchIndexes = new List<int>();
|
||||
foreach (var t in branchTopo)
|
||||
{
|
||||
branchIndexes.Add(Convert.ToInt32(t));
|
||||
}
|
||||
|
||||
var elCount = Convert.ToInt32(branch.Split('-')[1]);
|
||||
var myPath = new GH_Path(branchIndexes.ToArray());
|
||||
|
||||
for (int i = 0; i < elCount; i++)
|
||||
{
|
||||
tree.EnsurePath(myPath).Add(new Grasshopper.Kernel.Types.GH_ObjectWrapper(subset[subsetCount + i]));
|
||||
}
|
||||
|
||||
subsetCount += elCount;
|
||||
}
|
||||
}
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Encodes a tree topology into an exhaustive string which can be used to recreate it using
|
||||
/// <see cref="CreateDataTreeFromTopologyAndItems"/>.
|
||||
/// </summary>
|
||||
/// <param name="param"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetParamTopology(IGH_Param param)
|
||||
{
|
||||
string topology = "";
|
||||
foreach (GH_Path myPath in param.VolatileData.Paths)
|
||||
{
|
||||
topology += myPath.ToString(false) + "-" + param.VolatileData.get_Branch(myPath).Count + " ";
|
||||
}
|
||||
return topology;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
using Speckle.Connectors.Common.Operations;
|
||||
using Speckle.Sdk.Api;
|
||||
using Speckle.Sdk.Api.GraphQL.Models;
|
||||
using Speckle.Sdk.Common;
|
||||
using Version = Speckle.Sdk.Api.GraphQL.Models.Version;
|
||||
|
||||
namespace Speckle.Connectors.Grasshopper8.HostApp;
|
||||
|
||||
public abstract record SpeckleUrlModelResource(string Server, string ProjectId)
|
||||
{
|
||||
public abstract Task<ReceiveInfo> GetReceiveInfo(Client client, CancellationToken cancellationToken = default);
|
||||
|
||||
public abstract Task<SendInfo> GetSendInfo(Client client, CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
public record SpeckleUrlLatestModelVersionResource(string Server, string ProjectId, string ModelId)
|
||||
: SpeckleUrlModelResource(Server, ProjectId)
|
||||
{
|
||||
public override async Task<ReceiveInfo> GetReceiveInfo(Client client, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Project project = await client.Project.Get(ProjectId, cancellationToken).ConfigureAwait(false);
|
||||
ModelWithVersions model = await client
|
||||
.Model.GetWithVersions(ModelId, ProjectId, 1, null, null, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
Version version = model.versions.items[0];
|
||||
|
||||
var info = new ReceiveInfo(
|
||||
client.Account.id,
|
||||
new Uri(Server),
|
||||
ProjectId,
|
||||
project.name,
|
||||
ModelId,
|
||||
model.name,
|
||||
version.id,
|
||||
version.sourceApplication.NotNull()
|
||||
);
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
public override async Task<SendInfo> GetSendInfo(Client client, CancellationToken cancellationToken = default)
|
||||
{
|
||||
// We don't care about the return info, we just want to be sure we have access and everything exists.
|
||||
await client.Project.Get(ProjectId, cancellationToken).ConfigureAwait(false);
|
||||
await client.Model.Get(ModelId, ProjectId, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
return new SendInfo(
|
||||
client.Account.id,
|
||||
new Uri(Server),
|
||||
ProjectId,
|
||||
ModelId,
|
||||
"Grasshopper8" // TODO: Grab from the right place!
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public record SpeckleUrlModelVersionResource(string Server, string ProjectId, string ModelId, string VersionId)
|
||||
: SpeckleUrlModelResource(Server, ProjectId)
|
||||
{
|
||||
public override async Task<ReceiveInfo> GetReceiveInfo(Client client, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Project project = await client.Project.Get(ProjectId, cancellationToken).ConfigureAwait(false);
|
||||
Model model = await client.Model.Get(ModelId, ProjectId, cancellationToken).ConfigureAwait(false);
|
||||
Version version = await client.Version.Get(VersionId, ProjectId, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var info = new ReceiveInfo(
|
||||
client.Account.id,
|
||||
new Uri(Server),
|
||||
ProjectId,
|
||||
project.name,
|
||||
ModelId,
|
||||
model.name,
|
||||
VersionId,
|
||||
version.sourceApplication.NotNull()
|
||||
);
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
public override async Task<SendInfo> GetSendInfo(Client client, CancellationToken cancellationToken = default)
|
||||
{
|
||||
// We don't care about the return info, we just want to be sure we have access and everything exists.
|
||||
await client.Project.Get(ProjectId, cancellationToken).ConfigureAwait(false);
|
||||
await client.Model.Get(ModelId, ProjectId, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
return new SendInfo(
|
||||
client.Account.id,
|
||||
new Uri(Server),
|
||||
ProjectId,
|
||||
ModelId,
|
||||
"Grasshopper8" // TODO: Grab from the right place!
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public record SpeckleUrlModelObjectResource(string Server, string ProjectId, string ObjectId)
|
||||
: SpeckleUrlModelResource(Server, ProjectId)
|
||||
{
|
||||
public override Task<ReceiveInfo> GetReceiveInfo(Client client, CancellationToken cancellationToken = default) =>
|
||||
throw new NotImplementedException("Object Resources are not supported yet");
|
||||
|
||||
public override Task<SendInfo> GetSendInfo(Client client, CancellationToken cancellationToken = default) =>
|
||||
throw new NotImplementedException("Object Resources are not supported yet");
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
using System.Text.RegularExpressions;
|
||||
using Speckle.Sdk;
|
||||
|
||||
namespace Speckle.Connectors.Grasshopper8.HostApp;
|
||||
|
||||
public record SpeckleResourceBuilder
|
||||
{
|
||||
/// <summary>
|
||||
/// The ReGex pattern to determine if a URL's AbsolutePath is a Frontend2 URL or not.
|
||||
/// </summary>
|
||||
private static readonly Regex s_fe2UrlRegex =
|
||||
new(
|
||||
@"/projects/(?<projectId>[\w\d]+)(?:/models/(?<model>[\w\d]+(?:@[\w\d]+)?)(?:,(?<additionalModels>[\w\d]+(?:@[\w\d]+)?))*)?"
|
||||
);
|
||||
|
||||
public static SpeckleUrlModelResource[] FromUrlString(string speckleModel)
|
||||
{
|
||||
var uri = new Uri(speckleModel);
|
||||
var serverUrl = uri.GetLeftPart(UriPartial.Authority);
|
||||
var match = s_fe2UrlRegex.Match(speckleModel);
|
||||
var result = ParseFe2RegexMatch(serverUrl, match);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static SpeckleUrlModelResource[] ParseFe2RegexMatch(string serverUrl, Match match)
|
||||
{
|
||||
var projectId = match.Groups["projectId"];
|
||||
var model = match.Groups["model"];
|
||||
var additionalModels = match.Groups["additionalModels"];
|
||||
|
||||
if (!projectId.Success)
|
||||
{
|
||||
throw new SpeckleException("The provided url is not a valid Speckle url");
|
||||
}
|
||||
|
||||
if (!model.Success)
|
||||
{
|
||||
throw new SpeckleException("The provided url is not pointing to any model in the project.");
|
||||
}
|
||||
|
||||
if (model.Value == "all")
|
||||
{
|
||||
throw new NotSupportedException("Fetching all models is not supported.");
|
||||
}
|
||||
|
||||
if (model.Value.StartsWith("$"))
|
||||
{
|
||||
throw new NotSupportedException("Federation model urls are not supported");
|
||||
}
|
||||
|
||||
var modelRes = GetUrlModelResource(serverUrl, projectId.Value, model.Value);
|
||||
|
||||
var result = new List<SpeckleUrlModelResource> { modelRes };
|
||||
|
||||
if (additionalModels.Success)
|
||||
{
|
||||
foreach (Capture additionalModelsCapture in additionalModels.Captures)
|
||||
{
|
||||
var extraModel = GetUrlModelResource(serverUrl, projectId.Value, additionalModelsCapture.Value);
|
||||
result.Add(extraModel);
|
||||
}
|
||||
}
|
||||
|
||||
return result.ToArray();
|
||||
}
|
||||
|
||||
private static SpeckleUrlModelResource GetUrlModelResource(string serverUrl, string projectId, string modelValue)
|
||||
{
|
||||
if (modelValue.Length == 32)
|
||||
{
|
||||
return new SpeckleUrlModelObjectResource(serverUrl, projectId, modelValue); // Model value is an ObjectID
|
||||
}
|
||||
|
||||
if (!modelValue.Contains('@'))
|
||||
{
|
||||
return new SpeckleUrlLatestModelVersionResource(serverUrl, projectId, modelValue); // Model has no version attached
|
||||
}
|
||||
|
||||
var res = modelValue.Split('@');
|
||||
return new SpeckleUrlModelVersionResource(serverUrl, projectId, res[0], res[1]);
|
||||
}
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Rhino;
|
||||
using Speckle.Connectors.Grasshopper8.Registration;
|
||||
using Speckle.Converters.Common;
|
||||
using Speckle.Converters.Rhino;
|
||||
|
||||
namespace Speckle.Connectors.Grasshopper8.HostApp;
|
||||
|
||||
/// <summary>
|
||||
/// Handles grasshopper wide converters. We don't need new converters, unless the document changes - this class should handle this (untested).
|
||||
/// </summary>
|
||||
public static class ToSpeckleConversionContext
|
||||
{
|
||||
private static IServiceScope? Scope { get; set; }
|
||||
public static IRootToHostConverter ToHostConverter { get; private set; }
|
||||
public static IRootToSpeckleConverter ToSpeckleConverter { get; private set; }
|
||||
|
||||
static ToSpeckleConversionContext()
|
||||
{
|
||||
RhinoDoc.ActiveDocumentChanged += RhinoDocOnActiveDocumentChanged;
|
||||
InitializeConverters();
|
||||
}
|
||||
|
||||
private static void RhinoDocOnActiveDocumentChanged(object sender, DocumentEventArgs e) => InitializeConverters(); // note: untested, and wrong on mac
|
||||
|
||||
private static void InitializeConverters()
|
||||
{
|
||||
Scope?.Dispose();
|
||||
Scope = PriorityLoader.Container.CreateScope();
|
||||
|
||||
var rhinoConversionSettingsFactory = Scope.ServiceProvider.GetRequiredService<IRhinoConversionSettingsFactory>();
|
||||
Scope
|
||||
.ServiceProvider.GetRequiredService<IConverterSettingsStore<RhinoConversionSettings>>()
|
||||
.Initialize(rhinoConversionSettingsFactory.Create(RhinoDoc.ActiveDoc));
|
||||
|
||||
ToHostConverter = Scope.ServiceProvider.GetService<IRootToHostConverter>();
|
||||
ToSpeckleConverter = Scope.ServiceProvider.GetService<IRootToSpeckleConverter>();
|
||||
}
|
||||
}
|
||||
+189
@@ -0,0 +1,189 @@
|
||||
using Rhino.Geometry;
|
||||
using Speckle.Connectors.Common.Builders;
|
||||
using Speckle.Connectors.Common.Conversion;
|
||||
using Speckle.Connectors.Common.Extensions;
|
||||
using Speckle.Connectors.Common.Operations;
|
||||
using Speckle.Connectors.Common.Operations.Receive;
|
||||
using Speckle.Converters.Common;
|
||||
using Speckle.Converters.Rhino;
|
||||
using Speckle.Sdk;
|
||||
using Speckle.Sdk.Logging;
|
||||
using Speckle.Sdk.Models;
|
||||
using Speckle.Sdk.Models.Collections;
|
||||
using Speckle.Sdk.Models.Instances;
|
||||
|
||||
namespace Speckle.Connectors.Grasshopper8.Operations.Receive;
|
||||
|
||||
public sealed class GrasshopperReceiveConversionResult : ReceiveConversionResult
|
||||
{
|
||||
public object? Result { get; set; }
|
||||
public Base Source { get; set; }
|
||||
|
||||
public GrasshopperReceiveConversionResult(
|
||||
Status status,
|
||||
Base source,
|
||||
object? result,
|
||||
string? resultId = null,
|
||||
string? resultType = null,
|
||||
Exception? exception = null
|
||||
)
|
||||
: base(status, source, resultId, resultType, exception)
|
||||
{
|
||||
Result = result;
|
||||
Source = source;
|
||||
}
|
||||
}
|
||||
|
||||
public class GrasshopperHostObjectBuilder : IHostObjectBuilder
|
||||
{
|
||||
private readonly IRootToHostConverter _converter;
|
||||
private readonly IConverterSettingsStore<RhinoConversionSettings> _converterSettings;
|
||||
private readonly TraversalContextUnpacker _contextUnpacker;
|
||||
private readonly RootObjectUnpacker _rootObjectUnpacker;
|
||||
private readonly ISdkActivityFactory _activityFactory;
|
||||
|
||||
public GrasshopperHostObjectBuilder(
|
||||
IRootToHostConverter converter,
|
||||
IConverterSettingsStore<RhinoConversionSettings> converterSettings,
|
||||
RootObjectUnpacker rootObjectUnpacker,
|
||||
ISdkActivityFactory activityFactory,
|
||||
TraversalContextUnpacker contextUnpacker
|
||||
)
|
||||
{
|
||||
_converter = converter;
|
||||
_converterSettings = converterSettings;
|
||||
_rootObjectUnpacker = rootObjectUnpacker;
|
||||
_activityFactory = activityFactory;
|
||||
_contextUnpacker = contextUnpacker;
|
||||
}
|
||||
|
||||
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
|
||||
public async Task<HostObjectBuilderResult> Build(
|
||||
#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously
|
||||
Base rootObject,
|
||||
string projectName,
|
||||
string modelName,
|
||||
IProgress<CardProgress> onOperationProgressed,
|
||||
CancellationToken cancellationToken
|
||||
)
|
||||
{
|
||||
using var activity = _activityFactory.Start("Build");
|
||||
// POC: This is where the top level base-layer name is set. Could be abstracted or injected in the context?
|
||||
var baseLayerName = $"Project {projectName}: Model {modelName}";
|
||||
|
||||
// 1 - Unpack objects and proxies from root commit object
|
||||
|
||||
var unpackedRoot = _rootObjectUnpacker.Unpack(rootObject);
|
||||
|
||||
// 2 - Split atomic objects and instance components with their path
|
||||
var (atomicObjects, instanceComponents) = _rootObjectUnpacker.SplitAtomicObjectsAndInstances(
|
||||
unpackedRoot.ObjectsToConvert
|
||||
);
|
||||
|
||||
var atomicObjectsWithPath = _contextUnpacker.GetAtomicObjectsWithPath(atomicObjects);
|
||||
var instanceComponentsWithPath = _contextUnpacker.GetInstanceComponentsWithPath(instanceComponents);
|
||||
|
||||
// 2.1 - these are not captured by traversal, so we need to re-add them here
|
||||
if (unpackedRoot.DefinitionProxies != null && unpackedRoot.DefinitionProxies.Count > 0)
|
||||
{
|
||||
var transformed = unpackedRoot.DefinitionProxies.Select(proxy =>
|
||||
(Array.Empty<Collection>(), proxy as IInstanceComponent)
|
||||
);
|
||||
instanceComponentsWithPath.AddRange(transformed);
|
||||
}
|
||||
|
||||
// 3 - Bake materials and colors, as they are used later down the line by layers and objects
|
||||
onOperationProgressed.Report(new("Converting materials and colors", null));
|
||||
if (unpackedRoot.RenderMaterialProxies != null)
|
||||
{
|
||||
using var _ = _activityFactory.Start("Render Materials");
|
||||
//_materialBaker.BakeMaterials(unpackedRoot.RenderMaterialProxies, baseLayerName);
|
||||
}
|
||||
|
||||
if (unpackedRoot.ColorProxies != null)
|
||||
{
|
||||
//_colorBaker.ParseColors(unpackedRoot.ColorProxies);
|
||||
}
|
||||
|
||||
// 5 - Convert atomic objects
|
||||
List<ReceiveConversionResult> conversionResults = new();
|
||||
Dictionary<string, List<string>> applicationIdMap = new(); // This map is used in converting blocks in stage 2. keeps track of original app id => resulting new app ids post baking
|
||||
|
||||
int count = 0;
|
||||
using (var _ = _activityFactory.Start("Converting objects"))
|
||||
{
|
||||
foreach (var (path, obj) in atomicObjectsWithPath)
|
||||
{
|
||||
using (var convertActivity = _activityFactory.Start("Converting object"))
|
||||
{
|
||||
onOperationProgressed.Report(new("Converting objects", (double)++count / atomicObjects.Count));
|
||||
try
|
||||
{
|
||||
// 0: get pre-created layer from cache in layer baker
|
||||
// int layerIndex = _layerBaker.GetLayerIndex(path, baseLayerName);
|
||||
|
||||
// 1: create object attributes for baking
|
||||
string name = obj["name"] as string ?? "";
|
||||
|
||||
// 2: convert
|
||||
var result = _converter.Convert(obj);
|
||||
|
||||
// 3: bake
|
||||
if (result is GeometryBase geometryBase)
|
||||
{
|
||||
//var guid = BakeObject(geometryBase, obj, atts);
|
||||
}
|
||||
else if (result is List<GeometryBase> geometryBases) // one to many raw encoding case
|
||||
{
|
||||
foreach (var gb in geometryBases)
|
||||
{
|
||||
//var guid = BakeObject(gb, obj, atts);
|
||||
}
|
||||
}
|
||||
else if (result is IEnumerable<(object, Base)> fallbackConversionResult) // one to many fallback conversion
|
||||
{
|
||||
//var guids = BakeObjectsAsFallbackGroup(fallbackConversionResult, obj, atts, baseLayerName);
|
||||
}
|
||||
|
||||
// 4: log
|
||||
conversionResults.Add(
|
||||
new GrasshopperReceiveConversionResult(Status.SUCCESS, obj, result, null, result.GetType().ToString())
|
||||
);
|
||||
|
||||
// applicationIdMap[obj.applicationId ?? obj.id] = conversionIds;
|
||||
convertActivity?.SetStatus(SdkActivityStatusCode.Ok);
|
||||
}
|
||||
catch (Exception ex) when (!ex.IsFatal())
|
||||
{
|
||||
// TODO: No conversion report yet
|
||||
conversionResults.Add(new GrasshopperReceiveConversionResult(Status.ERROR, obj, null, null, null, ex));
|
||||
convertActivity?.SetStatus(SdkActivityStatusCode.Error);
|
||||
convertActivity?.RecordException(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 6 - Convert instances
|
||||
using (var _ = _activityFactory.Start("Converting instances"))
|
||||
{
|
||||
// TODO: No instances yet
|
||||
// var (createdInstanceIds, consumedObjectIds, instanceConversionResults) = await _instanceBaker
|
||||
// .BakeInstances(instanceComponentsWithPath, applicationIdMap, baseLayerName, onOperationProgressed)
|
||||
// .ConfigureAwait(false);
|
||||
|
||||
// TODO: No conversion report yet
|
||||
// conversionResults.RemoveAll(result => result.ResultId != null && consumedObjectIds.Contains(result.ResultId)); // remove all conversion results for atomic objects that have been consumed (POC: not that cool, but prevents problems on object highlighting)
|
||||
// conversionResults.AddRange(instanceConversionResults); // add instance conversion results to our list
|
||||
}
|
||||
|
||||
// 7 - Create groups
|
||||
if (unpackedRoot.GroupProxies is not null)
|
||||
{
|
||||
// TODO: No groups yet
|
||||
// _groupBaker.BakeGroups(unpackedRoot.GroupProxies, applicationIdMap, baseLayerName);
|
||||
}
|
||||
|
||||
return new HostObjectBuilderResult([], conversionResults);
|
||||
}
|
||||
}
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
using Speckle.Connectors.Common.Operations;
|
||||
using Speckle.Connectors.Logging;
|
||||
using Speckle.Sdk.Api;
|
||||
using Speckle.Sdk.Credentials;
|
||||
using Speckle.Sdk.Logging;
|
||||
using Speckle.Sdk.Models;
|
||||
using Speckle.Sdk.Transports;
|
||||
|
||||
namespace Speckle.Connectors.Grasshopper8.Operations.Receive;
|
||||
|
||||
public class GrasshopperReceiveOperation
|
||||
{
|
||||
private readonly AccountService _accountService;
|
||||
private readonly IServerTransportFactory _serverTransportFactory;
|
||||
private readonly IProgressDisplayManager _progressDisplayManager;
|
||||
private readonly ISdkActivityFactory _activityFactory;
|
||||
private readonly IOperations _operations;
|
||||
private readonly IClientFactory _clientFactory;
|
||||
|
||||
public GrasshopperReceiveOperation(
|
||||
AccountService accountService,
|
||||
IServerTransportFactory serverTransportFactory,
|
||||
IProgressDisplayManager progressDisplayManager,
|
||||
ISdkActivityFactory activityFactory,
|
||||
IOperations operations,
|
||||
IClientFactory clientFactory
|
||||
)
|
||||
{
|
||||
_accountService = accountService;
|
||||
_serverTransportFactory = serverTransportFactory;
|
||||
_progressDisplayManager = progressDisplayManager;
|
||||
_activityFactory = activityFactory;
|
||||
_operations = operations;
|
||||
_clientFactory = clientFactory;
|
||||
}
|
||||
|
||||
public async Task<Base> ReceiveCommitObject(
|
||||
ReceiveInfo receiveInfo,
|
||||
IProgress<CardProgress> onOperationProgressed,
|
||||
CancellationToken cancellationToken
|
||||
)
|
||||
{
|
||||
using var execute = _activityFactory.Start("Receive Operation");
|
||||
execute?.SetTag("receiveInfo", receiveInfo);
|
||||
// 2 - Check account exist
|
||||
Account account = _accountService.GetAccountWithServerUrlFallback(receiveInfo.AccountId, receiveInfo.ServerUrl);
|
||||
using Client apiClient = _clientFactory.Create(account);
|
||||
using var userScope = ActivityScope.SetTag(Consts.USER_ID, account.GetHashedEmail());
|
||||
|
||||
var version = await apiClient
|
||||
.Version.Get(receiveInfo.SelectedVersionId, receiveInfo.ProjectId, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
using var transport = _serverTransportFactory.Create(account, receiveInfo.ProjectId);
|
||||
|
||||
double? previousPercentage = null;
|
||||
_progressDisplayManager.Begin();
|
||||
Base commitObject = await _operations
|
||||
.Receive2(
|
||||
new Uri(account.serverInfo.url),
|
||||
receiveInfo.ProjectId,
|
||||
version.referencedObject,
|
||||
account.token,
|
||||
onProgressAction: new PassthroughProgress(args =>
|
||||
{
|
||||
if (args.ProgressEvent == ProgressEvent.CacheCheck || args.ProgressEvent == ProgressEvent.DownloadBytes)
|
||||
{
|
||||
switch (args.ProgressEvent)
|
||||
{
|
||||
case ProgressEvent.CacheCheck:
|
||||
previousPercentage = _progressDisplayManager.CalculatePercentage(args);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!_progressDisplayManager.ShouldUpdate())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
switch (args.ProgressEvent)
|
||||
{
|
||||
case ProgressEvent.CacheCheck:
|
||||
case ProgressEvent.DownloadBytes:
|
||||
onOperationProgressed.Report(new("Checking and Downloading... ", previousPercentage));
|
||||
break;
|
||||
case ProgressEvent.DeserializeObject:
|
||||
onOperationProgressed.Report(new("Deserializing ...", _progressDisplayManager.CalculatePercentage(args)));
|
||||
break;
|
||||
}
|
||||
}),
|
||||
cancellationToken: cancellationToken
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
await apiClient
|
||||
.Version.Received(new(version.id, receiveInfo.ProjectId, receiveInfo.SourceApplication), cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
return commitObject;
|
||||
}
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
using Speckle.Connectors.Common.Builders;
|
||||
using Speckle.Connectors.Common.Operations;
|
||||
using Speckle.Connectors.Grasshopper8.Parameters;
|
||||
using Speckle.Sdk.Models.Collections;
|
||||
|
||||
namespace Speckle.Connectors.Grasshopper8.Operations.Send;
|
||||
|
||||
public class GrasshopperRootObjectBuilder() : IRootObjectBuilder<SpeckleCollectionWrapperGoo>
|
||||
{
|
||||
public Task<RootObjectBuilderResult> Build(
|
||||
IReadOnlyList<SpeckleCollectionWrapperGoo> input,
|
||||
SendInfo sendInfo,
|
||||
IProgress<CardProgress> onOperationProgressed,
|
||||
CancellationToken ct = default
|
||||
)
|
||||
{
|
||||
// TODO: Send info is used in other connectors to get the project ID to populate the SendConversionCache
|
||||
Console.WriteLine($"Send Info {sendInfo}");
|
||||
|
||||
// set the input collection name to "Grasshopper Model"
|
||||
var rootCollection = new Collection { name = "Grasshopper model", elements = input[0].Value.Collection.elements };
|
||||
|
||||
// reconstruct the input collection by substituting all of the objectgoos with base
|
||||
var collection = ReplaceAndRebuild(rootCollection);
|
||||
|
||||
// TODO: Not getting any conversion results yet
|
||||
var result = new RootObjectBuilderResult(collection, []);
|
||||
|
||||
return Task.FromResult(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unwraps collection wrappers and object wrapppers.
|
||||
/// </summary>
|
||||
/// <param name="c"></param>
|
||||
/// <returns></returns>
|
||||
private Collection ReplaceAndRebuild(Collection c)
|
||||
{
|
||||
// Iterate over the current collection's elements
|
||||
var myCollection = new Collection() { name = c.name };
|
||||
|
||||
if (c["topology"] is string topology)
|
||||
{
|
||||
myCollection["topology"] = topology;
|
||||
}
|
||||
|
||||
for (int i = 0; i < c.elements.Count; i++)
|
||||
{
|
||||
var element = c.elements[i];
|
||||
if (element is SpeckleCollectionWrapper collectionWrapper)
|
||||
{
|
||||
var newCollection = new Collection
|
||||
{
|
||||
name = collectionWrapper.Collection.name,
|
||||
["topology"] = collectionWrapper.Topology,
|
||||
elements = collectionWrapper.Collection.elements
|
||||
};
|
||||
var unwrapped = ReplaceAndRebuild(newCollection);
|
||||
myCollection.elements.Add(unwrapped);
|
||||
}
|
||||
else if (element is SpeckleObjectWrapper so)
|
||||
{
|
||||
// If it's not a Collection, replace the non-Collection element
|
||||
myCollection.elements.Add(so.Base);
|
||||
}
|
||||
}
|
||||
return myCollection;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
namespace Speckle.Connectors.Grasshopper8.Parameters;
|
||||
|
||||
internal interface ISpeckleGoo { }
|
||||
+245
@@ -0,0 +1,245 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Collections.Specialized;
|
||||
using Grasshopper.Kernel;
|
||||
using Grasshopper.Kernel.Types;
|
||||
using Grasshopper.Rhinoceros;
|
||||
using Grasshopper.Rhinoceros.Model;
|
||||
using Rhino;
|
||||
using Rhino.DocObjects;
|
||||
using Speckle.Connectors.Grasshopper8.Components;
|
||||
using Speckle.Connectors.Grasshopper8.HostApp;
|
||||
using Speckle.Sdk.Models;
|
||||
using Speckle.Sdk.Models.Collections;
|
||||
using Layer = Rhino.DocObjects.Layer;
|
||||
|
||||
namespace Speckle.Connectors.Grasshopper8.Parameters;
|
||||
|
||||
#pragma warning disable CA1711 // Identifiers should not have incorrect suffix
|
||||
public class SpeckleCollectionWrapper : Base
|
||||
#pragma warning restore CA1711 // Identifiers should not have incorrect suffix
|
||||
{
|
||||
// the original collection
|
||||
public Collection Collection { get; set; }
|
||||
|
||||
// the list of layer names that build up the path to this collection, including this collection name
|
||||
public ObservableCollection<string> Path { get; set; }
|
||||
|
||||
public string Topology { get; set; }
|
||||
|
||||
public int? Color { get; set; }
|
||||
|
||||
public override string ToString() => $"{Collection.name} [{Collection.elements.Count}]";
|
||||
|
||||
public SpeckleCollectionWrapper(Collection value, List<string> path, int? color)
|
||||
{
|
||||
Collection = value;
|
||||
Path = new ObservableCollection<string>(path);
|
||||
Color = color;
|
||||
|
||||
// add listener on path changing.
|
||||
// this can be triggered by a create collection node, that changes the path of this collection.
|
||||
// when this happens, we want to update the paths of all elements downstream
|
||||
Path.CollectionChanged += OnPathChanged;
|
||||
}
|
||||
|
||||
private void OnPathChanged(object sender, NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
var newPath = e.NewItems.Cast<string>().ToList();
|
||||
foreach (var element in Collection.elements)
|
||||
{
|
||||
if (element is SpeckleObjectWrapper o)
|
||||
{
|
||||
o.Path = newPath;
|
||||
}
|
||||
else if (element is SpeckleCollectionWrapper c)
|
||||
{
|
||||
c.Path = new ObservableCollection<string>(newPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Bake(
|
||||
RhinoDoc doc,
|
||||
List<Guid> obj_ids,
|
||||
List<string> path,
|
||||
bool bakeObjects,
|
||||
List<Sdk.Models.Base>? elements = null
|
||||
)
|
||||
{
|
||||
if (!LayerExists(doc, path, out int currentLayerIndex))
|
||||
{
|
||||
currentLayerIndex = CreateLayerByPath(doc, path);
|
||||
}
|
||||
|
||||
// then bake elements in this collection
|
||||
List<Sdk.Models.Base> e = elements ?? Collection.elements;
|
||||
foreach (var obj in e)
|
||||
{
|
||||
if (obj is SpeckleObjectWrapper so)
|
||||
{
|
||||
if (bakeObjects)
|
||||
{
|
||||
so.Bake(doc, obj_ids, currentLayerIndex, true);
|
||||
}
|
||||
}
|
||||
else if (obj is SpeckleCollectionWrapper c)
|
||||
{
|
||||
path.Add(c.Collection.name);
|
||||
Bake(doc, obj_ids, path, bakeObjects, c.Collection.elements);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool LayerExists(RhinoDoc doc, List<string> path, out int layerIndex)
|
||||
{
|
||||
var fullPath = string.Join(Constants.LAYER_PATH_DELIMITER, path);
|
||||
layerIndex = doc.Layers.FindByFullPath(fullPath, -1);
|
||||
return layerIndex != -1;
|
||||
}
|
||||
|
||||
private int CreateLayer(RhinoDoc doc, string name, Guid parentId)
|
||||
{
|
||||
Layer layer = new() { Name = name, ParentLayerId = parentId };
|
||||
return doc.Layers.Add(layer);
|
||||
}
|
||||
|
||||
public int CreateLayerByPath(RhinoDoc doc, List<string> path)
|
||||
{
|
||||
if (path.Count == 0 || doc == null)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
int parentLayerIndex = -1;
|
||||
List<string> currentfullpath = new();
|
||||
Guid currentLayerId = Guid.Empty;
|
||||
foreach (string layerName in path)
|
||||
{
|
||||
currentfullpath.Add(layerName);
|
||||
|
||||
// Find or create the layer at this level
|
||||
if (LayerExists(doc, currentfullpath, out int currentLayerIndex))
|
||||
{
|
||||
currentLayerId = doc.Layers.FindIndex(currentLayerIndex).Id;
|
||||
}
|
||||
else
|
||||
{
|
||||
currentLayerIndex = CreateLayer(doc, layerName, currentLayerId);
|
||||
currentLayerId = doc.Layers.FindIndex(currentLayerIndex).Id;
|
||||
}
|
||||
parentLayerIndex = currentLayerIndex;
|
||||
}
|
||||
|
||||
return parentLayerIndex;
|
||||
}
|
||||
}
|
||||
|
||||
public class SpeckleCollectionWrapperGoo : GH_Goo<SpeckleCollectionWrapper>, ISpeckleGoo //, IGH_PreviewData // can be made previewable later
|
||||
{
|
||||
public override IGH_Goo Duplicate() => throw new NotImplementedException();
|
||||
|
||||
public override string ToString() =>
|
||||
$@"Speckle Collection Goo [{m_value.Collection?.name} ({Value.Collection.elements.Count})]";
|
||||
|
||||
public override bool IsValid => true;
|
||||
public override string TypeName => "Speckle collection wrapper";
|
||||
public override string TypeDescription => "Speckle collection wrapper";
|
||||
|
||||
public override bool CastFrom(object source)
|
||||
{
|
||||
switch (source)
|
||||
{
|
||||
case SpeckleCollectionWrapper speckleGrasshopperCollection:
|
||||
Value = speckleGrasshopperCollection;
|
||||
return true;
|
||||
case GH_Goo<SpeckleCollectionWrapper> speckleGrasshopperCollectionGoo:
|
||||
Value = speckleGrasshopperCollectionGoo.Value;
|
||||
return true;
|
||||
case ModelLayer modelLayer:
|
||||
Collection modelCollection = new() { name = modelLayer.Name, elements = new() };
|
||||
Value = new SpeckleCollectionWrapper(
|
||||
modelCollection,
|
||||
GetModelLayerPath(modelLayer),
|
||||
modelLayer.DisplayColor?.ToArgb()
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private List<string> GetModelLayerPath(ModelLayer modellayer)
|
||||
{
|
||||
ModelContentName currentParent = modellayer.Parent;
|
||||
ModelContentName stem = modellayer.Parent.Stem;
|
||||
List<string> path = new() { modellayer.Name };
|
||||
while (currentParent != stem)
|
||||
{
|
||||
path.Add(currentParent);
|
||||
currentParent = currentParent.Parent;
|
||||
}
|
||||
path.Add(stem);
|
||||
|
||||
path.Reverse();
|
||||
return path;
|
||||
}
|
||||
|
||||
public SpeckleCollectionWrapperGoo() { }
|
||||
|
||||
public SpeckleCollectionWrapperGoo(SpeckleCollectionWrapper value)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
}
|
||||
|
||||
public class SpeckleCollectionParam : GH_Param<SpeckleCollectionWrapperGoo>, IGH_BakeAwareObject
|
||||
{
|
||||
public SpeckleCollectionParam()
|
||||
: this(GH_ParamAccess.item) { }
|
||||
|
||||
public SpeckleCollectionParam(IGH_InstanceDescription tag)
|
||||
: base(tag) { }
|
||||
|
||||
public SpeckleCollectionParam(IGH_InstanceDescription tag, GH_ParamAccess access)
|
||||
: base(tag, access) { }
|
||||
|
||||
public SpeckleCollectionParam(GH_ParamAccess access)
|
||||
: base(
|
||||
"Speckle Collection",
|
||||
"SCO",
|
||||
"XXXXX",
|
||||
ComponentCategories.PRIMARY_RIBBON,
|
||||
ComponentCategories.PARAMETERS,
|
||||
access
|
||||
) { }
|
||||
|
||||
public override Guid ComponentGuid => new("6E871D5B-B221-4992-882A-EFE6796F3010");
|
||||
protected override Bitmap Icon => BitmapBuilder.CreateHexagonalBitmap("C");
|
||||
|
||||
bool IGH_BakeAwareObject.IsBakeCapable => // False if no data
|
||||
!VolatileData.IsEmpty;
|
||||
|
||||
void IGH_BakeAwareObject.BakeGeometry(RhinoDoc doc, List<Guid> obj_ids)
|
||||
{
|
||||
// Iterate over all data stored in the parameter
|
||||
foreach (var item in VolatileData.AllData(true))
|
||||
{
|
||||
if (item is SpeckleCollectionWrapperGoo goo)
|
||||
{
|
||||
goo.Value.Bake(doc, obj_ids, goo.Value.Path.ToList(), true, goo.Value.Collection.elements);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void IGH_BakeAwareObject.BakeGeometry(RhinoDoc doc, ObjectAttributes att, List<Guid> obj_ids)
|
||||
{
|
||||
// Iterate over all data stored in the parameter
|
||||
foreach (var item in VolatileData.AllData(true))
|
||||
{
|
||||
if (item is SpeckleCollectionWrapperGoo goo)
|
||||
{
|
||||
goo.Value.Bake(doc, obj_ids, goo.Value.Path.ToList(), true, goo.Value.Collection.elements);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+317
@@ -0,0 +1,317 @@
|
||||
using Grasshopper.Kernel;
|
||||
using Grasshopper.Kernel.Types;
|
||||
using Grasshopper.Rhinoceros.Model;
|
||||
using Rhino;
|
||||
using Rhino.Display;
|
||||
using Rhino.DocObjects;
|
||||
using Rhino.Geometry;
|
||||
using Speckle.Connectors.Grasshopper8.Components;
|
||||
using Speckle.Connectors.Grasshopper8.HostApp;
|
||||
using Speckle.Sdk.Models;
|
||||
|
||||
namespace Speckle.Connectors.Grasshopper8.Parameters;
|
||||
|
||||
/// <summary>
|
||||
/// Wrapper around a geometry base object and its converted speckle equivalent.
|
||||
/// </summary>
|
||||
public class SpeckleObjectWrapper : Base
|
||||
{
|
||||
public required Base Base { get; set; }
|
||||
|
||||
// note: how will we send intervals and other gh native objects? do we? maybe not for now
|
||||
// note: this does not handle on to many relationship well.
|
||||
// For receiving data objects, we are wrapping every value in the data object display value, and storing a reference to the same data object in each wrapped object.
|
||||
public required GeometryBase GeometryBase { get; set; }
|
||||
|
||||
// The list of layer/collection names that forms the full path to this object
|
||||
public List<string> Path { get; set; } = new();
|
||||
public SpeckleCollectionWrapper? Parent { get; set; }
|
||||
|
||||
// A dictionary of property path to property
|
||||
public SpecklePropertyGroupGoo Properties { get; set; } = new();
|
||||
public string Name { get; set; } = "";
|
||||
public int? Color { get; set; }
|
||||
public string? RenderMaterialName { get; set; }
|
||||
|
||||
// RenderMaterial, ColorProxies, Properties (?)
|
||||
public override string ToString() => $"Speckle Wrapper [{GeometryBase.GetType().Name}]";
|
||||
|
||||
public void DrawPreview(IGH_PreviewArgs args, bool isSelected = false)
|
||||
{
|
||||
switch (GeometryBase)
|
||||
{
|
||||
case Mesh m:
|
||||
args.Display.DrawMeshShaded(m, isSelected ? args.ShadeMaterial_Selected : args.ShadeMaterial);
|
||||
break;
|
||||
|
||||
case Brep b:
|
||||
args.Display.DrawBrepShaded(b, isSelected ? args.ShadeMaterial_Selected : args.ShadeMaterial);
|
||||
args.Display.DrawBrepWires(
|
||||
b,
|
||||
isSelected ? args.WireColour_Selected : args.WireColour,
|
||||
args.DefaultCurveThickness
|
||||
);
|
||||
break;
|
||||
|
||||
case Extrusion e:
|
||||
args.Display.DrawMeshShaded(
|
||||
e.GetMesh(MeshType.Any),
|
||||
isSelected ? args.ShadeMaterial_Selected : args.ShadeMaterial
|
||||
);
|
||||
break;
|
||||
|
||||
case SubD d:
|
||||
args.Display.DrawSubDShaded(d, isSelected ? args.ShadeMaterial_Selected : args.ShadeMaterial);
|
||||
args.Display.DrawSubDWires(
|
||||
d,
|
||||
isSelected ? args.WireColour_Selected : args.WireColour,
|
||||
args.DefaultCurveThickness
|
||||
);
|
||||
break;
|
||||
|
||||
case Curve c:
|
||||
args.Display.DrawCurve(c, isSelected ? args.WireColour_Selected : args.WireColour, args.DefaultCurveThickness);
|
||||
break;
|
||||
|
||||
case Rhino.Geometry.Point p:
|
||||
args.Display.DrawPoint(p.Location, isSelected ? args.WireColour_Selected : args.WireColour);
|
||||
break;
|
||||
|
||||
case PointCloud pc:
|
||||
args.Display.DrawPointCloud(pc, 1, isSelected ? args.WireColour_Selected : args.WireColour);
|
||||
break;
|
||||
|
||||
case Hatch h:
|
||||
args.Display.DrawHatch(
|
||||
h,
|
||||
isSelected ? args.WireColour_Selected : args.WireColour,
|
||||
isSelected ? args.WireColour_Selected : args.WireColour
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void DrawPreviewRaw(DisplayPipeline display, DisplayMaterial material)
|
||||
{
|
||||
switch (GeometryBase)
|
||||
{
|
||||
case Mesh m:
|
||||
display.DrawMeshShaded(m, material);
|
||||
break;
|
||||
case Brep b:
|
||||
display.DrawBrepShaded(b, material);
|
||||
display.DrawBrepWires(b, material.Diffuse);
|
||||
break;
|
||||
case Extrusion e:
|
||||
var eBrep = e.ToBrep();
|
||||
display.DrawBrepShaded(eBrep, material);
|
||||
display.DrawBrepWires(eBrep, material.Diffuse);
|
||||
break;
|
||||
case SubD d:
|
||||
display.DrawSubDShaded(d, material);
|
||||
display.DrawSubDWires(d, material.Diffuse, display.DefaultCurveThickness);
|
||||
break;
|
||||
case Curve c:
|
||||
display.DrawCurve(c, material.Diffuse);
|
||||
break;
|
||||
case Rhino.Geometry.Point p:
|
||||
display.DrawPoint(p.Location, material.Diffuse);
|
||||
break;
|
||||
case PointCloud pc:
|
||||
display.DrawPointCloud(pc, 1, material.Diffuse);
|
||||
break;
|
||||
case Hatch h:
|
||||
display.DrawHatch(h, material.Diffuse, material.Diffuse);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void Bake(RhinoDoc doc, List<Guid> obj_ids, int bakeLayerIndex = -1, bool layersAlreadyCreated = false)
|
||||
{
|
||||
// get or make layers
|
||||
if (!layersAlreadyCreated && bakeLayerIndex < 0)
|
||||
{
|
||||
if (Path.Count > 0 && Parent != null)
|
||||
{
|
||||
bakeLayerIndex = Parent.CreateLayerByPath(doc, Path);
|
||||
}
|
||||
}
|
||||
|
||||
// create attributes
|
||||
using ObjectAttributes att = new() { Name = Name };
|
||||
|
||||
if (Color is int argb)
|
||||
{
|
||||
att.ObjectColor = System.Drawing.Color.FromArgb(argb);
|
||||
att.ColorSource = ObjectColorSource.ColorFromObject;
|
||||
att.LayerIndex = bakeLayerIndex;
|
||||
}
|
||||
|
||||
foreach (var kvp in Properties.Value)
|
||||
{
|
||||
att.SetUserString(kvp.Key, kvp.Value.Value.ToString());
|
||||
}
|
||||
|
||||
// add to doc
|
||||
Guid guid = doc.Objects.Add(GeometryBase, att);
|
||||
obj_ids.Add(guid);
|
||||
}
|
||||
}
|
||||
|
||||
public class SpeckleObjectWrapperGoo : GH_Goo<SpeckleObjectWrapper>, IGH_PreviewData, ISpeckleGoo
|
||||
{
|
||||
public override IGH_Goo Duplicate() => throw new NotImplementedException();
|
||||
|
||||
public override string ToString() => $@"Speckle Object Goo [{m_value.Base?.speckle_type}]";
|
||||
|
||||
public override bool IsValid => true;
|
||||
public override string TypeName => "Speckle object wrapper";
|
||||
public override string TypeDescription => "A wrapper around speckle grasshopper objects.";
|
||||
|
||||
BoundingBox IGH_PreviewData.ClippingBox => Value.GeometryBase.GetBoundingBox(false);
|
||||
|
||||
public SpeckleObjectWrapperGoo(ModelObject mo)
|
||||
{
|
||||
CastFrom(mo);
|
||||
}
|
||||
|
||||
public override bool CastFrom(object source)
|
||||
{
|
||||
switch (source)
|
||||
{
|
||||
case SpeckleObjectWrapper speckleGrasshopperObject:
|
||||
Value = speckleGrasshopperObject;
|
||||
return true;
|
||||
case GH_Goo<SpeckleObjectWrapper> speckleGrasshopperObjectGoo:
|
||||
Value = speckleGrasshopperObjectGoo.Value;
|
||||
return true;
|
||||
case IGH_GeometricGoo geometricGoo:
|
||||
var gooGB = geometricGoo.GeometricGooToGeometryBase();
|
||||
var gooConverted = ToSpeckleConversionContext.ToSpeckleConverter.Convert(gooGB);
|
||||
Value = new SpeckleObjectWrapper() { GeometryBase = gooGB, Base = gooConverted };
|
||||
return true;
|
||||
case ModelObject modelObject:
|
||||
if (GetGeometryFromModelObject(modelObject) is GeometryBase modelGB)
|
||||
{
|
||||
var modelConverted = ToSpeckleConversionContext.ToSpeckleConverter.Convert(modelGB);
|
||||
SpecklePropertyGroupGoo propertyGroup = new();
|
||||
propertyGroup.CastFrom(modelObject.UserText);
|
||||
|
||||
// update the converted Base with props as well
|
||||
modelConverted["name"] = modelObject.Name.ToString();
|
||||
Dictionary<string, object?> propertyDict = new();
|
||||
foreach (var entry in propertyGroup.Value)
|
||||
{
|
||||
propertyDict.Add(entry.Key, entry.Value.Value);
|
||||
}
|
||||
modelConverted["properties"] = propertyDict;
|
||||
|
||||
SpeckleObjectWrapper so =
|
||||
new()
|
||||
{
|
||||
GeometryBase = modelGB,
|
||||
Base = modelConverted,
|
||||
Name = modelObject.Name.ToString(),
|
||||
Color = modelObject.Display.Color?.Color.ToArgb(),
|
||||
RenderMaterialName = modelObject.Render.Material?.Material?.Name,
|
||||
Properties = propertyGroup
|
||||
};
|
||||
|
||||
Value = so;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private GeometryBase? GetGeometryFromModelObject(ModelObject modelObject) =>
|
||||
RhinoDoc.ActiveDoc.Objects.FindId(modelObject.Id ?? Guid.Empty).Geometry;
|
||||
|
||||
public override bool CastTo<T>(ref T target)
|
||||
{
|
||||
var type = typeof(T);
|
||||
|
||||
if (type == typeof(IGH_GeometricGoo))
|
||||
{
|
||||
target = (T)(object)GH_Convert.ToGeometricGoo(Value.GeometryBase);
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO: cast to material, etc.
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void DrawViewportWires(GH_PreviewWireArgs args)
|
||||
{
|
||||
// TODO ?
|
||||
}
|
||||
|
||||
public void DrawViewportMeshes(GH_PreviewMeshArgs args)
|
||||
{
|
||||
Value.DrawPreviewRaw(args.Pipeline, args.Material);
|
||||
}
|
||||
|
||||
public SpeckleObjectWrapperGoo(SpeckleObjectWrapper value)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
|
||||
public SpeckleObjectWrapperGoo() { }
|
||||
}
|
||||
|
||||
public class SpeckleObjectParam : GH_Param<SpeckleObjectWrapperGoo>, IGH_BakeAwareObject
|
||||
{
|
||||
public SpeckleObjectParam()
|
||||
: this(GH_ParamAccess.item) { }
|
||||
|
||||
public SpeckleObjectParam(IGH_InstanceDescription tag)
|
||||
: base(tag) { }
|
||||
|
||||
public SpeckleObjectParam(IGH_InstanceDescription tag, GH_ParamAccess access)
|
||||
: base(tag, access) { }
|
||||
|
||||
public SpeckleObjectParam(GH_ParamAccess access)
|
||||
: base(
|
||||
"Speckle Object",
|
||||
"SO",
|
||||
"Represents a Speckle object",
|
||||
ComponentCategories.PRIMARY_RIBBON,
|
||||
ComponentCategories.PARAMETERS,
|
||||
access
|
||||
) { }
|
||||
|
||||
public override Guid ComponentGuid => new("22FD5510-D5D3-4101-8727-153FFD329E4F");
|
||||
|
||||
protected override Bitmap Icon => BitmapBuilder.CreateHexagonalBitmap("SO");
|
||||
|
||||
public bool IsBakeCapable =>
|
||||
// False if no data
|
||||
!VolatileData.IsEmpty;
|
||||
|
||||
public void BakeGeometry(RhinoDoc doc, List<Guid> obj_ids)
|
||||
{
|
||||
// Iterate over all data stored in the parameter
|
||||
foreach (var item in VolatileData.AllData(true))
|
||||
{
|
||||
if (item is SpeckleObjectWrapperGoo goo)
|
||||
{
|
||||
goo.Value.Bake(doc, obj_ids);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void BakeGeometry(RhinoDoc doc, ObjectAttributes att, List<Guid> obj_ids)
|
||||
{
|
||||
// Iterate over all data stored in the parameter
|
||||
foreach (var item in VolatileData.AllData(true))
|
||||
{
|
||||
if (item is SpeckleObjectWrapperGoo goo)
|
||||
{
|
||||
goo.Value.Bake(doc, obj_ids);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+140
@@ -0,0 +1,140 @@
|
||||
using Grasshopper.Kernel;
|
||||
using Grasshopper.Kernel.Types;
|
||||
using Grasshopper.Rhinoceros;
|
||||
using Speckle.Connectors.Grasshopper8.Components;
|
||||
using Speckle.Connectors.Grasshopper8.HostApp;
|
||||
|
||||
namespace Speckle.Connectors.Grasshopper8.Parameters;
|
||||
|
||||
/// <summary>
|
||||
/// The Speckle Property Group Goo is a flat dictionary of (speckle property path, speckle property).
|
||||
/// The speckle property path is the concatenated string of all original flattened keys with the property delimiter
|
||||
/// </summary>
|
||||
public class SpecklePropertyGroupGoo : GH_Goo<Dictionary<string, SpecklePropertyGoo>>, ISpeckleGoo
|
||||
{
|
||||
public override IGH_Goo Duplicate() => throw new NotImplementedException();
|
||||
|
||||
public override string ToString() => $"PropertyGroup ({Value.Count})";
|
||||
|
||||
public override bool IsValid => true;
|
||||
public override string TypeName => "Speckle property group wrapper";
|
||||
public override string TypeDescription => "Speckle property group wrapper";
|
||||
|
||||
public SpecklePropertyGroupGoo()
|
||||
{
|
||||
Value = new();
|
||||
}
|
||||
|
||||
public SpecklePropertyGroupGoo(Dictionary<string, SpecklePropertyGoo> value)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
|
||||
public SpecklePropertyGroupGoo(Dictionary<string, object?> value)
|
||||
{
|
||||
CastFrom(value);
|
||||
}
|
||||
|
||||
public override bool CastFrom(object source)
|
||||
{
|
||||
switch (source)
|
||||
{
|
||||
case SpecklePropertyGroupGoo specklePropertyGroup:
|
||||
Value = specklePropertyGroup.Value;
|
||||
return true;
|
||||
|
||||
case ModelUserText userText:
|
||||
Dictionary<string, SpecklePropertyGoo> dictionary = new();
|
||||
foreach (KeyValuePair<string, string> entry in userText)
|
||||
{
|
||||
string key = entry.Key;
|
||||
SpecklePropertyGoo value = new() { Path = key, Value = entry.Value };
|
||||
dictionary.Add(key, value);
|
||||
}
|
||||
|
||||
Value = dictionary;
|
||||
return true;
|
||||
|
||||
case Dictionary<string, object?> properties:
|
||||
Dictionary<string, object> flattenedProperties = new();
|
||||
FlattenDictionary(properties, flattenedProperties, "");
|
||||
Dictionary<string, SpecklePropertyGoo> speckleProperties = new();
|
||||
foreach (var kvp in flattenedProperties)
|
||||
{
|
||||
speckleProperties.Add(kvp.Key, new() { Value = kvp.Value });
|
||||
}
|
||||
Value = speckleProperties;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public override bool CastTo<T>(ref T target)
|
||||
{
|
||||
var type = typeof(T);
|
||||
if (type == typeof(Dictionary<string, object?>))
|
||||
{
|
||||
Dictionary<string, object?> dictionary = new();
|
||||
foreach (var entry in Value)
|
||||
{
|
||||
dictionary.Add(entry.Key, entry.Value);
|
||||
}
|
||||
|
||||
target = (T)(object)dictionary;
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO: cast to material, model object, etc.
|
||||
return false;
|
||||
}
|
||||
|
||||
// Flattens a dictionary that may contain more dictionaries of the same type
|
||||
private void FlattenDictionary(
|
||||
Dictionary<string, object?> dict,
|
||||
Dictionary<string, object> flattenedDict,
|
||||
string keyPrefix = ""
|
||||
)
|
||||
{
|
||||
foreach (var kvp in dict)
|
||||
{
|
||||
string newKey = string.IsNullOrEmpty(keyPrefix)
|
||||
? kvp.Key
|
||||
: $"{keyPrefix}{Constants.PROPERTY_PATH_DELIMITER}{kvp.Key}";
|
||||
|
||||
if (kvp.Value is Dictionary<string, object?> childDict)
|
||||
{
|
||||
FlattenDictionary(childDict, flattenedDict, newKey);
|
||||
}
|
||||
else
|
||||
{
|
||||
flattenedDict.Add(newKey, kvp.Value ?? "");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class SpecklePropertyGroupParam : GH_Param<SpecklePropertyGroupGoo>
|
||||
{
|
||||
public override Guid ComponentGuid => new("AF4757C3-BA33-4ACD-A92B-C80356043129");
|
||||
protected override Bitmap Icon => BitmapBuilder.CreateHexagonalBitmap("PG");
|
||||
|
||||
public SpecklePropertyGroupParam()
|
||||
: this(GH_ParamAccess.item) { }
|
||||
|
||||
public SpecklePropertyGroupParam(IGH_InstanceDescription tag)
|
||||
: base(tag) { }
|
||||
|
||||
public SpecklePropertyGroupParam(IGH_InstanceDescription tag, GH_ParamAccess access)
|
||||
: base(tag, access) { }
|
||||
|
||||
public SpecklePropertyGroupParam(GH_ParamAccess access)
|
||||
: base(
|
||||
"Speckle Property Group",
|
||||
"SPGO",
|
||||
"Represents a Dictionary property group",
|
||||
ComponentCategories.PRIMARY_RIBBON,
|
||||
ComponentCategories.PARAMETERS,
|
||||
access
|
||||
) { }
|
||||
}
|
||||
+140
@@ -0,0 +1,140 @@
|
||||
using System.Runtime.InteropServices;
|
||||
using Grasshopper.Kernel;
|
||||
using Grasshopper.Kernel.Types;
|
||||
using Speckle.Connectors.Grasshopper8.Components;
|
||||
using Speckle.Connectors.Grasshopper8.HostApp;
|
||||
|
||||
namespace Speckle.Connectors.Grasshopper8.Parameters;
|
||||
|
||||
public class SpecklePropertyGoo : GH_Goo<object>, ISpeckleGoo
|
||||
{
|
||||
public override IGH_Goo Duplicate() => throw new NotImplementedException();
|
||||
|
||||
public override string ToString() => $"{Path} - {Value}";
|
||||
|
||||
public string Path { get; set; }
|
||||
|
||||
public override bool IsValid => true;
|
||||
public override string TypeName => "Speckle property wrapper";
|
||||
public override string TypeDescription => "Speckle property wrapper";
|
||||
|
||||
public SpecklePropertyGoo() { }
|
||||
|
||||
public SpecklePropertyGoo(object value)
|
||||
{
|
||||
SpecklePropertyGoo goo = new();
|
||||
if (goo.CastFrom(value))
|
||||
{
|
||||
Value = goo;
|
||||
}
|
||||
else
|
||||
{
|
||||
//TODO: throw
|
||||
}
|
||||
}
|
||||
|
||||
public override bool CastFrom(object source)
|
||||
{
|
||||
switch (source)
|
||||
{
|
||||
case SpecklePropertyGoo speckleProperty:
|
||||
Value = speckleProperty.Value;
|
||||
Path = speckleProperty.Path;
|
||||
return true;
|
||||
case double d:
|
||||
Value = new SpecklePropertyGoo() { Value = d, Path = string.Empty };
|
||||
return true;
|
||||
case int i:
|
||||
Value = new SpecklePropertyGoo() { Value = i, Path = string.Empty };
|
||||
return true;
|
||||
case string s:
|
||||
Value = new SpecklePropertyGoo() { Value = s, Path = string.Empty };
|
||||
return true;
|
||||
case bool b:
|
||||
Value = new SpecklePropertyGoo() { Value = b, Path = string.Empty };
|
||||
return true;
|
||||
case KeyValuePair<string, object?> kvp:
|
||||
Value = new SpecklePropertyGoo() { Value = kvp.Value ?? "", Path = kvp.Key };
|
||||
return true;
|
||||
case KeyValuePair<string, string> kvp:
|
||||
Value = new SpecklePropertyGoo() { Value = kvp.Value, Path = kvp.Key };
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public override bool CastTo<T>(ref T target)
|
||||
{
|
||||
var type = typeof(T);
|
||||
|
||||
if (
|
||||
type.IsAssignableFrom(typeof(int))
|
||||
|| type.IsAssignableFrom(typeof(double))
|
||||
|| type.IsAssignableFrom(typeof(bool))
|
||||
|| type.IsAssignableFrom(typeof(string))
|
||||
)
|
||||
{
|
||||
object? ptr = Value;
|
||||
target = (T)ptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (type.IsAssignableFrom(typeof(GH_Integer)))
|
||||
{
|
||||
object ptr = new GH_Integer((int)Value);
|
||||
target = (T)ptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (type.IsAssignableFrom(typeof(GH_Number)))
|
||||
{
|
||||
object ptr = new GH_Number((double)Value);
|
||||
target = (T)ptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (type.IsAssignableFrom(typeof(GH_Boolean)))
|
||||
{
|
||||
object ptr = new GH_Boolean((bool)Value);
|
||||
target = (T)ptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (type.IsAssignableFrom(typeof(GH_String)))
|
||||
{
|
||||
object ptr = new GH_String((string)Value);
|
||||
target = (T)ptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
[Guid("B3101D12-DA73-45DF-B617-16E1C65BB37C")]
|
||||
public class SpecklePropertyParam : GH_Param<SpecklePropertyGoo>
|
||||
{
|
||||
public SpecklePropertyParam(GH_ParamAccess access)
|
||||
: base(
|
||||
"Speckle Property",
|
||||
"SPO",
|
||||
"Represents a Speckle Property",
|
||||
ComponentCategories.PRIMARY_RIBBON,
|
||||
ComponentCategories.PARAMETERS,
|
||||
access
|
||||
) { }
|
||||
|
||||
public override Guid ComponentGuid => GetType().GUID;
|
||||
|
||||
protected override Bitmap Icon => BitmapBuilder.CreateHexagonalBitmap("P");
|
||||
|
||||
public SpecklePropertyParam()
|
||||
: this(GH_ParamAccess.item) { }
|
||||
|
||||
public SpecklePropertyParam(IGH_InstanceDescription tag)
|
||||
: base(tag) { }
|
||||
|
||||
public SpecklePropertyParam(IGH_InstanceDescription tag, GH_ParamAccess access)
|
||||
: base(tag, access) { }
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
using Grasshopper.Kernel.Types;
|
||||
using Speckle.Connectors.Grasshopper8.HostApp;
|
||||
|
||||
namespace Speckle.Connectors.Grasshopper8.Parameters;
|
||||
|
||||
public class SpeckleUrlModelResourceGoo : GH_Goo<SpeckleUrlModelResource>
|
||||
{
|
||||
public override IGH_Goo Duplicate() => new SpeckleUrlModelResourceGoo() { Value = Value };
|
||||
|
||||
public override string ToString() => Value.ToString();
|
||||
|
||||
public override bool IsValid => true;
|
||||
public override string TypeName => "SpeckleUrlModelResource";
|
||||
public override string TypeDescription => "Points to a model/version/object in a Speckle server";
|
||||
|
||||
public override bool CastFrom(object source)
|
||||
{
|
||||
switch (source)
|
||||
{
|
||||
case SpeckleUrlModelResource resource:
|
||||
Value = resource;
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool CastTo<TOut>(ref TOut target)
|
||||
{
|
||||
var type = typeof(TOut);
|
||||
var success = false;
|
||||
if (type == typeof(SpeckleUrlModelResource))
|
||||
{
|
||||
target = (TOut)(object)Value;
|
||||
success = true;
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
using Grasshopper.Kernel;
|
||||
|
||||
namespace Speckle.Connectors.Grasshopper8.Parameters;
|
||||
|
||||
public class SpeckleUrlModelResourceParam : GH_Param<SpeckleUrlModelResourceGoo>
|
||||
{
|
||||
public SpeckleUrlModelResourceParam()
|
||||
: this(GH_ParamAccess.item) { }
|
||||
|
||||
public SpeckleUrlModelResourceParam(IGH_InstanceDescription tag)
|
||||
: base(tag) { }
|
||||
|
||||
public SpeckleUrlModelResourceParam(IGH_InstanceDescription tag, GH_ParamAccess access)
|
||||
: base(tag, access) { }
|
||||
|
||||
public SpeckleUrlModelResourceParam(GH_ParamAccess access)
|
||||
: base("Speckle URL", "URL", "A Speckle resource", "Speckle", "Resources", access) { }
|
||||
|
||||
public override Guid ComponentGuid => new Guid("E5421FC2-F10D-447F-BF23-5C934ABDB2D3");
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"profiles": {
|
||||
"Rhino8Core": {
|
||||
"commandName": "Executable",
|
||||
"executablePath": "C:\\Program Files\\Rhino 8\\System\\Rhino.exe",
|
||||
"commandLineArgs": "/netcore /runscript=\"_Grasshopper\"",
|
||||
"environmentVariables": {
|
||||
"RHINO_PACKAGE_DIRS": "$(ProjectDir)$(OutputPath)\\"
|
||||
}
|
||||
},
|
||||
"Rhino8NetFx": {
|
||||
"commandName": "Executable",
|
||||
"executablePath": "C:\\Program Files\\Rhino 8\\System\\Rhino.exe",
|
||||
"commandLineArgs": "/netfx /runscript=\"_Grasshopper\"",
|
||||
"environmentVariables": {
|
||||
"RHINO_PACKAGE_DIRS": "$(ProjectDir)$(OutputPath)\\"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
using Grasshopper.Kernel;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Speckle.Connectors.Common;
|
||||
using Speckle.Connectors.Common.Builders;
|
||||
using Speckle.Connectors.Common.Operations;
|
||||
using Speckle.Connectors.Common.Operations.Receive;
|
||||
using Speckle.Connectors.Common.Threading;
|
||||
using Speckle.Connectors.Grasshopper8.Operations.Receive;
|
||||
using Speckle.Connectors.Grasshopper8.Operations.Send;
|
||||
using Speckle.Connectors.Grasshopper8.Parameters;
|
||||
using Speckle.Converters.Rhino;
|
||||
using Speckle.Sdk;
|
||||
using Speckle.Sdk.Credentials;
|
||||
using Speckle.Sdk.Host;
|
||||
using Speckle.Sdk.Models.GraphTraversal;
|
||||
|
||||
namespace Speckle.Connectors.Grasshopper8.Registration;
|
||||
|
||||
public class PriorityLoader : GH_AssemblyPriority
|
||||
{
|
||||
private IDisposable? _disposableLogger;
|
||||
public static ServiceProvider? Container { get; set; }
|
||||
|
||||
public override GH_LoadingInstruction PriorityLoad()
|
||||
{
|
||||
try
|
||||
{
|
||||
var services = new ServiceCollection();
|
||||
_disposableLogger = services.Initialize(HostApplications.Grasshopper, GetVersion());
|
||||
services.AddRhinoConverters().AddConnectorUtils();
|
||||
|
||||
// receive
|
||||
services.AddTransient<IHostObjectBuilder, GrasshopperHostObjectBuilder>();
|
||||
services.AddTransient<GrasshopperReceiveOperation>();
|
||||
services.AddSingleton(DefaultTraversal.CreateTraversalFunc());
|
||||
services.AddScoped<RootObjectUnpacker>();
|
||||
|
||||
services.AddTransient<TraversalContextUnpacker>();
|
||||
services.AddTransient<AccountManager>();
|
||||
|
||||
// send
|
||||
services.AddTransient<IRootObjectBuilder<SpeckleCollectionWrapperGoo>, GrasshopperRootObjectBuilder>();
|
||||
services.AddTransient<SendOperation<SpeckleCollectionWrapperGoo>>();
|
||||
services.AddSingleton<IThreadContext>(new DefaultThreadContext());
|
||||
|
||||
Container = services.BuildServiceProvider();
|
||||
return GH_LoadingInstruction.Proceed;
|
||||
}
|
||||
catch (Exception e) when (!e.IsFatal())
|
||||
{
|
||||
// TODO: Top level exception handling here
|
||||
return GH_LoadingInstruction.Abort;
|
||||
}
|
||||
}
|
||||
|
||||
private HostAppVersion GetVersion()
|
||||
{
|
||||
#if RHINO7
|
||||
return HostAppVersion.v7;
|
||||
#elif RHINO8
|
||||
return HostAppVersion.v8;
|
||||
#else
|
||||
throw new NotImplementedException();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<!-- Select the framework(s) you wish to target.
|
||||
Rhino 6: net45
|
||||
Rhino 7: net48
|
||||
Rhino 8 Windows: net48, net7.0, net7.0-windows, net7.0-windows10.0.22000.0, etc
|
||||
Rhino 8 Mac: net7.0, net7.0-macos, net7.0-macos12.0, etc
|
||||
-->
|
||||
<TargetFramework>net48</TargetFramework>
|
||||
<Configurations>Debug;Release;Local</Configurations>
|
||||
<TargetExt>.gha</TargetExt>
|
||||
<NoWarn>$(NoWarn);NU1701;NETSDK1086</NoWarn>
|
||||
<EnableWindowsTargeting>true</EnableWindowsTargeting>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<DefineConstants>$(DefineConstants);GRASSHOPPER;RHINO8;RHINO7_OR_GREATER;RHINO8_OR_GREATER</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<Title>Speckle.Connectors.Grasshopper8</Title>
|
||||
<Description>Description of Speckle.Connectors.Grasshopper8</Description>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="GrasshopperAsyncComponent" />
|
||||
<PackageReference Include="RhinoCommon" IncludeAssets="compile; build" PrivateAssets="all" />
|
||||
<PackageReference Include="Grasshopper" IncludeAssets="compile; build" PrivateAssets="all" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\Converters\Rhino\Speckle.Converters.Rhino8\Speckle.Converters.Rhino8.csproj" />
|
||||
<ProjectReference Include="..\..\..\Sdk\Speckle.Connectors.Common\Speckle.Connectors.Common.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
using Grasshopper.Kernel;
|
||||
|
||||
namespace Speckle.Connectors.Grasshopper8;
|
||||
|
||||
public class Speckle_Connectors_Grasshopper8Info : GH_AssemblyInfo
|
||||
{
|
||||
public override string Name => "Speckle.Connector.Grasshopper8";
|
||||
|
||||
// Return a 24x24 pixel bitmap to represent this GHA library.
|
||||
// public override Bitmap Icon => null;
|
||||
|
||||
// Return a short string describing the purpose of this GHA library.
|
||||
public override string Description => "x";
|
||||
|
||||
public override Guid Id => new Guid("d711dd2a-9c17-483c-a92d-45c1fc736c46");
|
||||
|
||||
// Return a string identifying you or your company.
|
||||
public override string AuthorName => "Speckle";
|
||||
|
||||
// Return a string representing your preferred contact details.
|
||||
public override string AuthorContact => "info@speckle.systems";
|
||||
|
||||
// Return a string representing the version. This returns the same version as the assembly.
|
||||
public override string AssemblyVersion => GetType().Assembly.GetName().Version.ToString();
|
||||
}
|
||||
@@ -0,0 +1,367 @@
|
||||
{
|
||||
"version": 2,
|
||||
"dependencies": {
|
||||
".NETFramework,Version=v4.8": {
|
||||
"Grasshopper": {
|
||||
"type": "Direct",
|
||||
"requested": "[8.9.24194.18121, )",
|
||||
"resolved": "8.9.24194.18121",
|
||||
"contentHash": "ZQ7vT1urn9jG2KLMdT/aVhCsijN349lj2Lrg7+Cd5A84KOW+RIErG6IqH+133hc9HT9D10+7oi/XnIlgYZRzqQ==",
|
||||
"dependencies": {
|
||||
"RhinoCommon": "[8.9.24194.18121]"
|
||||
}
|
||||
},
|
||||
"GrasshopperAsyncComponent": {
|
||||
"type": "Direct",
|
||||
"requested": "[1.2.3, )",
|
||||
"resolved": "1.2.3",
|
||||
"contentHash": "KdCmyZ7Su8T3wb5t5BEbSg2inz+aJfGFHpDysColTdeyYX9S6MRJK69UV4kYYHE+ro1FKPADOwoSE6eLKq/yDA=="
|
||||
},
|
||||
"Microsoft.NETFramework.ReferenceAssemblies": {
|
||||
"type": "Direct",
|
||||
"requested": "[1.0.3, )",
|
||||
"resolved": "1.0.3",
|
||||
"contentHash": "vUc9Npcs14QsyOD01tnv/m8sQUnGTGOw1BCmKcv77LBJY7OxhJ+zJF7UD/sCL3lYNFuqmQEVlkfS4Quif6FyYg==",
|
||||
"dependencies": {
|
||||
"Microsoft.NETFramework.ReferenceAssemblies.net48": "1.0.3"
|
||||
}
|
||||
},
|
||||
"Microsoft.SourceLink.GitHub": {
|
||||
"type": "Direct",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "8.0.0",
|
||||
"contentHash": "G5q7OqtwIyGTkeIOAc3u2ZuV/kicQaec5EaRnc0pIeSnh9LUjj+PYQrJYBURvDt7twGl2PKA7nSN0kz1Zw5bnQ==",
|
||||
"dependencies": {
|
||||
"Microsoft.Build.Tasks.Git": "8.0.0",
|
||||
"Microsoft.SourceLink.Common": "8.0.0"
|
||||
}
|
||||
},
|
||||
"PolySharp": {
|
||||
"type": "Direct",
|
||||
"requested": "[1.14.1, )",
|
||||
"resolved": "1.14.1",
|
||||
"contentHash": "mOOmFYwad3MIOL14VCjj02LljyF1GNw1wP0YVlxtcPvqdxjGGMNdNJJxHptlry3MOd8b40Flm8RPOM8JOlN2sQ=="
|
||||
},
|
||||
"RhinoCommon": {
|
||||
"type": "Direct",
|
||||
"requested": "[8.9.24194.18121, )",
|
||||
"resolved": "8.9.24194.18121",
|
||||
"contentHash": "XRMnm38sBFeMT5AAtRTJdSaql/YNtT02AGi8TEVP1VZ4fkm8VJ1q2nNioWN3tW/+H8Tdi4nV+DuhB/5uE41MCg=="
|
||||
},
|
||||
"Speckle.InterfaceGenerator": {
|
||||
"type": "Direct",
|
||||
"requested": "[0.9.6, )",
|
||||
"resolved": "0.9.6",
|
||||
"contentHash": "HKH7tYrYYlCK1ct483hgxERAdVdMtl7gUKW9ijWXxA1UsYR4Z+TrRHYmzZ9qmpu1NnTycSrp005NYM78GDKV1w=="
|
||||
},
|
||||
"GraphQL.Client": {
|
||||
"type": "Transitive",
|
||||
"resolved": "6.0.0",
|
||||
"contentHash": "8yPNBbuVBpTptivyAlak4GZvbwbUcjeQTL4vN1HKHRuOykZ4r7l5fcLS6vpyPyLn0x8FsL31xbOIKyxbmR9rbA==",
|
||||
"dependencies": {
|
||||
"GraphQL.Client.Abstractions": "6.0.0",
|
||||
"GraphQL.Client.Abstractions.Websocket": "6.0.0",
|
||||
"System.Net.WebSockets.Client.Managed": "1.0.22",
|
||||
"System.Reactive": "5.0.0"
|
||||
}
|
||||
},
|
||||
"GraphQL.Client.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "6.0.0",
|
||||
"contentHash": "h7uzWFORHZ+CCjwr/ThAyXMr0DPpzEANDa4Uo54wqCQ+j7qUKwqYTgOrb1W40sqbvNaZm9v/X7It31SUw0maHA==",
|
||||
"dependencies": {
|
||||
"GraphQL.Primitives": "6.0.0"
|
||||
}
|
||||
},
|
||||
"GraphQL.Client.Abstractions.Websocket": {
|
||||
"type": "Transitive",
|
||||
"resolved": "6.0.0",
|
||||
"contentHash": "Nr9bPf8gIOvLuXpqEpqr9z9jslYFJOvd0feHth3/kPqeR3uMbjF5pjiwh4jxyMcxHdr8Pb6QiXkV3hsSyt0v7A==",
|
||||
"dependencies": {
|
||||
"GraphQL.Client.Abstractions": "6.0.0"
|
||||
}
|
||||
},
|
||||
"GraphQL.Primitives": {
|
||||
"type": "Transitive",
|
||||
"resolved": "6.0.0",
|
||||
"contentHash": "yg72rrYDapfsIUrul7aF6wwNnTJBOFvuA9VdDTQpPa8AlAriHbufeXYLBcodKjfUdkCnaiggX1U/nEP08Zb5GA=="
|
||||
},
|
||||
"Microsoft.Bcl.AsyncInterfaces": {
|
||||
"type": "Transitive",
|
||||
"resolved": "5.0.0",
|
||||
"contentHash": "W8DPQjkMScOMTtJbPwmPyj9c3zYSFGawDW3jwlBOOsnY+EzZFLgNQ/UMkK35JmkNOVPdCyPr2Tw7Vv9N+KA3ZQ==",
|
||||
"dependencies": {
|
||||
"System.Threading.Tasks.Extensions": "4.5.4"
|
||||
}
|
||||
},
|
||||
"Microsoft.Build.Tasks.Git": {
|
||||
"type": "Transitive",
|
||||
"resolved": "8.0.0",
|
||||
"contentHash": "bZKfSIKJRXLTuSzLudMFte/8CempWjVamNUR5eHJizsy+iuOuO/k2gnh7W0dHJmYY0tBf+gUErfluCv5mySAOQ=="
|
||||
},
|
||||
"Microsoft.CSharp": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.7.0",
|
||||
"contentHash": "pTj+D3uJWyN3My70i2Hqo+OXixq3Os2D1nJ2x92FFo6sk8fYS1m1WLNTs0Dc1uPaViH0YvEEwvzddQ7y4rhXmA=="
|
||||
},
|
||||
"Microsoft.Data.Sqlite": {
|
||||
"type": "Transitive",
|
||||
"resolved": "7.0.5",
|
||||
"contentHash": "KGxbPeWsQMnmQy43DSBxAFtHz3l2JX8EWBSGUCvT3CuZ8KsuzbkqMIJMDOxWtG8eZSoCDI04aiVQjWuuV8HmSw==",
|
||||
"dependencies": {
|
||||
"Microsoft.Data.Sqlite.Core": "7.0.5",
|
||||
"SQLitePCLRaw.bundle_e_sqlite3": "2.1.4"
|
||||
}
|
||||
},
|
||||
"Microsoft.Data.Sqlite.Core": {
|
||||
"type": "Transitive",
|
||||
"resolved": "7.0.5",
|
||||
"contentHash": "FTerRmQPqHrCrnoUzhBu+E+1DNGwyrAMLqHkAqOOOu5pGfyMOj8qQUBxI/gDtWtG11p49UxSfWmBzRNlwZqfUg==",
|
||||
"dependencies": {
|
||||
"SQLitePCLRaw.core": "2.1.4"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Configuration": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "nOP8R1mVb/6mZtm2qgAJXn/LFm/2kMjHDAg/QJLFG6CuWYJtaD3p1BwQhufBVvRzL9ceJ/xF0SQ0qsI2GkDQAA==",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Configuration.Abstractions": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Configuration.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "65MrmXCziWaQFrI0UHkQbesrX5wTwf9XPjY5yFm/VkgJKFJ5gqvXRoXjIZcf2wLi5ZlwGz/oMYfyURVCWbM5iw==",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Primitives": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Configuration.Binder": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "vJ9xvOZCnUAIHcGC3SU35r3HKmHTVIeHzo6u/qzlHAqD8m6xv92MLin4oJntTvkpKxVX3vI1GFFkIQtU3AdlsQ==",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Configuration": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Options": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "UpZLNLBpIZ0GTebShui7xXYh6DmBHjWM8NxGxZbdQh/bPZ5e6YswqI+bru6BnEL5eWiOdodsXtEz3FROcgi/qg==",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0",
|
||||
"Microsoft.Extensions.Primitives": "2.2.0",
|
||||
"System.ComponentModel.Annotations": "4.5.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Primitives": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "azyQtqbm4fSaDzZHD/J+V6oWMFaf2tWP4WEGIYePLCMw3+b2RQdj9ybgbQyjCshcitQKQ4lEDOZjmSlTTrHxUg==",
|
||||
"dependencies": {
|
||||
"System.Memory": "4.5.1",
|
||||
"System.Runtime.CompilerServices.Unsafe": "4.5.1"
|
||||
}
|
||||
},
|
||||
"Microsoft.NETFramework.ReferenceAssemblies.net48": {
|
||||
"type": "Transitive",
|
||||
"resolved": "1.0.3",
|
||||
"contentHash": "zMk4D+9zyiEWByyQ7oPImPN/Jhpj166Ky0Nlla4eXlNL8hI/BtSJsgR8Inldd4NNpIAH3oh8yym0W2DrhXdSLQ=="
|
||||
},
|
||||
"Microsoft.SourceLink.Common": {
|
||||
"type": "Transitive",
|
||||
"resolved": "8.0.0",
|
||||
"contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw=="
|
||||
},
|
||||
"Speckle.Newtonsoft.Json": {
|
||||
"type": "Transitive",
|
||||
"resolved": "13.0.2",
|
||||
"contentHash": "g1BejUZwax5PRfL6xHgLEK23sqHWOgOj9hE7RvfRRlN00AGt8GnPYt8HedSK7UB3HiRW8zCA9Pn0iiYxCK24BA=="
|
||||
},
|
||||
"SQLitePCLRaw.bundle_e_sqlite3": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.1.4",
|
||||
"contentHash": "EWI1olKDjFEBMJu0+3wuxwziIAdWDVMYLhuZ3Qs84rrz+DHwD00RzWPZCa+bLnHCf3oJwuFZIRsHT5p236QXww==",
|
||||
"dependencies": {
|
||||
"SQLitePCLRaw.lib.e_sqlite3": "2.1.4",
|
||||
"SQLitePCLRaw.provider.dynamic_cdecl": "2.1.4"
|
||||
}
|
||||
},
|
||||
"SQLitePCLRaw.core": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.1.4",
|
||||
"contentHash": "inBjvSHo9UDKneGNzfUfDjK08JzlcIhn1+SP5Y3m6cgXpCxXKCJDy6Mka7LpgSV+UZmKSnC8rTwB0SQ0xKu5pA==",
|
||||
"dependencies": {
|
||||
"System.Memory": "4.5.3"
|
||||
}
|
||||
},
|
||||
"SQLitePCLRaw.lib.e_sqlite3": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.1.4",
|
||||
"contentHash": "2C9Q9eX7CPLveJA0rIhf9RXAvu+7nWZu1A2MdG6SD/NOu26TakGgL1nsbc0JAspGijFOo3HoN79xrx8a368fBg=="
|
||||
},
|
||||
"SQLitePCLRaw.provider.dynamic_cdecl": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.1.4",
|
||||
"contentHash": "ZsaKKhgYF9B1fvcnOGKl3EycNAwd9CRWX7v0rEfuPWhQQ5Jjpvf2VEHahiLIGHio3hxi3EIKFJw9KvyowWOUAw==",
|
||||
"dependencies": {
|
||||
"SQLitePCLRaw.core": "2.1.4"
|
||||
}
|
||||
},
|
||||
"System.Buffers": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.4.0",
|
||||
"contentHash": "AwarXzzoDwX6BgrhjoJsk6tUezZEozOT5Y9QKF94Gl4JK91I4PIIBkBco9068Y9/Dra8Dkbie99kXB8+1BaYKw=="
|
||||
},
|
||||
"System.ComponentModel.Annotations": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.5.0",
|
||||
"contentHash": "UxYQ3FGUOtzJ7LfSdnYSFd7+oEv6M8NgUatatIN2HxNtDdlcvFAf+VIq4Of9cDMJEJC0aSRv/x898RYhB4Yppg=="
|
||||
},
|
||||
"System.Memory": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.5.3",
|
||||
"contentHash": "3oDzvc/zzetpTKWMShs1AADwZjQ/36HnsufHRPcOjyRAAMLDlu2iD33MBI2opxnezcVUtXyqDXXjoFMOU9c7SA==",
|
||||
"dependencies": {
|
||||
"System.Buffers": "4.4.0",
|
||||
"System.Numerics.Vectors": "4.4.0",
|
||||
"System.Runtime.CompilerServices.Unsafe": "4.5.2"
|
||||
}
|
||||
},
|
||||
"System.Net.WebSockets.Client.Managed": {
|
||||
"type": "Transitive",
|
||||
"resolved": "1.0.22",
|
||||
"contentHash": "WqEOxPlXjuZrIjUtXNE9NxEfU/n5E35iV2PtoZdJSUC4tlrqwHnTee+wvMIM4OUaJWmwrymeqcgYrE0IkGAgLA==",
|
||||
"dependencies": {
|
||||
"System.Buffers": "4.4.0",
|
||||
"System.Numerics.Vectors": "4.4.0"
|
||||
}
|
||||
},
|
||||
"System.Numerics.Vectors": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.4.0",
|
||||
"contentHash": "UiLzLW+Lw6HLed1Hcg+8jSRttrbuXv7DANVj0DkL9g6EnnzbL75EB7EWsw5uRbhxd/4YdG8li5XizGWepmG3PQ=="
|
||||
},
|
||||
"System.Reactive": {
|
||||
"type": "Transitive",
|
||||
"resolved": "5.0.0",
|
||||
"contentHash": "erBZjkQHWL9jpasCE/0qKAryzVBJFxGHVBAvgRN1bzM0q2s1S4oYREEEL0Vb+1kA/6BKb5FjUZMp5VXmy+gzkQ==",
|
||||
"dependencies": {
|
||||
"System.Threading.Tasks.Extensions": "4.5.4"
|
||||
}
|
||||
},
|
||||
"System.Runtime.CompilerServices.Unsafe": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.5.3",
|
||||
"contentHash": "3TIsJhD1EiiT0w2CcDMN/iSSwnNnsrnbzeVHSKkaEgV85txMprmuO+Yq2AdSbeVGcg28pdNDTPK87tJhX7VFHw=="
|
||||
},
|
||||
"System.Threading.Tasks.Extensions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.5.4",
|
||||
"contentHash": "zteT+G8xuGu6mS+mzDzYXbzS7rd3K6Fjb9RiZlYlJPam2/hU7JCBZBVEcywNuR+oZ1ncTvc/cq0faRr3P01OVg==",
|
||||
"dependencies": {
|
||||
"System.Runtime.CompilerServices.Unsafe": "4.5.3"
|
||||
}
|
||||
},
|
||||
"speckle.connectors.common": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.DependencyInjection": "[2.2.0, )",
|
||||
"Speckle.Connectors.Logging": "[1.0.0, )",
|
||||
"Speckle.Objects": "[3.1.7, )",
|
||||
"Speckle.Sdk": "[3.1.7, )",
|
||||
"Speckle.Sdk.Dependencies": "[3.1.7, )"
|
||||
}
|
||||
},
|
||||
"speckle.connectors.logging": {
|
||||
"type": "Project"
|
||||
},
|
||||
"speckle.converters.common": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
|
||||
"Speckle.Objects": "[3.1.7, )"
|
||||
}
|
||||
},
|
||||
"speckle.converters.rhino8": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"RhinoCommon": "[8.9.24194.18121, )",
|
||||
"Speckle.Converters.Common": "[1.0.0, )"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[2.2.0, )",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "MZtBIwfDFork5vfjpJdG5g8wuJFt7d/y3LOSVVtDK/76wlbtz6cjltfKHqLx2TKVqTj5/c41t77m1+h20zqtPA==",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Logging": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[2.2.0, )",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "Nxqhadc9FCmFHzU+fz3oc8sFlE6IadViYg8dfUdGzJZ2JUxnCsRghBhhOWdM4B2zSZqEc+0BjliBh/oNdRZuig==",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Configuration.Binder": "2.2.0",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0",
|
||||
"Microsoft.Extensions.Logging.Abstractions": "2.2.0",
|
||||
"Microsoft.Extensions.Options": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Logging.Abstractions": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[2.2.0, )",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "B2WqEox8o+4KUOpL7rZPyh6qYjik8tHi2tN8Z9jZkHzED8ElYgZa/h6K+xliB435SqUcWT290Fr2aa8BtZjn8A=="
|
||||
},
|
||||
"Speckle.DoubleNumerics": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[4.1.0, )",
|
||||
"resolved": "4.1.0",
|
||||
"contentHash": "20DtS+FsDRsOD9+AU3TwNFZ0qrKo5f6f7B5ZR9wStsIHHHC9k7DpjbCvuNtmnSjx54MD+TJC7wV2f5iyGVPj1A=="
|
||||
},
|
||||
"Speckle.Objects": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[3.1.7, )",
|
||||
"resolved": "3.1.7",
|
||||
"contentHash": "Htg6IeMLTTf8fTaOKEKMPZzrseu4NAtVpiZwVtLhg7ZzdndW8WlsvEyFRShK1o3hxlPsQJOA5qfsTvf5fcz/pQ==",
|
||||
"dependencies": {
|
||||
"Speckle.Sdk": "3.1.7"
|
||||
}
|
||||
},
|
||||
"Speckle.Sdk": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[3.1.7, )",
|
||||
"resolved": "3.1.7",
|
||||
"contentHash": "oi6fz5fSsWZ+VQiZukpom/fKHRH++Vlyf8a6rlkYQPj6NAqTIV3Rgthalt7Y7wWxGNRIP4KMdGTXvrN7wqCcjA==",
|
||||
"dependencies": {
|
||||
"GraphQL.Client": "6.0.0",
|
||||
"Microsoft.Bcl.AsyncInterfaces": "5.0.0",
|
||||
"Microsoft.CSharp": "4.7.0",
|
||||
"Microsoft.Data.Sqlite": "7.0.5",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0",
|
||||
"Microsoft.Extensions.Logging": "2.2.0",
|
||||
"Speckle.DoubleNumerics": "4.1.0",
|
||||
"Speckle.Newtonsoft.Json": "13.0.2",
|
||||
"Speckle.Sdk.Dependencies": "3.1.7"
|
||||
}
|
||||
},
|
||||
"Speckle.Sdk.Dependencies": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[3.1.7, )",
|
||||
"resolved": "3.1.7",
|
||||
"contentHash": "T7FgbPXh9zI+VkC7f9I5qchtktEhslIOo2xeCm4VKRhImrR7naTmZInQ5MXIZvRfawZlPEg6u0tWzCV1q7ov9g=="
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -139,11 +139,6 @@
|
||||
"Microsoft.Extensions.Configuration": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Options": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
@@ -315,6 +310,12 @@
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Logging": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[2.2.0, )",
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
<ProjectReference Include="..\..\..\Converters\Rhino\Speckle.Converters.Rhino8\Speckle.Converters.Rhino8.csproj" />
|
||||
<ProjectReference Include="..\..\..\Sdk\Speckle.Connectors.Common\Speckle.Connectors.Common.csproj" />
|
||||
<ProjectReference Include="..\..\..\DUI3\Speckle.Connectors.DUI.WebView\Speckle.Connectors.DUI.WebView.csproj" />
|
||||
<ProjectReference Include="..\Speckle.Connectors.Grasshopper8\Speckle.Connectors.Grasshopper8.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -139,11 +139,6 @@
|
||||
"Microsoft.Extensions.Configuration": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Options": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
@@ -289,6 +284,14 @@
|
||||
"Speckle.Connectors.DUI": "[1.0.0, )"
|
||||
}
|
||||
},
|
||||
"speckle.connectors.grasshopper8": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"GrasshopperAsyncComponent": "[1.2.3, )",
|
||||
"Speckle.Connectors.Common": "[1.0.0, )",
|
||||
"Speckle.Converters.Rhino8": "[1.0.0, )"
|
||||
}
|
||||
},
|
||||
"speckle.connectors.logging": {
|
||||
"type": "Project"
|
||||
},
|
||||
@@ -306,6 +309,12 @@
|
||||
"Speckle.Converters.Common": "[1.0.0, )"
|
||||
}
|
||||
},
|
||||
"GrasshopperAsyncComponent": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[1.2.3, )",
|
||||
"resolved": "1.2.3",
|
||||
"contentHash": "KdCmyZ7Su8T3wb5t5BEbSg2inz+aJfGFHpDysColTdeyYX9S6MRJK69UV4kYYHE+ro1FKPADOwoSE6eLKq/yDA=="
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[2.2.0, )",
|
||||
@@ -315,6 +324,12 @@
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Logging": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[2.2.0, )",
|
||||
|
||||
@@ -169,11 +169,6 @@
|
||||
"Microsoft.Extensions.Configuration": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Options": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
@@ -380,6 +375,12 @@
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Logging": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[2.2.0, )",
|
||||
|
||||
@@ -183,11 +183,6 @@
|
||||
"Microsoft.Extensions.Configuration": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Options": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
@@ -461,6 +456,12 @@
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Logging": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[2.2.0, )",
|
||||
|
||||
@@ -126,11 +126,6 @@
|
||||
"Microsoft.Extensions.Configuration": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Options": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
@@ -235,6 +230,12 @@
|
||||
"resolved": "1.1.15",
|
||||
"contentHash": "KuA7N3Nv/lIeawJdQBQJR6oqWD9KETHLbWzBqapwFs+Tby+R5I4crkKujKMm5bXcSuFZ8LNtflFQVadsWCbBjg=="
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Logging": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[2.2.0, )",
|
||||
|
||||
@@ -130,11 +130,6 @@
|
||||
"Microsoft.Extensions.Configuration": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Options": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
@@ -261,6 +256,12 @@
|
||||
"Speckle.Objects": "[3.1.7, )"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Logging": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[2.2.0, )",
|
||||
|
||||
@@ -130,11 +130,6 @@
|
||||
"Microsoft.Extensions.Configuration": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Options": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
@@ -261,6 +256,12 @@
|
||||
"Speckle.Objects": "[3.1.7, )"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Logging": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[2.2.0, )",
|
||||
|
||||
@@ -130,11 +130,6 @@
|
||||
"Microsoft.Extensions.Configuration": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Options": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
@@ -299,6 +294,12 @@
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Logging": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[2.2.0, )",
|
||||
|
||||
@@ -121,11 +121,6 @@
|
||||
"Microsoft.Extensions.Configuration": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Options": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
@@ -255,6 +250,12 @@
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Logging": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[2.2.0, )",
|
||||
|
||||
@@ -130,11 +130,6 @@
|
||||
"Microsoft.Extensions.Configuration": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Options": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
@@ -261,6 +256,12 @@
|
||||
"Speckle.Objects": "[3.1.7, )"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Logging": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[2.2.0, )",
|
||||
|
||||
@@ -121,11 +121,6 @@
|
||||
"Microsoft.Extensions.Configuration": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Options": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
@@ -217,6 +212,12 @@
|
||||
"Speckle.Objects": "[3.1.7, )"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Logging": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[2.2.0, )",
|
||||
|
||||
@@ -139,11 +139,6 @@
|
||||
"Microsoft.Extensions.Configuration": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Options": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
@@ -270,6 +265,12 @@
|
||||
"Speckle.Objects": "[3.1.7, )"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Logging": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[2.2.0, )",
|
||||
|
||||
@@ -139,11 +139,6 @@
|
||||
"Microsoft.Extensions.Configuration": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Options": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
@@ -270,6 +265,12 @@
|
||||
"Speckle.Objects": "[3.1.7, )"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Logging": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[2.2.0, )",
|
||||
|
||||
@@ -139,11 +139,6 @@
|
||||
"Microsoft.Extensions.Configuration": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Options": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
@@ -270,6 +265,12 @@
|
||||
"Speckle.Objects": "[3.1.7, )"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Logging": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[2.2.0, )",
|
||||
|
||||
@@ -130,11 +130,6 @@
|
||||
"Microsoft.Extensions.Configuration": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Options": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
@@ -264,6 +259,12 @@
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Logging": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[2.2.0, )",
|
||||
|
||||
@@ -130,11 +130,6 @@
|
||||
"Microsoft.Extensions.Configuration": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Options": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
@@ -292,6 +287,12 @@
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Logging": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[2.2.0, )",
|
||||
|
||||
@@ -130,11 +130,6 @@
|
||||
"Microsoft.Extensions.Configuration": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Options": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
@@ -292,6 +287,12 @@
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Logging": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[2.2.0, )",
|
||||
|
||||
@@ -130,11 +130,6 @@
|
||||
"Microsoft.Extensions.Configuration": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Options": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
@@ -292,6 +287,12 @@
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Logging": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[2.2.0, )",
|
||||
|
||||
@@ -130,11 +130,6 @@
|
||||
"Microsoft.Extensions.Configuration": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Options": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
@@ -292,6 +287,12 @@
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Logging": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[2.2.0, )",
|
||||
|
||||
@@ -130,11 +130,6 @@
|
||||
"Microsoft.Extensions.Configuration": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Options": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
@@ -292,6 +287,12 @@
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Logging": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[2.2.0, )",
|
||||
|
||||
@@ -130,11 +130,6 @@
|
||||
"Microsoft.Extensions.Configuration": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Options": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
@@ -292,6 +287,12 @@
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Logging": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[2.2.0, )",
|
||||
|
||||
@@ -189,11 +189,6 @@
|
||||
"Microsoft.Extensions.Configuration": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Options": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
@@ -350,6 +345,12 @@
|
||||
"NUnit": "[4.1.0, )"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Logging": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[2.2.0, )",
|
||||
|
||||
@@ -130,11 +130,6 @@
|
||||
"Microsoft.Extensions.Configuration": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Options": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
@@ -261,6 +256,12 @@
|
||||
"Speckle.Objects": "[3.1.7, )"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Logging": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[2.2.0, )",
|
||||
|
||||
@@ -189,11 +189,6 @@
|
||||
"Microsoft.Extensions.Configuration": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Options": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
@@ -350,6 +345,12 @@
|
||||
"NUnit": "[4.1.0, )"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Logging": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[2.2.0, )",
|
||||
|
||||
@@ -130,11 +130,6 @@
|
||||
"Microsoft.Extensions.Configuration": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Options": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
@@ -261,6 +256,12 @@
|
||||
"Speckle.Objects": "[3.1.7, )"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Logging": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[2.2.0, )",
|
||||
|
||||
@@ -189,11 +189,6 @@
|
||||
"Microsoft.Extensions.Configuration": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Options": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
@@ -350,6 +345,12 @@
|
||||
"NUnit": "[4.1.0, )"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Logging": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[2.2.0, )",
|
||||
|
||||
@@ -130,11 +130,6 @@
|
||||
"Microsoft.Extensions.Configuration": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Options": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
@@ -261,6 +256,12 @@
|
||||
"Speckle.Objects": "[3.1.7, )"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Logging": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[2.2.0, )",
|
||||
|
||||
@@ -121,11 +121,6 @@
|
||||
"Microsoft.Extensions.Configuration": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Options": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
@@ -217,6 +212,12 @@
|
||||
"Speckle.Objects": "[3.1.7, )"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Logging": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[2.2.0, )",
|
||||
|
||||
@@ -189,11 +189,6 @@
|
||||
"Microsoft.Extensions.Configuration": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Options": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
@@ -350,6 +345,12 @@
|
||||
"NUnit": "[4.1.0, )"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Logging": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[2.2.0, )",
|
||||
|
||||
@@ -130,11 +130,6 @@
|
||||
"Microsoft.Extensions.Configuration": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Options": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
@@ -261,6 +256,12 @@
|
||||
"Speckle.Objects": "[3.1.7, )"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Logging": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[2.2.0, )",
|
||||
|
||||
@@ -130,11 +130,6 @@
|
||||
"Microsoft.Extensions.Configuration": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Options": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
@@ -261,6 +256,12 @@
|
||||
"Speckle.Objects": "[3.1.7, )"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Logging": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[2.2.0, )",
|
||||
|
||||
+1
-1
@@ -11,4 +11,4 @@
|
||||
<ItemGroup>
|
||||
<Compile Include="$(MSBuildThisFileDirectory)**\*.cs" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
using Speckle.Converters.Common;
|
||||
using Speckle.Converters.Common.Objects;
|
||||
using Speckle.Sdk.Common.Exceptions;
|
||||
using Speckle.Sdk.Models;
|
||||
|
||||
namespace Speckle.Converters.Rhino.ToSpeckle.Grasshopper;
|
||||
|
||||
[NameAndRankValue(typeof(RG.GeometryBase), NameAndRankValueAttribute.SPECKLE_DEFAULT_RANK)]
|
||||
public class GeometryBaseConverter : IToSpeckleTopLevelConverter
|
||||
{
|
||||
private readonly ITypedConverter<RG.Point, SOG.Point> _pointConverter;
|
||||
private readonly ITypedConverter<RG.ArcCurve, Base> _arcCurveConverter;
|
||||
private readonly ITypedConverter<RG.LineCurve, SOG.Line> _lineCurveConverter;
|
||||
private readonly ITypedConverter<RG.NurbsCurve, SOG.Curve> _nurbsCurveConverter;
|
||||
private readonly ITypedConverter<RG.PolyCurve, SOG.Polycurve> _polycurveConverter;
|
||||
private readonly ITypedConverter<RG.Polyline, SOG.Polyline> _polylineConverter;
|
||||
private readonly ITypedConverter<RG.Mesh, SOG.Mesh> _meshConverter;
|
||||
private readonly ITypedConverter<RG.Extrusion, SOG.ExtrusionX> _extrusionConverter;
|
||||
private readonly ITypedConverter<RG.SubD, SOG.SubDX> _subdConverter;
|
||||
private readonly ITypedConverter<RG.Brep, SOG.BrepX> _brepConverter;
|
||||
|
||||
public GeometryBaseConverter(
|
||||
ITypedConverter<RG.Point, SOG.Point> pointConverter,
|
||||
ITypedConverter<RG.ArcCurve, Base> arcCurveConverter,
|
||||
ITypedConverter<RG.LineCurve, SOG.Line> lineCurveConverter,
|
||||
ITypedConverter<RG.NurbsCurve, SOG.Curve> nurbsCurveConverter,
|
||||
ITypedConverter<RG.PolyCurve, SOG.Polycurve> polycurveConverter,
|
||||
ITypedConverter<RG.Polyline, SOG.Polyline> polylineConverter,
|
||||
ITypedConverter<RG.Mesh, SOG.Mesh> meshConverter,
|
||||
ITypedConverter<RG.Brep, SOG.BrepX> brepConverter,
|
||||
ITypedConverter<RG.Extrusion, SOG.ExtrusionX> extrusionConverter,
|
||||
ITypedConverter<RG.SubD, SOG.SubDX> subdConverter
|
||||
)
|
||||
{
|
||||
_pointConverter = pointConverter;
|
||||
_arcCurveConverter = arcCurveConverter;
|
||||
_lineCurveConverter = lineCurveConverter;
|
||||
_nurbsCurveConverter = nurbsCurveConverter;
|
||||
_polycurveConverter = polycurveConverter;
|
||||
_polylineConverter = polylineConverter;
|
||||
_meshConverter = meshConverter;
|
||||
_brepConverter = brepConverter;
|
||||
_extrusionConverter = extrusionConverter;
|
||||
_subdConverter = subdConverter;
|
||||
}
|
||||
|
||||
public Base Convert(object target)
|
||||
{
|
||||
switch (target)
|
||||
{
|
||||
case RG.Point pt:
|
||||
return _pointConverter.Convert(pt);
|
||||
case RG.ArcCurve ac:
|
||||
return _arcCurveConverter.Convert(ac);
|
||||
case RG.LineCurve ln:
|
||||
return _lineCurveConverter.Convert(ln);
|
||||
case RG.NurbsCurve nurbsCurve:
|
||||
return _nurbsCurveConverter.Convert(nurbsCurve);
|
||||
case RG.PolyCurve polyCurve:
|
||||
return _polycurveConverter.Convert(polyCurve);
|
||||
case RG.Polyline polyline:
|
||||
return _polylineConverter.Convert(polyline);
|
||||
case RG.PolylineCurve polylineCurve:
|
||||
return _polylineConverter.Convert(polylineCurve.ToPolyline());
|
||||
case RG.Mesh mesh:
|
||||
return _meshConverter.Convert(mesh);
|
||||
case RG.Brep brep:
|
||||
return _brepConverter.Convert(brep);
|
||||
case RG.Extrusion ext:
|
||||
return _extrusionConverter.Convert(ext);
|
||||
case RG.SubD subD:
|
||||
return _subdConverter.Convert(subD);
|
||||
}
|
||||
|
||||
throw new ConversionException($"Failed to find a conversion for {target.GetType()}");
|
||||
}
|
||||
}
|
||||
+3
@@ -60,6 +60,9 @@ public static class DisplayMeshExtractor
|
||||
#pragma warning restore CA2000
|
||||
renderMeshes = [subdMesh];
|
||||
break;
|
||||
case RG.Extrusion extrusion:
|
||||
renderMeshes = RG.Mesh.CreateFromBrep(extrusion.ToBrep(), new(0.05, 0.05));
|
||||
break;
|
||||
default:
|
||||
throw new ConversionException($"Unsupported object for display mesh generation {geometry.GetType().FullName}");
|
||||
}
|
||||
|
||||
+15
-190
@@ -1,218 +1,43 @@
|
||||
using Speckle.Converters.Common;
|
||||
using Speckle.Converters.Common;
|
||||
using Speckle.Converters.Common.Objects;
|
||||
using Speckle.Objects;
|
||||
using Speckle.Sdk;
|
||||
using Speckle.Sdk.Common;
|
||||
using Speckle.Converters.Rhino.ToSpeckle.Encoding;
|
||||
using Speckle.Converters.Rhino.ToSpeckle.Meshing;
|
||||
|
||||
namespace Speckle.Converters.Rhino.ToSpeckle.Raw;
|
||||
|
||||
public class BrepToSpeckleConverter : ITypedConverter<RG.Brep, SOG.Brep>
|
||||
public class BrepToSpeckleConverter : ITypedConverter<RG.Brep, SOG.BrepX>
|
||||
{
|
||||
private readonly ITypedConverter<RG.Point3d, SOG.Point> _pointConverter;
|
||||
private readonly ITypedConverter<RG.Curve, ICurve> _curveConverter;
|
||||
private readonly ITypedConverter<RG.NurbsSurface, SOG.Surface> _surfaceConverter;
|
||||
private readonly ITypedConverter<RG.Mesh, SOG.Mesh> _meshConverter;
|
||||
private readonly ITypedConverter<RG.Box, SOG.Box> _boxConverter;
|
||||
private readonly ITypedConverter<RG.Interval, SOP.Interval> _intervalConverter;
|
||||
private readonly IConverterSettingsStore<RhinoConversionSettings> _settingsStore;
|
||||
|
||||
public BrepToSpeckleConverter(
|
||||
ITypedConverter<RG.Point3d, SOG.Point> pointConverter,
|
||||
ITypedConverter<RG.Curve, ICurve> curveConverter,
|
||||
ITypedConverter<RG.NurbsSurface, SOG.Surface> surfaceConverter,
|
||||
ITypedConverter<RG.Mesh, SOG.Mesh> meshConverter,
|
||||
ITypedConverter<RG.Box, SOG.Box> boxConverter,
|
||||
ITypedConverter<RG.Interval, SOP.Interval> intervalConverter,
|
||||
IConverterSettingsStore<RhinoConversionSettings> settingsStore
|
||||
)
|
||||
{
|
||||
_pointConverter = pointConverter;
|
||||
_curveConverter = curveConverter;
|
||||
_surfaceConverter = surfaceConverter;
|
||||
_meshConverter = meshConverter;
|
||||
_boxConverter = boxConverter;
|
||||
_intervalConverter = intervalConverter;
|
||||
_settingsStore = settingsStore;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a Brep object to a Speckle Brep object.
|
||||
/// Converts a Brep geometry to a Speckle BrepX object.
|
||||
/// </summary>
|
||||
/// <param name="target">The Brep object to convert.</param>
|
||||
/// <returns>The converted Speckle Brep object.</returns>
|
||||
public SOG.Brep Convert(RG.Brep target)
|
||||
/// <param name="target">The Brep to convert.</param>
|
||||
/// <returns>The converted Speckle BrepX object.</returns>
|
||||
public SOG.BrepX Convert(RG.Brep target)
|
||||
{
|
||||
var tol = _settingsStore.Current.Document.ModelAbsoluteTolerance;
|
||||
target.Repair(tol); // NOTE: for objects far-ish (not that far imho) from origin, this call nukes performance and takes ages.
|
||||
var brepEncoding = RawEncodingCreator.Encode(target, _settingsStore.Current.Document);
|
||||
|
||||
// POC: CNX-9276 This should come as part of the user settings in the context object.
|
||||
// if (PreprocessGeometry)
|
||||
// {
|
||||
// brep = BrepEncoder.ToRawBrep(brep, 1.0, Doc.ModelAngleToleranceRadians, Doc.ModelRelativeTolerance);
|
||||
// }
|
||||
var displayMesh = DisplayMeshExtractor.GetGeometryDisplayMesh(target);
|
||||
List<SOG.Mesh> displayValue = displayMesh is null ? new() : new() { _meshConverter.Convert(displayMesh) };
|
||||
|
||||
// get display mesh and attach render material to it if it exists
|
||||
var displayMesh = GetBrepDisplayMesh(target);
|
||||
var displayValue = new List<SOG.Mesh>();
|
||||
if (displayMesh != null)
|
||||
var bx = new SOG.BrepX()
|
||||
{
|
||||
displayValue.Add(_meshConverter.Convert(displayMesh));
|
||||
}
|
||||
|
||||
// POC: CNX-9277 Swap input material for something coming from the context.
|
||||
// if (displayValue != null && mat != null)
|
||||
// {
|
||||
// displayValue["renderMaterial"] = mat;
|
||||
// }
|
||||
|
||||
|
||||
// Vertices, uv curves, 3d curves and surfaces
|
||||
List<SOG.Point> vertices = new(target.Vertices.Count);
|
||||
vertices.AddRange(target.Vertices.Select(v => _pointConverter.Convert(v.Location)));
|
||||
|
||||
List<ICurve> curves3d = new(target.Curves3D.Count);
|
||||
curves3d.AddRange(target.Curves3D.Select(curve3d => _curveConverter.Convert(curve3d)));
|
||||
|
||||
List<SOG.Surface> surfaces = new(target.Curves3D.Count);
|
||||
surfaces.AddRange(target.Surfaces.Select(srf => _surfaceConverter.Convert(srf.ToNurbsSurface())));
|
||||
|
||||
List<ICurve> curves2d = new(target.Curves2D.Count);
|
||||
using (_settingsStore.Push(x => x with { SpeckleUnits = Units.None }))
|
||||
{
|
||||
// Curves2D are unitless, so we convert them within a new pushed context with None units.
|
||||
curves2d.AddRange(target.Curves2D.Select(curve2d => _curveConverter.Convert(curve2d)));
|
||||
}
|
||||
|
||||
var speckleBrep = new SOG.Brep
|
||||
{
|
||||
Vertices = vertices,
|
||||
Curve3D = curves3d,
|
||||
Curve2D = curves2d,
|
||||
Surfaces = surfaces,
|
||||
displayValue = displayValue,
|
||||
IsClosed = target.IsSolid,
|
||||
Orientation = (SOG.BrepOrientation)target.SolidOrientation,
|
||||
volume = target.IsSolid ? target.GetVolume() : 0,
|
||||
area = target.GetArea(),
|
||||
bbox = _boxConverter.Convert(new RG.Box(target.GetBoundingBox(false))),
|
||||
units = _settingsStore.Current.SpeckleUnits,
|
||||
Edges = new(target.Edges.Count),
|
||||
Loops = new(target.Loops.Count),
|
||||
Trims = new(target.Trims.Count),
|
||||
Faces = new(target.Faces.Count)
|
||||
encodedValue = brepEncoding,
|
||||
units = _settingsStore.Current.SpeckleUnits
|
||||
};
|
||||
|
||||
// Brep non-geometry types
|
||||
ConvertBrepFaces(target, speckleBrep);
|
||||
ConvertBrepEdges(target, speckleBrep);
|
||||
ConvertBrepLoops(target, speckleBrep);
|
||||
ConvertBrepTrims(target, speckleBrep);
|
||||
|
||||
return speckleBrep;
|
||||
}
|
||||
|
||||
private static void ConvertBrepFaces(RG.Brep brep, SOG.Brep speckleParent)
|
||||
{
|
||||
foreach (var f in brep.Faces)
|
||||
{
|
||||
speckleParent.Faces.Add(
|
||||
new SOG.BrepFace
|
||||
{
|
||||
Brep = speckleParent,
|
||||
SurfaceIndex = f.SurfaceIndex,
|
||||
LoopIndices = f.Loops.Select(l => l.LoopIndex).ToList(),
|
||||
OuterLoopIndex = f.OuterLoop.LoopIndex,
|
||||
OrientationReversed = f.OrientationIsReversed,
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private void ConvertBrepEdges(RG.Brep brep, SOG.Brep speckleParent)
|
||||
{
|
||||
foreach (var edge in brep.Edges)
|
||||
{
|
||||
speckleParent.Edges.Add(
|
||||
new SOG.BrepEdge
|
||||
{
|
||||
Brep = speckleParent,
|
||||
Curve3dIndex = edge.EdgeCurveIndex,
|
||||
TrimIndices = edge.TrimIndices(),
|
||||
StartIndex = edge.StartVertex.VertexIndex,
|
||||
EndIndex = edge.EndVertex.VertexIndex,
|
||||
ProxyCurveIsReversed = edge.ProxyCurveIsReversed,
|
||||
Domain = _intervalConverter.Convert(edge.Domain),
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private void ConvertBrepTrims(RG.Brep brep, SOG.Brep speckleParent)
|
||||
{
|
||||
foreach (var trim in brep.Trims)
|
||||
{
|
||||
speckleParent.Trims.Add(
|
||||
new SOG.BrepTrim
|
||||
{
|
||||
Brep = speckleParent,
|
||||
EdgeIndex = trim.Edge?.EdgeIndex ?? -1,
|
||||
FaceIndex = trim.Face.FaceIndex,
|
||||
LoopIndex = trim.Loop.LoopIndex,
|
||||
CurveIndex = trim.TrimCurveIndex,
|
||||
IsoStatus = (int)trim.IsoStatus,
|
||||
TrimType = (SOG.BrepTrimType)trim.TrimType,
|
||||
IsReversed = trim.IsReversed(),
|
||||
StartIndex = trim.StartVertex.VertexIndex,
|
||||
EndIndex = trim.EndVertex.VertexIndex,
|
||||
Domain = _intervalConverter.Convert(trim.Domain),
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private void ConvertBrepLoops(RG.Brep brep, SOG.Brep speckleParent)
|
||||
{
|
||||
foreach (var loop in brep.Loops)
|
||||
{
|
||||
speckleParent.Loops.Add(
|
||||
new SOG.BrepLoop
|
||||
{
|
||||
Brep = speckleParent,
|
||||
FaceIndex = loop.Face.FaceIndex,
|
||||
TrimIndices = loop.Trims.Select(t => t.TrimIndex).ToList(),
|
||||
Type = (SOG.BrepLoopType)loop.LoopType,
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private RG.Mesh? GetBrepDisplayMesh(RG.Brep brep)
|
||||
{
|
||||
var joinedMesh = new RG.Mesh();
|
||||
|
||||
// get from settings
|
||||
//Settings.TryGetValue("sendMeshSetting", out string meshSetting);
|
||||
|
||||
RG.MeshingParameters mySettings = new(0.05, 0.05);
|
||||
// switch (SelectedMeshSettings)
|
||||
// {
|
||||
// case MeshSettings.CurrentDoc:
|
||||
// mySettings = RH.MeshingParameters.DocumentCurrentSetting(Doc);
|
||||
// break;
|
||||
// case MeshSettings.Default:
|
||||
// default:
|
||||
// mySettings = new RH.MeshingParameters(0.05, 0.05);
|
||||
// break;
|
||||
// }
|
||||
|
||||
try
|
||||
{
|
||||
joinedMesh.Append(RG.Mesh.CreateFromBrep(brep, mySettings));
|
||||
return joinedMesh;
|
||||
}
|
||||
catch (Exception ex) when (!ex.IsFatal())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return bx;
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user