Compare commits
137 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e1308bfa21 | |||
| ed1d1f5b44 | |||
| aff871baaa | |||
| 0608e7048d | |||
| 0875e55c1d | |||
| 3508bcc42e | |||
| e59bfb2e12 | |||
| 3bb4039c78 | |||
| bd49e19c9e | |||
| 73bcd75b78 | |||
| a0578fa35d | |||
| 7de08d9f24 | |||
| d047f5e6d2 | |||
| 71071f817c | |||
| c7c864b8c0 | |||
| 67d4862f6b | |||
| 6a16327c30 | |||
| 060b1b8f41 | |||
| da2e228293 | |||
| ab7397bf55 | |||
| f79547f781 | |||
| 2152f1c90e | |||
| 503fb4d246 | |||
| 2befefa752 | |||
| 85e64c5076 | |||
| 60523dc994 | |||
| 6d780bf350 | |||
| eec02a1f84 | |||
| ace2fe6fe3 | |||
| 188794af8d | |||
| 92a941a944 | |||
| 0e1ddf2b11 | |||
| b57fa010d1 | |||
| f816452b78 | |||
| 120083bb31 | |||
| a5bb5c4686 | |||
| e5e2729f0a | |||
| ba8b902f48 | |||
| 2d67815ae6 | |||
| ec0c9066d2 | |||
| 58ae858077 | |||
| 613e7938b3 | |||
| e07ff1a445 | |||
| de7dd34ea2 | |||
| 0552f695f9 | |||
| b8d4f3d946 | |||
| fa112a70b1 | |||
| 97309ebb88 | |||
| 556ddc0b6f | |||
| a0dde690ea | |||
| a76dab5be6 | |||
| 2d10bc5bbf | |||
| 4042632e0b | |||
| 7ccf83e1a4 | |||
| 019cd0756f | |||
| 0e5f9f80be | |||
| fc6767860a | |||
| 5b5b4be7b2 | |||
| 45351d082e | |||
| 22ccd07491 | |||
| 2cf9ee647b | |||
| efb567824b | |||
| f0aac39486 | |||
| f278055805 | |||
| 6f2e36fd11 | |||
| 119d80ffc8 | |||
| 771c3df864 | |||
| 7d1963e458 | |||
| dde85972b3 | |||
| 5e061da910 | |||
| 46bea345de | |||
| bc53462ad6 | |||
| 884df40a1d | |||
| b23168c067 | |||
| 5568212f15 | |||
| 79db79d799 | |||
| 18a4008efd | |||
| 83e4abd1ee | |||
| 243bcfba72 | |||
| af2c8c560f | |||
| 6a37f3871c | |||
| 759a388448 | |||
| 360e89d7ce | |||
| 64655a3284 | |||
| c58356bde8 | |||
| f74117632d | |||
| 5f2b8b8e2b | |||
| f0ce7481fd | |||
| 6e7a5c6140 | |||
| 079c18ee19 | |||
| 26ef6a3815 | |||
| cf6dcefe6c | |||
| 35590eb979 | |||
| 583a8b8a76 | |||
| c6e8a664de | |||
| 24a5e0a579 | |||
| a242c197fb | |||
| 08bdd23149 | |||
| c5b35b2d98 | |||
| 5407fecd1f | |||
| 12d2821d26 | |||
| 2e6d58e6a3 | |||
| 0f0c0fd5ae | |||
| ef9ec1c223 | |||
| f4387bae30 | |||
| 49b238a23a | |||
| 4b75c01b28 | |||
| e7f641046b | |||
| 9aaabe0fab | |||
| b6e4b711bf | |||
| 58fcfd210b | |||
| 5868b9c234 | |||
| 0dc6d9cf9d | |||
| 67f50cf2fd | |||
| 8b26a4d49a | |||
| a1d0bb0aa1 | |||
| bfe08560b1 | |||
| ac3ac24272 | |||
| 03e7191d0e | |||
| b3a42f8723 | |||
| 9c4b740300 | |||
| 2a12bdadf2 | |||
| c90e8ad4d2 | |||
| 4a52c51c86 | |||
| 0efc817ddc | |||
| fee54fc98c | |||
| 210f751396 | |||
| 2e2bc3fe29 | |||
| a6f05f86d1 | |||
| fc144e4848 | |||
| cef9531428 | |||
| abd4faefbf | |||
| 966f7aaed5 | |||
| 51b59fa995 | |||
| 0b713736bd | |||
| 9e33581c66 | |||
| b97792b596 |
+160
-33
@@ -26,21 +26,17 @@ jobs:
|
||||
build-connector: # Reusable job for basic connectors
|
||||
executor:
|
||||
name: win/default # comes with python 3.7.3
|
||||
shell: cmd.exe
|
||||
shell: powershell.exe
|
||||
parameters:
|
||||
slug:
|
||||
type: string
|
||||
default: ""
|
||||
environment:
|
||||
SSM: 'C:\Program Files\DigiCert\DigiCert One Signing Manager Tools'
|
||||
steps:
|
||||
- checkout
|
||||
- attach_workspace:
|
||||
at: ./
|
||||
- run:
|
||||
name: Create Innosetup signing cert
|
||||
shell: powershell.exe
|
||||
command: |
|
||||
echo $env:PFX_B64 > "speckle-sharp-ci-tools\SignTool\AEC Systems Ltd.txt"
|
||||
certutil -decode "speckle-sharp-ci-tools\SignTool\AEC Systems Ltd.txt" "speckle-sharp-ci-tools\SignTool\AEC Systems Ltd.pfx"
|
||||
- run:
|
||||
name: Set Environment Variable
|
||||
shell: powershell.exe
|
||||
@@ -52,30 +48,134 @@ jobs:
|
||||
python patch_version.py $semver
|
||||
environment:
|
||||
WORKFLOW_NUM: << pipeline.number >>
|
||||
- run:
|
||||
name: Build Installer
|
||||
command: speckle-sharp-ci-tools\InnoSetup\ISCC.exe speckle-sharp-ci-tools\sketchup.iss /Sbyparam=$p
|
||||
shell: cmd.exe #does not work in powershell
|
||||
|
||||
#- run:
|
||||
# name: Patch
|
||||
# shell: powershell.exe
|
||||
# command:
|
||||
# | # If no tag, use 0.0.0.1 and don't make any YML (for testing only!)
|
||||
# $tag = if([string]::IsNullOrEmpty($env:CIRCLE_TAG)) { "0.0.0" } else { $env:CIRCLE_TAG }
|
||||
# $semver = if($tag.Contains('/')) {$tag.Split("/")[1] } else { $tag }
|
||||
# $ver = if($semver.Contains('-')) {$semver.Split("-")[0] } else { $semver }
|
||||
# $channel = if($semver.Contains('-')) {$semver.Split("-")[1] } else { "latest" }
|
||||
# $version = "$($ver).$($env:CIRCLE_BUILD_NUM)"
|
||||
# New-Item -Force "speckle-sharp-ci-tools/Installers/sketchup/$channel.yml" -ItemType File -Value "version: $semver"
|
||||
# echo $version
|
||||
# python patch_version.py $semver
|
||||
# speckle-sharp-ci-tools\InnoSetup\ISCC.exe speckle-sharp-ci-tools\sketchup.iss
|
||||
- unless: # Build installers unsigned on non-tagged builds
|
||||
condition: << pipeline.git.tag >>
|
||||
steps:
|
||||
- run:
|
||||
name: Build Installer
|
||||
command: speckle-sharp-ci-tools\InnoSetup\ISCC.exe speckle-sharp-ci-tools\sketchup.iss /Sbyparam=$p
|
||||
shell: cmd.exe # does not work in powershell
|
||||
- when: # Setup certificates and build installers signed for tagged builds
|
||||
condition: << pipeline.git.tag >>
|
||||
steps:
|
||||
- run:
|
||||
name: "Digicert Signing Manager Setup"
|
||||
command: |
|
||||
cd C:\
|
||||
curl.exe -X GET https://one.digicert.com/signingmanager/api-ui/v1/releases/smtools-windows-x64.msi/download -H "x-api-key:$env:SM_API_KEY" -o smtools-windows-x64.msi
|
||||
msiexec.exe /i smtools-windows-x64.msi /quiet /qn | Wait-Process
|
||||
- run:
|
||||
name: "Create Auth & OV Signing Cert"
|
||||
command: |
|
||||
cd C:\
|
||||
echo $env:SM_CLIENT_CERT_FILE_B64 > certificate.txt
|
||||
certutil -decode certificate.txt certificate.p12
|
||||
- run:
|
||||
name: "Sync Certs"
|
||||
command: |
|
||||
& $env:SSM\smksp_cert_sync.exe
|
||||
- run:
|
||||
name: "Build Installer"
|
||||
command: speckle-sharp-ci-tools\InnoSetup\ISCC.exe speckle-sharp-ci-tools\sketchup.iss /Sbyparam=$p /DSIGN_INSTALLER /DCODE_SIGNING_CERT_FINGERPRINT=%SM_CODE_SIGNING_CERT_SHA1_HASH%
|
||||
shell: cmd.exe
|
||||
- persist_to_workspace:
|
||||
root: ./
|
||||
paths:
|
||||
- speckle-sharp-ci-tools/Installers
|
||||
|
||||
build-connector-mac:
|
||||
macos:
|
||||
xcode: 13.4.1
|
||||
parameters:
|
||||
projname:
|
||||
type: string
|
||||
default: ""
|
||||
slug:
|
||||
type: string
|
||||
default: ""
|
||||
installer:
|
||||
type: boolean
|
||||
default: false
|
||||
converter-files:
|
||||
type: string
|
||||
default: ""
|
||||
installername:
|
||||
type: string
|
||||
default: ""
|
||||
build-config:
|
||||
type: string
|
||||
default: Release
|
||||
bundlename:
|
||||
type: string
|
||||
default: ""
|
||||
steps:
|
||||
- checkout
|
||||
- attach_workspace:
|
||||
at: ./
|
||||
- run:
|
||||
name: Install dotnet
|
||||
command: |
|
||||
curl -sSL https://dot.net/v1/dotnet-install.sh | bash /dev/stdin --channel Current
|
||||
|
||||
$HOME/.dotnet/dotnet --version
|
||||
$HOME/.dotnet/dotnet --list-runtimes
|
||||
$HOME/.dotnet/dotnet --list-sdks
|
||||
- run:
|
||||
name: Create installer target dir
|
||||
command: |
|
||||
mkdir -p speckle-sharp-ci-tools/Installers/<< parameters.slug >>
|
||||
- run:
|
||||
name: Set Environment Variable
|
||||
command: |
|
||||
TAG=$(if [ "${CIRCLE_TAG}" ]; then echo $CIRCLE_TAG; else echo "2.0.999"; fi;)
|
||||
SEMVER=$(echo "$TAG" | sed -e 's/\/[a-zA-Z-]*//')
|
||||
VER=$(echo "$SEMVER" | sed -e 's/-.*//')
|
||||
VERSION=$(echo $VER.$WORKFLOW_NUM)
|
||||
python3 patch_version.py $SEMVER
|
||||
environment:
|
||||
WORKFLOW_NUM: << pipeline.number >>
|
||||
- run:
|
||||
name: Zip Connector files
|
||||
command: |
|
||||
zip -r << parameters.slug >>-mac.zip "./speckle_connector" "./speckle_connector.rb"
|
||||
# Copy installer files
|
||||
- run:
|
||||
name: Copy files to installer
|
||||
command: |
|
||||
mkdir -p speckle-sharp-ci-tools/Mac/<< parameters.installername >>/.installationFiles/
|
||||
cp << parameters.slug >>-mac.zip speckle-sharp-ci-tools/Mac/<<parameters.installername>>/.installationFiles
|
||||
# Create installer
|
||||
- run:
|
||||
name: Exit if External PR
|
||||
command: if [ "$CIRCLE_PR_REPONAME" ]; then circleci-agent step halt; fi
|
||||
- run:
|
||||
name: Build Mac installer
|
||||
command: ~/.dotnet/dotnet publish speckle-sharp-ci-tools/Mac/<<parameters.installername>>/<<parameters.installername>>.sln -r osx-x64 -c Release
|
||||
- run:
|
||||
name: Zip installer
|
||||
command: |
|
||||
cd speckle-sharp-ci-tools/Mac/<<parameters.installername>>/bin/Release/net6.0/osx-x64/publish/
|
||||
zip -r <<parameters.slug>>.zip ./
|
||||
- store_artifacts:
|
||||
path: speckle-sharp-ci-tools/Mac/<<parameters.installername>>/bin/Release/net6.0/osx-x64/publish/<<parameters.slug>>.zip
|
||||
- run:
|
||||
name: Copy to installer location
|
||||
command: |
|
||||
TAG=$(if [ "${CIRCLE_TAG}" ]; then echo $CIRCLE_TAG; else echo "2.0.999"; fi;)
|
||||
SEMVER=$(echo "$TAG" | sed -e 's/\/[a-zA-Z-]*//')
|
||||
VER=$(echo "$SEMVER" | sed -e 's/-.*//')
|
||||
VERSION=$(echo $VER.$WORKFLOW_NUM)
|
||||
cp speckle-sharp-ci-tools/Mac/<<parameters.installername>>/bin/Release/net6.0/osx-x64/publish/<<parameters.slug>>.zip speckle-sharp-ci-tools/Installers/<< parameters.slug >>/<<parameters.slug>>-$SEMVER.zip
|
||||
environment:
|
||||
WORKFLOW_NUM: << pipeline.number >>
|
||||
- when:
|
||||
condition: << pipeline.git.tag >>
|
||||
steps:
|
||||
- persist_to_workspace:
|
||||
root: ./
|
||||
paths:
|
||||
- speckle-sharp-ci-tools/Installers
|
||||
|
||||
get-ci-tools: # Clones our ci tools and persists them to the workspace
|
||||
docker:
|
||||
- image: cimg/base:2021.01
|
||||
@@ -91,14 +191,21 @@ jobs:
|
||||
- run:
|
||||
name: Clone
|
||||
command: git clone git@github.com:specklesystems/speckle-sharp-ci-tools.git speckle-sharp-ci-tools
|
||||
- run:
|
||||
name: Checkout branch
|
||||
command: |
|
||||
cd speckle-sharp-ci-tools
|
||||
if [ -z "$CIRCLE_TAG" ]
|
||||
then
|
||||
git checkout ${CIRCLE_BRANCH} || git checkout main
|
||||
else
|
||||
git checkout ${CIRCLE_TAG} || git checkout main
|
||||
fi
|
||||
- persist_to_workspace:
|
||||
root: ./
|
||||
paths:
|
||||
- speckle-sharp-ci-tools
|
||||
- persist_to_workspace:
|
||||
root: ./
|
||||
paths:
|
||||
- speckle-sharp-ci-tools
|
||||
|
||||
deploy-manager2:
|
||||
docker:
|
||||
- image: mcr.microsoft.com/dotnet/sdk:6.0
|
||||
@@ -144,7 +251,17 @@ workflows:
|
||||
filters:
|
||||
tags:
|
||||
only: /.*/
|
||||
context: innosetup
|
||||
context: digicert-keylocker
|
||||
|
||||
- build-connector-mac:
|
||||
slug: sketchup
|
||||
requires:
|
||||
- get-ci-tools
|
||||
- build-ui
|
||||
filters:
|
||||
tags:
|
||||
only: /.*/
|
||||
installername: SpeckleSketchUpInstall
|
||||
|
||||
- deploy-manager2:
|
||||
context: do-spaces-speckle-releases
|
||||
@@ -152,11 +269,21 @@ workflows:
|
||||
os: Win
|
||||
extension: exe
|
||||
requires:
|
||||
- get-ci-tools
|
||||
- build-ui
|
||||
- build-connector
|
||||
filters:
|
||||
tags:
|
||||
only: /([0-9]+)\.([0-9]+)\.([0-9]+)(?:-\w+)?$/
|
||||
branches:
|
||||
ignore: /.*/ # For testing only! /ci\/.*/
|
||||
- deploy-manager2:
|
||||
context: do-spaces-speckle-releases
|
||||
slug: sketchup
|
||||
os: OSX
|
||||
extension: zip
|
||||
requires:
|
||||
- build-connector-mac
|
||||
filters:
|
||||
tags:
|
||||
only: /([0-9]+)\.([0-9]+)\.([0-9]+)(?:-\w+)?$/
|
||||
branches:
|
||||
ignore: /.*/ # For testing only! /ci\/.*/
|
||||
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
[submodule "_sqlite3"]
|
||||
path = _sqlite3
|
||||
url = git@github.com:specklesystems/sketchup-sqlite3.git
|
||||
url = https://github.com/specklesystems/sketchup-sqlite3.git
|
||||
|
||||
@@ -2,44 +2,14 @@
|
||||
<img src="https://user-images.githubusercontent.com/2679513/131189167-18ea5fe1-c578-47f6-9785-3748178e4312.png" width="150px"/><br/>
|
||||
Speckle | SketchUp
|
||||
</h1>
|
||||
|
||||
<p align="center"><a href="https://twitter.com/SpeckleSystems"><img src="https://img.shields.io/twitter/follow/SpeckleSystems?style=social" alt="Twitter Follow"></a> <a href="https://speckle.community"><img src="https://img.shields.io/discourse/users?server=https%3A%2F%2Fspeckle.community&style=flat-square&logo=discourse&logoColor=white" alt="Community forum users"></a> <a href="https://speckle.systems"><img src="https://img.shields.io/badge/https://-speckle.systems-royalblue?style=flat-square" alt="website"></a> <a href="https://speckle.guide/dev/"><img src="https://img.shields.io/badge/docs-speckle.guide-orange?style=flat-square&logo=read-the-docs&logoColor=white" alt="docs"></a></p>
|
||||
|
||||
> Speckle is the first AEC data hub that connects with your favorite AEC tools. Speckle exists to overcome the challenges of working in a fragmented industry where communication, creative workflows, and the exchange of data are often hindered by siloed software and processes. It is here to make the industry better.
|
||||
|
||||
<h3 align="center">
|
||||
Connector for SketchUp
|
||||
</h3>
|
||||
<p align="center"><b>Speckle</b> is the data infrastructure for the AEC industry.</p><br/>
|
||||
|
||||
<p align="center"><a href="https://twitter.com/SpeckleSystems"><img src="https://img.shields.io/twitter/follow/SpeckleSystems?style=social" alt="Twitter Follow"></a> <a href="https://speckle.community"><img src="https://img.shields.io/discourse/users?server=https%3A%2F%2Fspeckle.community&style=flat-square&logo=discourse&logoColor=white" alt="Community forum users"></a> <a href="https://speckle.systems"><img src="https://img.shields.io/badge/https://-speckle.systems-royalblue?style=flat-square" alt="website"></a> <a href="https://speckle.guide/dev/"><img src="https://img.shields.io/badge/docs-speckle.guide-orange?style=flat-square&logo=read-the-docs&logoColor=white" alt="docs"></a></p>
|
||||
<p align="center"><a href="https://github.com/specklesystems/speckle-blender/"><img src="https://circleci.com/gh/specklesystems/speckle-blender.svg?style=svg&circle-token=76eabd350ea243575cbb258b746ed3f471f7ac29" alt="Speckle-Next"></a> </p>
|
||||
|
||||
# About Speckle
|
||||
|
||||
What is Speckle? Check our 
|
||||
|
||||
### Features
|
||||
|
||||
- **Object-based:** say goodbye to files! Speckle is the first object based platform for the AEC industry
|
||||
- **Version control:** Speckle is the Git & Hub for geometry and BIM data
|
||||
- **Collaboration:** share your designs collaborate with others
|
||||
- **3D Viewer:** see your CAD and BIM models online, share and embed them anywhere
|
||||
- **Interoperability:** get your CAD and BIM models into other software without exporting or importing
|
||||
- **Real time:** get real time updates and notifications and changes
|
||||
- **GraphQL API:** get what you need anywhere you want it
|
||||
- **Webhooks:** the base for a automation and next-gen pipelines
|
||||
- **Built for developers:** we are building Speckle with developers in mind and got tools for every stack
|
||||
- **Built for the AEC industry:** Speckle connectors are plugins for the most common software used in the industry such as Revit, Rhino, Grasshopper, AutoCAD, Civil 3D, Excel, Unreal Engine, Unity, QGIS, Blender and more!
|
||||
|
||||
### Try Speckle now!
|
||||
|
||||
Give Speckle a try in no time by:
|
||||
|
||||
- [](https://speckle.xyz) ⇒ creating an account at our public server
|
||||
- [](https://marketplace.digitalocean.com/apps/speckle-server?refcode=947a2b5d7dc1) ⇒ deploying an instance in 1 click
|
||||
|
||||
### Resources
|
||||
|
||||
- [](https://speckle.community) for help, feature requests or just to hang with other speckle enthusiasts, check out our community forum!
|
||||
- [](https://speckle.systems) our tutorials portal is full of resources to get you started using Speckle
|
||||
- [](https://speckle.guide/user/blender.html) reference on almost any end-user and developer functionality
|
||||
|
||||
|
||||
# Repo structure
|
||||
|
||||
@@ -66,6 +36,15 @@ This repo is split into three parts:
|
||||
After building `sqlite3.sln` file, compiled `sqlite3.so` (for Windows) and `sqlite3.bundle` (for OSX) dynamic library files are created
|
||||
by solution to place them into source code into `speckle_connector/src/ext`. Building this project should be only
|
||||
happen when SketchUp starts to support newer Ruby versions (currently it is `2.7`).
|
||||
|
||||
### Other repos
|
||||
|
||||
Make sure to also check and ⭐️ these other Speckle next generation repositories:
|
||||
|
||||
- [`speckle-sharp-connectors`](https://github.com/specklesystems/speckle-sharp-connectors): .NET connectors and desktop UI
|
||||
- [`speckle-sharp-sdk`](https://github.com/specklesystems/speckle-sharp-sdk): our .NET SDK for next gen connectors and development
|
||||
- [`speckle-powerbi`](https://github.com/specklesystems/speckle-powerbi): PowerBi connector
|
||||
- and more [connectors & tooling](https://github.com/specklesystems/)!
|
||||
|
||||
## Contribution Guide
|
||||
|
||||
@@ -194,4 +173,4 @@ To track your code quality locally,
|
||||
2. To check overall state of repository by RubyCritic, run below
|
||||
```ruby
|
||||
rake rubycritic
|
||||
```
|
||||
```
|
||||
|
||||
@@ -24,7 +24,7 @@ module SpeckleConnector
|
||||
|
||||
# Run from localhost or from build files
|
||||
DEV_MODE = false
|
||||
puts("Loading Speckle Connector v#{CONNECTOR_VERSION} from #{DEV_MODE ? 'dev' : 'build'}")
|
||||
puts("Loading Speckle (Legacy) Connector v#{CONNECTOR_VERSION} from #{DEV_MODE ? 'dev' : 'build'}")
|
||||
|
||||
unless file_loaded?(__FILE__)
|
||||
ex = SketchupExtension.new('Speckle SketchUp', File.join(PATH, 'bootstrap'))
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
require 'sketchup'
|
||||
require 'pathname'
|
||||
require 'speckle_connector/debug'
|
||||
require_relative 'src/log/log'
|
||||
require_relative 'src/ui/sketchup_ui'
|
||||
require_relative 'src/ui/ui_controller'
|
||||
require_relative 'src/commands/menu_command_handler'
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 26 KiB |
@@ -9,12 +9,16 @@ module SpeckleConnector
|
||||
module Actions
|
||||
# Apply mappings for selected entities.
|
||||
class ApplyMappings < Action
|
||||
def initialize(entities_to_map, method, category, name, is_definition)
|
||||
def initialize(entities_to_map, method, category, family,
|
||||
family_type, level, name, is_definition)
|
||||
super()
|
||||
@entities_to_map = entities_to_map
|
||||
@method = method
|
||||
@category = category
|
||||
@name = name
|
||||
@family = family
|
||||
@family_type = family_type
|
||||
@level = level
|
||||
@is_definition = is_definition
|
||||
end
|
||||
|
||||
@@ -51,6 +55,9 @@ module SpeckleConnector
|
||||
SketchupModel::Dictionary::SpeckleSchemaDictionaryHandler.set_attribute(entity, :category, @category)
|
||||
SketchupModel::Dictionary::SpeckleSchemaDictionaryHandler.set_attribute(entity, :name, name)
|
||||
SketchupModel::Dictionary::SpeckleSchemaDictionaryHandler.set_attribute(entity, :method, @method)
|
||||
SketchupModel::Dictionary::SpeckleSchemaDictionaryHandler.set_attribute(entity, :family, @family)
|
||||
SketchupModel::Dictionary::SpeckleSchemaDictionaryHandler.set_attribute(entity, :family_type, @family_type)
|
||||
SketchupModel::Dictionary::SpeckleSchemaDictionaryHandler.set_attribute(entity, :level, @level)
|
||||
speckle_state = speckle_state.with_mapped_entity(entity)
|
||||
end
|
||||
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative 'action'
|
||||
require_relative '../sketchup_model/dictionary/speckle_entity_dictionary_handler'
|
||||
|
||||
module SpeckleConnector
|
||||
module Actions
|
||||
# Clear mapper source.
|
||||
class ClearMapperSource < Action
|
||||
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||
# @return [States::State] the new updated state object
|
||||
def self.update_state(state, _data)
|
||||
new_speckle_state = state.speckle_state.with_removed_mapper_source
|
||||
erase_levels(state)
|
||||
state.with_speckle_state(new_speckle_state)
|
||||
end
|
||||
|
||||
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||
def self.erase_levels(state)
|
||||
levels = state.sketchup_state.sketchup_model.definitions.select do |definition|
|
||||
SketchupModel::Dictionary::SpeckleEntityDictionaryHandler.get_attribute(definition, :speckle_type) ==
|
||||
OBJECTS_BUILTELEMENTS_REVIT_LEVEL
|
||||
end
|
||||
levels.each do |level|
|
||||
level.entities.clear!
|
||||
level.instances.each(&:erase!)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,31 +1,28 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative 'event_action'
|
||||
require_relative '../../mapping/category/revit_category'
|
||||
require_relative '../mapper_selection_changed'
|
||||
require_relative '../../mapper/category/revit_category'
|
||||
require_relative '../../sketchup_model/reader/speckle_entities_reader'
|
||||
require_relative '../../sketchup_model/reader/mapper_reader'
|
||||
require_relative '../../sketchup_model/query/entity'
|
||||
|
||||
module SpeckleConnector
|
||||
module Actions
|
||||
module Events
|
||||
# Update selected speckle objects when the selection changes for mapping tool.
|
||||
# Update selected speckle objects when the selection changes for mapper tool.
|
||||
class SelectionEventAction < EventAction
|
||||
# @param state [States::State] the current state of Speckle application.
|
||||
# @return [States::State] the new updated state object
|
||||
def self.update_state(state, event_data)
|
||||
return state unless event_data&.any?
|
||||
|
||||
# Get sketchup selection
|
||||
sketchup_selection = state.sketchup_state.sketchup_model.selection
|
||||
selection = {
|
||||
selection: SketchupModel::Reader::SpeckleEntitiesReader.entities_schema_details(sketchup_selection),
|
||||
mappingMethods: [
|
||||
'Direct Shape'
|
||||
],
|
||||
categories: Mapping::Category::RevitCategory.to_a
|
||||
}
|
||||
selection = { selection: [], mappingMethods: [], categories: [] } if sketchup_selection.none?
|
||||
|
||||
state.with_selection_queue(selection)
|
||||
# Collect and return mapper selection info.
|
||||
# Later we can add more selection info for different scopes.
|
||||
MapperSelectionChanged.new(sketchup_selection).update_state(state)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
require_relative 'action'
|
||||
require_relative 'initialize_materials'
|
||||
require_relative '../sketchup_model/reader/speckle_entities_reader'
|
||||
require_relative '../sketchup_model/reader/mapper_reader'
|
||||
require_relative '../preferences/preferences'
|
||||
require_relative '../states/state'
|
||||
require_relative '../states/sketchup_state'
|
||||
@@ -29,7 +30,7 @@ module SpeckleConnector
|
||||
new_speckle_entities = SketchupModel::Reader::SpeckleEntitiesReader.read(sketchup_model.entities)
|
||||
new_speckle_state = new_state.speckle_state.with_speckle_entities(Immutable::Hash.new(new_speckle_entities))
|
||||
# Read mapped entities
|
||||
new_mapped_entities = SketchupModel::Reader::SpeckleEntitiesReader.read_mapped_entities(sketchup_model.entities)
|
||||
new_mapped_entities = SketchupModel::Reader::MapperReader.read_mapped_entities(sketchup_model.entities)
|
||||
new_speckle_state = new_speckle_state.with_mapped_entities(Immutable::Hash.new(new_mapped_entities))
|
||||
new_state = new_state.with_speckle_state(new_speckle_state)
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative 'action'
|
||||
require_relative '../sketchup_model/reader/speckle_entities_reader'
|
||||
require_relative '../sketchup_model/reader/mapper_reader'
|
||||
|
||||
module SpeckleConnector
|
||||
module Actions
|
||||
@@ -10,8 +10,8 @@ module SpeckleConnector
|
||||
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||
# @return [States::State] the new updated state object
|
||||
def self.update_state(state, _data = nil)
|
||||
mapped_entities = SketchupModel::Reader::SpeckleEntitiesReader
|
||||
.mapped_entity_details(state.speckle_state.mapped_entities.values.to_a)
|
||||
mapped_entities = SketchupModel::Reader::MapperReader
|
||||
.mapped_entity_details(state.speckle_state.speckle_mapper_state.mapped_entities.values.to_a)
|
||||
|
||||
state.with_mapped_entities_queue(mapped_entities)
|
||||
end
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative 'action'
|
||||
require_relative '../mapper/category/revit_category'
|
||||
require_relative '../mapper/category/revit_family_category'
|
||||
|
||||
module SpeckleConnector
|
||||
module Actions
|
||||
# Collects mapper selection info.
|
||||
class MapperInitialized < Action
|
||||
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||
# @return [States::State] the new updated state object
|
||||
def self.update_state(state, _data)
|
||||
init_parameters = {
|
||||
categories: Mapper::Category::RevitCategory.to_a,
|
||||
familyCategories: Mapper::Category::RevitFamilyCategory.to_a
|
||||
}.freeze
|
||||
state.with_mapper_init_queue(init_parameters)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,200 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative 'action'
|
||||
require_relative '../mapper/category/revit_category'
|
||||
require_relative '../mapper/category/revit_family_category'
|
||||
require_relative '../sketchup_model/reader/mapper_reader'
|
||||
require_relative '../sketchup_model/reader/speckle_entities_reader'
|
||||
require_relative '../sketchup_model/dictionary/speckle_entity_dictionary_handler'
|
||||
|
||||
module SpeckleConnector
|
||||
module Actions
|
||||
# Collects mapper selection info.
|
||||
class MapperSelectionChanged < Action
|
||||
READER = SketchupModel::Reader
|
||||
DICTIONARY = SketchupModel::Dictionary
|
||||
|
||||
def initialize(selection)
|
||||
super()
|
||||
@selection = selection
|
||||
end
|
||||
|
||||
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||
# @return [States::State] the new updated state object
|
||||
def update_state(state)
|
||||
# Get mapping info from selection.
|
||||
mapping = get_mapping_info(state, @selection)
|
||||
|
||||
state.with_mapper_selection_queue(mapping)
|
||||
end
|
||||
|
||||
def filter_out_levels(selection)
|
||||
selection.reject do |e|
|
||||
DICTIONARY::SpeckleEntityDictionaryHandler
|
||||
.get_attribute(e, :speckle_type) == OBJECTS_BUILTELEMENTS_REVIT_LEVEL
|
||||
end
|
||||
end
|
||||
|
||||
def get_mapping_info(state, selection)
|
||||
source_exist = !state.speckle_state.speckle_mapper_state.mapper_source.nil?
|
||||
selection = filter_out_levels(selection)
|
||||
grouped_by_type = group_by_type(selection)
|
||||
|
||||
supported_entity_count = grouped_by_type.length
|
||||
|
||||
# Return empty method list if there is no supported entity to map.
|
||||
return EMPTY_SELECTION if supported_entity_count == 0
|
||||
|
||||
# Return Direct Shape itself if multiple kinds of element are selected like Edge and Face.
|
||||
# OR single type is equal to only direct shape supports.
|
||||
return multiple_supported_selection_info(selection) if supported_entity_count > 1
|
||||
|
||||
# FIXME: Distinguish selection info according to selection elegantly!!!
|
||||
if grouped_by_type.keys.first == Sketchup::ComponentInstance
|
||||
return component_selection_info(selection, source_exist)
|
||||
end
|
||||
|
||||
return group_selection_info(selection) if grouped_by_type.keys.first == Sketchup::Group
|
||||
|
||||
if supported_entity_count > 1 ||
|
||||
(supported_entity_count == 1 &&
|
||||
MAPPER_DIRECT_SHAPE_SUPPORTED_ENTITY_TYPES.include?(grouped_by_type.keys.first))
|
||||
if source_exist
|
||||
return direct_shape_selection_info_with_source(selection, [])
|
||||
else
|
||||
return direct_shape_selection_info(selection, source_exist)
|
||||
end
|
||||
end
|
||||
|
||||
# Only single type selections remained after this point.
|
||||
return face_selection_info(state, grouped_by_type.values.first) if grouped_by_type.keys.first == Sketchup::Face
|
||||
|
||||
return edge_selection_info(state, grouped_by_type.values.first) if grouped_by_type.keys.first == Sketchup::Edge
|
||||
|
||||
EMPTY_SELECTION
|
||||
end
|
||||
|
||||
MAPPER_SUPPORTED_ENTITY_TYPES = [
|
||||
Sketchup::ComponentInstance,
|
||||
Sketchup::Group,
|
||||
Sketchup::Face,
|
||||
Sketchup::Edge
|
||||
].freeze
|
||||
|
||||
MAPPER_DIRECT_SHAPE_SUPPORTED_ENTITY_TYPES = [
|
||||
Sketchup::ComponentInstance,
|
||||
Sketchup::Group
|
||||
].freeze
|
||||
|
||||
EMPTY_SELECTION = {
|
||||
selection: [],
|
||||
mappingMethods: []
|
||||
}.freeze
|
||||
|
||||
def multiple_supported_selection_info(selection)
|
||||
{
|
||||
selection: SketchupModel::Reader::MapperReader.entities_schema_details(selection),
|
||||
mappingMethods: ['Direct Shape']
|
||||
}.freeze
|
||||
end
|
||||
|
||||
def component_selection_info(selection, source_exist)
|
||||
if source_exist
|
||||
{
|
||||
selection: SketchupModel::Reader::MapperReader.entities_schema_details(selection),
|
||||
mappingMethods: ['Direct Shape', 'New Revit Family', 'Family Instance']
|
||||
}.freeze
|
||||
else
|
||||
{
|
||||
selection: SketchupModel::Reader::MapperReader.entities_schema_details(selection),
|
||||
mappingMethods: ['Direct Shape', 'New Revit Family']
|
||||
}.freeze
|
||||
end
|
||||
end
|
||||
|
||||
def group_selection_info(selection)
|
||||
{
|
||||
selection: SketchupModel::Reader::MapperReader.entities_schema_details(selection),
|
||||
mappingMethods: ['Direct Shape']
|
||||
}.freeze
|
||||
end
|
||||
|
||||
def direct_shape_selection_info(selection, source_exist)
|
||||
methods = ['Direct Shape', 'New Revit Family']
|
||||
methods.append('Family Instance') if source_exist
|
||||
{
|
||||
selection: SketchupModel::Reader::MapperReader.entities_schema_details(selection),
|
||||
mappingMethods: methods
|
||||
}.freeze
|
||||
end
|
||||
|
||||
def direct_shape_selection_info_with_default(selection, methods)
|
||||
{
|
||||
selection: SketchupModel::Reader::MapperReader.entities_schema_details(selection),
|
||||
mappingMethods: ['Direct Shape'] + methods
|
||||
}.freeze
|
||||
end
|
||||
|
||||
def direct_shape_selection_info_with_source(filtered_selection, methods)
|
||||
instances = @selection.grep(Sketchup::ComponentInstance)
|
||||
selected_level = instances.find do |i|
|
||||
DICTIONARY::SpeckleEntityDictionaryHandler
|
||||
.get_attribute(i, :speckle_type) == OBJECTS_BUILTELEMENTS_REVIT_LEVEL
|
||||
end
|
||||
selected_level_name = nil
|
||||
if selected_level
|
||||
selected_level_name = DICTIONARY::SpeckleEntityDictionaryHandler.get_attribute(selected_level, :name)
|
||||
end
|
||||
{
|
||||
selection: READER::MapperReader.entities_schema_details(filtered_selection),
|
||||
mappingMethods: ['Direct Shape'] + methods,
|
||||
categories: Mapper::Category::RevitCategory.to_a,
|
||||
selectedLevelName: selected_level_name
|
||||
}.freeze
|
||||
end
|
||||
|
||||
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||
def face_selection_info(state, faces)
|
||||
source_exist = !state.speckle_state.speckle_mapper_state.mapper_source.nil?
|
||||
grouped_by_verticality = faces.group_by { |face| face.normal.perpendicular?(VECTOR_Z) }
|
||||
return direct_shape_selection_info(faces, source_exist) if grouped_by_verticality.length == 2
|
||||
|
||||
if source_exist
|
||||
if grouped_by_verticality.keys.first
|
||||
direct_shape_selection_info_with_source(faces, ['Wall'])
|
||||
else
|
||||
direct_shape_selection_info_with_source(faces, ['Floor'])
|
||||
end
|
||||
else
|
||||
if grouped_by_verticality.keys.first
|
||||
direct_shape_selection_info_with_default(faces, ['Default Wall'])
|
||||
else
|
||||
direct_shape_selection_info_with_default(faces, ['Default Floor'])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def edge_selection_info(state, edges)
|
||||
source_exist = !state.speckle_state.speckle_mapper_state.mapper_source.nil?
|
||||
|
||||
if source_exist
|
||||
methods = ['Column', 'Beam', 'Pipe', 'Duct']
|
||||
direct_shape_selection_info_with_source(edges, methods)
|
||||
else
|
||||
default_methods = ['Default Column', 'Default Beam', 'Default Pipe', 'Default Duct']
|
||||
direct_shape_selection_info_with_default(edges, default_methods)
|
||||
end
|
||||
end
|
||||
|
||||
def group_by_type_old(selection)
|
||||
selection.group_by(&:class).filter_map do |group|
|
||||
[group.first, group] if MAPPER_SUPPORTED_ENTITY_TYPES.include?(group.first)
|
||||
end.to_h
|
||||
end
|
||||
|
||||
def group_by_type(selection)
|
||||
selection.select { |s| MAPPER_SUPPORTED_ENTITY_TYPES.include?(s.class) }.group_by(&:class)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,77 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative 'action'
|
||||
require_relative '../constants/type_constants'
|
||||
require_relative '../mapper/mapper_source'
|
||||
require_relative '../speckle_objects/built_elements/revit/revit_element_type'
|
||||
|
||||
module SpeckleConnector
|
||||
module Actions
|
||||
# Action to update mapper source.
|
||||
class MapperSourceUpdated < Action
|
||||
def initialize(base, stream_id, commit_id)
|
||||
super()
|
||||
@base = base
|
||||
@stream_id = stream_id
|
||||
@commit_id = commit_id
|
||||
end
|
||||
|
||||
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||
# @return [States::State] the new updated state object
|
||||
def update_state(state)
|
||||
levels = convert_levels(state, @base['@Levels'])
|
||||
types = convert_types(@base['@Types'])
|
||||
family_instances = convert_family_instance_types(@base['@Types'])
|
||||
mapper_source = Mapper::MapperSource.new(@stream_id, @commit_id, levels, types)
|
||||
new_speckle_state = state.speckle_state.with_mapper_source(mapper_source)
|
||||
state = state.with_speckle_state(new_speckle_state)
|
||||
|
||||
state.with_add_queue('mapperSourceUpdated', @stream_id, [
|
||||
{ is_string: false, val: levels.to_json },
|
||||
{ is_string: false, val: types.to_json },
|
||||
{ is_string: false, val: family_instances.to_json }
|
||||
])
|
||||
end
|
||||
|
||||
def convert_types(types)
|
||||
types.collect do |type, type_elements|
|
||||
next if type_elements.nil? || !type_elements.is_a?(Array) || type == '__closure'
|
||||
|
||||
type = type[1..-1] if type[0] == '@'
|
||||
elements = type_elements.map do |type_element|
|
||||
SpeckleObjects::BuiltElements::Revit::RevitElementType.to_native(type_element)
|
||||
end
|
||||
elements = elements.group_by { |e| e[:family] }
|
||||
[type, elements]
|
||||
end.compact.to_h
|
||||
end
|
||||
|
||||
def convert_family_instance_types(types)
|
||||
family_instance_types = {}
|
||||
types.each do |type, type_elements|
|
||||
next if type_elements.nil? || !type_elements.is_a?(Array) || type == '__closure'
|
||||
|
||||
# skip type if there is no any revit symbol element type
|
||||
symbol_element_types = type_elements.select do |t|
|
||||
t['speckle_type'] == OBJECTS_BUILTELEMENTS_REVIT_REVITSYMBOLELEMENTTYPE &&
|
||||
t['placementType'] == 'OneLevelBased'
|
||||
end
|
||||
next if symbol_element_types.empty?
|
||||
|
||||
elements = type_elements.map do |type_element|
|
||||
SpeckleObjects::BuiltElements::Revit::RevitElementType.to_native(type_element)
|
||||
end
|
||||
elements = elements.group_by { |e| e[:family] }
|
||||
family_instance_types.merge!(elements)
|
||||
end
|
||||
family_instance_types
|
||||
end
|
||||
|
||||
def convert_levels(state, levels)
|
||||
levels.collect do |level|
|
||||
SpeckleObjects::BuiltElements::Level.to_native(state, level, @stream_id)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -3,6 +3,7 @@
|
||||
require_relative 'action'
|
||||
require_relative '../convertors/units'
|
||||
require_relative '../convertors/to_native'
|
||||
require_relative '../convertors/clean_up'
|
||||
|
||||
module SpeckleConnector
|
||||
module Actions
|
||||
@@ -26,7 +27,12 @@ module SpeckleConnector
|
||||
converter = Converters::ToNative.new(state, @stream_id, @stream_name, @branch_name, @source_app)
|
||||
# Have side effects on the sketchup model. It effects directly on the entities by adding new objects.
|
||||
start_time = Time.now.to_f
|
||||
state.sketchup_state.sketchup_model.start_operation('Receive Speckle Objects', true)
|
||||
state = converter.receive_commit_object(@base)
|
||||
if state.user_state.model_preferences[:merge_coplanar_faces]
|
||||
Converters::CleanUp.merge_coplanar_faces(converter.converted_faces)
|
||||
end
|
||||
state.sketchup_state.sketchup_model.commit_operation
|
||||
elapsed_time = (Time.now.to_f - start_time).round(3)
|
||||
puts "==== Converting to Native executed in #{elapsed_time} sec ===="
|
||||
puts "==== Source application is #{@source_app}. ===="
|
||||
|
||||
@@ -11,9 +11,13 @@ module SpeckleConnector
|
||||
entities_to_map = data['entitiesToMap']
|
||||
method = data['method']
|
||||
category = data['category']
|
||||
family = data['family']
|
||||
family_type = data['familyType']
|
||||
level = data['level']
|
||||
name = data['name']
|
||||
is_definition = data['isDefinition']
|
||||
action = Actions::ApplyMappings.new(entities_to_map, method, category, name, is_definition)
|
||||
action = Actions::ApplyMappings.new(entities_to_map, method, category, family,
|
||||
family_type, level, name, is_definition)
|
||||
app.update_state!(action)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -12,7 +12,7 @@ module SpeckleConnector
|
||||
# This is the command where we show UI to user.
|
||||
class InitializeSpeckle < Command
|
||||
def dialog_title
|
||||
"Speckle #{CONNECTOR_VERSION}"
|
||||
"Speckle (Legacy) #{CONNECTOR_VERSION}"
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative 'command'
|
||||
require_relative '../actions/mapper_source_updated'
|
||||
|
||||
module SpeckleConnector
|
||||
module Commands
|
||||
# Command to update mapper source.
|
||||
class MapperSourceUpdated < Command
|
||||
def _run(data)
|
||||
base = data['base']
|
||||
stream_id = data['stream_id']
|
||||
commit_id = data['commit_id']
|
||||
action = Actions::MapperSourceUpdated.new(base, stream_id, commit_id)
|
||||
app.update_state!(action)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,27 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative 'command'
|
||||
require_relative '../states/initial_state'
|
||||
require_relative '../ui/vue_view'
|
||||
require_relative '../actions/initialize_speckle'
|
||||
require_relative '../observers/factory'
|
||||
|
||||
module SpeckleConnector
|
||||
module Commands
|
||||
# Command to reset Speckle UI window location onto center of SketchUp window.
|
||||
class ResetWindowLocation < Command
|
||||
|
||||
private
|
||||
|
||||
def _run
|
||||
app = self.app
|
||||
vue_view = app.ui_controller.user_interfaces[Ui::SPECKLE_UI_ID]
|
||||
if vue_view
|
||||
vue_view.dialog.reset_dialog_location
|
||||
else
|
||||
puts "Speckle UI didn't initialized!"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -3,6 +3,7 @@
|
||||
require_relative 'menu_command_handler'
|
||||
require_relative 'action_command'
|
||||
require_relative 'initialize_speckle'
|
||||
require_relative 'reset_window_location'
|
||||
require_relative '../actions/one_click_send'
|
||||
|
||||
module SpeckleConnector
|
||||
@@ -10,6 +11,7 @@ module SpeckleConnector
|
||||
# Speckle menu commands that adds them to Sketchup menu and toolbar.
|
||||
class SpeckleMenuCommands
|
||||
CMD_INITIALIZE_SPECKLE = :initialize_speckle
|
||||
CMD_RESET_WINDOW_LOCATION_SPECKLE = :reset_window_location_speckle
|
||||
CMD_SEND_TO_SPECKLE = :send_to_speckle
|
||||
CMD_RECEIVE_FROM_SPECKLE = :receive_from_speckle
|
||||
|
||||
@@ -26,31 +28,29 @@ module SpeckleConnector
|
||||
commands.add_to_menu!(CMD_INITIALIZE_SPECKLE, speckle_menu)
|
||||
commands.add_to_toolbar!(CMD_INITIALIZE_SPECKLE, speckle_toolbar)
|
||||
|
||||
# commands[CMD_SEND_TO_SPECKLE] = send_command(app)
|
||||
# commands.add_to_menu!(CMD_SEND_TO_SPECKLE, speckle_menu)
|
||||
# commands.add_to_toolbar!(CMD_SEND_TO_SPECKLE, speckle_toolbar)
|
||||
commands[CMD_RESET_WINDOW_LOCATION_SPECKLE] = reset_window_location_command(app)
|
||||
commands.add_to_menu!(CMD_RESET_WINDOW_LOCATION_SPECKLE, speckle_menu)
|
||||
end
|
||||
|
||||
def self.initialize_speckle_command(app)
|
||||
cmd = MenuCommandHandler.sketchup_command(
|
||||
InitializeSpeckle.new(app), 'Initialize Speckle'
|
||||
InitializeSpeckle.new(app), 'Initialize Speckle (Legacy)'
|
||||
)
|
||||
cmd.tooltip = 'Launch Connector'
|
||||
cmd.status_bar_text = 'Opens the Speckle Connector window'
|
||||
cmd.status_bar_text = 'Opens the Speckle (Legacy) Connector window'
|
||||
cmd.small_icon = '../../img/s2logo.png'
|
||||
cmd.large_icon = '../../img/s2logo.png'
|
||||
cmd
|
||||
end
|
||||
|
||||
def self.send_command(app)
|
||||
def self.reset_window_location_command(app)
|
||||
cmd = MenuCommandHandler.sketchup_command(
|
||||
ActionCommand.new(app, Actions::OneClickSend), 'Send to Speckle'
|
||||
ResetWindowLocation.new(app), 'Reset Window Location'
|
||||
)
|
||||
cmd.tooltip = 'Send to Speckle'
|
||||
cmd.status_bar_text = 'Send to Speckle'
|
||||
cmd.small_icon = '../../img/Sender.png'
|
||||
cmd.large_icon = '../../img/Sender.png'
|
||||
cmd.set_validation_proc { MenuCommandHandler.speckle_started(app) }
|
||||
cmd.tooltip = 'Bring Speckle window onto center of SketchUp window'
|
||||
cmd.status_bar_text = 'Bring Speckle window onto center of SketchUp window'
|
||||
cmd.small_icon = '../../img/s2logo.png'
|
||||
cmd.large_icon = '../../img/s2logo.png'
|
||||
cmd
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module SpeckleConnector
|
||||
VECTOR_Z = Geom::Vector3d.new(0, 0, 1)
|
||||
end
|
||||
@@ -14,7 +14,9 @@ module SpeckleConnector
|
||||
path = ENV.fetch('APPDATA')
|
||||
Pathname.new(File.join(path, 'Speckle')).cleanpath.to_s
|
||||
when OS_MAC
|
||||
File.join(Dir.home, 'Library/Application Support/Speckle')
|
||||
primary_path = File.join(Dir.home, '.config/Speckle')
|
||||
fallback_path = File.join(Dir.home, 'Library/Application Support/Speckle')
|
||||
Dir.exist?(primary_path) ? primary_path : fallback_path
|
||||
else
|
||||
raise 'Speckle could not determine your Appdata path'
|
||||
end
|
||||
|
||||
@@ -15,7 +15,7 @@ module SpeckleConnector
|
||||
Sketchup::ComponentInstance => INCLUDE_COMPONENT_ENTITY_ATTRIBUTES,
|
||||
Sketchup::Group => INCLUDE_GROUP_ENTITY_ATTRIBUTES,
|
||||
Sketchup::Face => INCLUDE_FACE_ENTITY_ATTRIBUTES,
|
||||
Sketchup::Face => INCLUDE_EDGE_ENTITY_ATTRIBUTES
|
||||
Sketchup::Edge => INCLUDE_EDGE_ENTITY_ATTRIBUTES
|
||||
}.freeze
|
||||
|
||||
LEVEL_SHIFT_VALUE = SpeckleObjects::Geometry.length_to_native(1.5, 'm')
|
||||
|
||||
@@ -4,14 +4,34 @@ module SpeckleConnector
|
||||
BASE_OBJECT = 'Base'
|
||||
|
||||
OBJECTS_GIS_POLYGONELEMENT = 'Objects.GIS.PolygonElement'
|
||||
OBJECTS_GIS_LINEELEMENT = 'Objects.GIS.LineElement'
|
||||
|
||||
OBJECTS_BUILTELEMENTS_VIEW3D = 'Objects.BuiltElements.View:Objects.BuiltElements.View3D'
|
||||
OBJECTS_BUILTELEMENTS_NETWORK = 'Objects.BuiltElements.Network'
|
||||
OBJECTS_BUILTELEMENTS_REVIT_DIRECTSHAPE = 'Objects.BuiltElements.Revit.DirectShape'
|
||||
OBJECTS_BUILTELEMENTS_REVIT_LEVEL = 'Objects.BuiltElements.Level:Objects.BuiltElements.Revit.RevitLevel'
|
||||
OBJECTS_BUILTELEMENTS_DEFAULT_FLOOR = 'Objects.BuiltElements.Floor'
|
||||
OBJECTS_BUILTELEMENTS_REVIT_FLOOR = 'Objects.BuiltElements.Floor:Objects.BuiltElements.Revit.RevitFloor'
|
||||
OBJECTS_BUILTELEMENTS_DEFAULT_WALL = 'Objects.BuiltElements.Wall'
|
||||
OBJECTS_BUILTELEMENTS_REVIT_WALL = 'Objects.BuiltElements.Wall:Objects.BuiltElements.Revit.RevitWall'
|
||||
OBJECTS_BUILTELEMENTS_DEFAULT_COLUMN = 'Objects.BuiltElements.Column'
|
||||
OBJECTS_BUILTELEMENTS_REVIT_COLUMN = 'Objects.BuiltElements.Column:Objects.BuiltElements.Revit.RevitColumn'
|
||||
OBJECTS_BUILTELEMENTS_DEFAULT_BEAM = 'Objects.BuiltElements.Beam'
|
||||
OBJECTS_BUILTELEMENTS_REVIT_BEAM = 'Objects.BuiltElements.Beam:Objects.BuiltElements.Revit.RevitBeam'
|
||||
OBJECTS_BUILTELEMENTS_DEFAULT_PIPE = 'Objects.BuiltElements.Pipe'
|
||||
OBJECTS_BUILTELEMENTS_REVIT_PIPE = 'Objects.BuiltElements.Pipe:Objects.BuiltElements.Revit.RevitPipe'
|
||||
OBJECTS_BUILTELEMENTS_DEFAULT_DUCT = 'Objects.BuiltElements.Duct'
|
||||
OBJECTS_BUILTELEMENTS_REVIT_DUCT = 'Objects.BuiltElements.Duct:Objects.BuiltElements.Revit.RevitDuct'
|
||||
OBJECTS_BUILTELEMENTS_REVIT_DIRECTSHAPE = 'Objects.BuiltElements.Revit.DirectShape'
|
||||
OBJECTS_BUILTELEMENTS_REVIT_FAMILY_INSTANCE = 'Objects.BuiltElements.Revit.FamilyInstance'
|
||||
OBJECTS_BUILTELEMENTS_REVIT_PARAMETER = 'Objects.BuiltElements.Revit.Parameter'
|
||||
OBJECTS_BUILTELEMENTS_REVIT_REVITELEMENTTYPE = 'Objects.BuiltElements.Revit.RevitElementType'
|
||||
OBJECTS_BUILTELEMENTS_REVIT_REVITSYMBOLELEMENTTYPE = 'Objects.BuiltElements.Revit.RevitElementType:Objects.BuiltElements.Revit.RevitSymbolElementType'
|
||||
|
||||
OBJECTS_GEOMETRY_LINE = 'Objects.Geometry.Line'
|
||||
OBJECTS_GEOMETRY_POLYLINE = 'Objects.Geometry.Polyline'
|
||||
OBJECTS_GEOMETRY_POLYCURVE = 'Objects.Geometry.Polycurve'
|
||||
OBJECTS_GEOMETRY_ARC = 'Objects.Geometry.Arc'
|
||||
OBJECTS_GEOMETRY_CIRCLE = 'Objects.Geometry.Circle'
|
||||
OBJECTS_GEOMETRY_MESH = 'Objects.Geometry.Mesh'
|
||||
OBJECTS_GEOMETRY_BREP = 'Objects.Geometry.Brep'
|
||||
|
||||
@@ -24,4 +44,6 @@ module SpeckleConnector
|
||||
OBJECTS_OTHER_DISPLAYSTYLE = 'Objects.Other.DisplayStyle'
|
||||
|
||||
SPECKLE_CORE_MODELS_COLLECTION = 'Speckle.Core.Models.Collection'
|
||||
SPECKLE_CORE_MODELS_COLLECTION_RASTER_LAYER = 'Speckle.Core.Models.Collection:Objects.GIS.RasterLayer'
|
||||
SPECKLE_CORE_MODELS_COLLECTION_VECTOR_LAYER = 'Speckle.Core.Models.Collection:Objects.GIS.VectorLayer'
|
||||
end
|
||||
|
||||
@@ -11,12 +11,31 @@ module SpeckleConnector
|
||||
# @param entities [Sketchup::Entities] entities to remove edges between that make entities coplanar.
|
||||
# @note Merging coplanar faces idea originated from [CleanUp](https://github.com/thomthom/cleanup) plugin
|
||||
# which is developed by [Thomas Thomassen](https://github.com/thomthom).
|
||||
def self.merge_coplanar_faces(entities)
|
||||
def self.merge_coplanar_entities(entities)
|
||||
edges = []
|
||||
faces = entities.collect { |entity| entity if entity.is_a? Sketchup::Face }.compact
|
||||
faces = merged_faces(faces)
|
||||
faces.each { |face| face.edges.each { |edge| edges << edge } }
|
||||
edges.uniq!
|
||||
edges.each { |edge| remove_edge_have_coplanar_faces(edge, faces, false) }
|
||||
# Remove remaining orphan edges
|
||||
edges.reject(&:deleted?).select { |edge| edge.faces.empty? }.each(&:erase!)
|
||||
merged_faces(faces)
|
||||
end
|
||||
|
||||
def self.merge_coplanar_faces(faces)
|
||||
edges = []
|
||||
faces = faces.reject(&:deleted?)
|
||||
|
||||
faces.each { |face| face.edges.each { |edge| edges << edge } }
|
||||
|
||||
edges.uniq!
|
||||
|
||||
edges.each { |edge| remove_edge_have_coplanar_faces(edge) }
|
||||
|
||||
# Remove remaining orphan edges
|
||||
# edges.reject(&:deleted?).select { |edge| edge.faces.empty? }.each(&:erase!)
|
||||
|
||||
merged_faces(faces)
|
||||
end
|
||||
|
||||
@@ -33,43 +52,34 @@ module SpeckleConnector
|
||||
# - Whether UV texture map is aligned between faces or not.
|
||||
# - Finally, if faces are coplanar by correcting these checks, then removes edge from Sketchup.active_model.
|
||||
# @param edge [Sketchup::Edge] edge to check.
|
||||
# @param faces [Array<Sketchup::Face>] scoped faces to check 'edge.faces' both (first and second)
|
||||
# belongs to this faces or not. If any of this faces does not involve this scoped faces, then do not delete.
|
||||
# @param ignore_materials [Boolean] whether ignore materials or not.
|
||||
# Returns true if the given edge separating two coplanar faces.
|
||||
# Return false otherwise.
|
||||
# rubocop:disable Metrics/AbcSize
|
||||
def self.remove_edge_have_coplanar_faces(edge, faces, ignore_materials)
|
||||
def self.remove_edge_have_coplanar_faces(edge)
|
||||
return false unless edge.valid? && edge.is_a?(Sketchup::Edge)
|
||||
return false unless edge.faces.size == 2
|
||||
|
||||
# Check scoped faces have this edges
|
||||
if edge.faces.size == 2
|
||||
is_first = faces.include?(edge.faces[0])
|
||||
is_second = faces.include?(edge.faces[1])
|
||||
return false unless is_first && is_second
|
||||
end
|
||||
|
||||
face_1, face_2 = edge.faces
|
||||
|
||||
return false if face_duplicate?(face_1, face_2)
|
||||
# Check for troublesome faces which might lead to missing geometry if merged.
|
||||
return false unless edge_safe_to_merge?(edge)
|
||||
begin
|
||||
return false unless face_1.normal.samedirection?(face_2.normal)
|
||||
|
||||
return false if face_duplicate?(face_1, face_2)
|
||||
# Check for troublesome faces which might lead to missing geometry if merged.
|
||||
return false unless edge_safe_to_merge?(edge)
|
||||
|
||||
# Check materials match.
|
||||
unless ignore_materials
|
||||
return false unless (face_1.material == face_2.material) && (face_1.back_material == face_2.back_material)
|
||||
|
||||
# Verify UV mapping match.
|
||||
return false if !face_1.material.nil? && !continuous_uv?(face_1, face_2, edge) && face_1.material.texture.nil?
|
||||
end
|
||||
# Check faces are coplanar or not.
|
||||
return false unless faces_coplanar?(face_1, face_2)
|
||||
# Check faces are coplanar or not.
|
||||
return false unless faces_coplanar?(face_1, face_2)
|
||||
|
||||
edge.erase!
|
||||
true
|
||||
edge.erase!
|
||||
true
|
||||
rescue StandardError => e
|
||||
puts "Failed to merge coplanar faces by removing edge with error: #{e}"
|
||||
false
|
||||
end
|
||||
end
|
||||
# rubocop:enable Metrics/AbcSize
|
||||
|
||||
# Determines if two faces are overlapped.
|
||||
def self.face_duplicate?(face_1, face_2, overlapping: false)
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
|
||||
require_relative 'converter'
|
||||
require_relative '../constants/type_constants'
|
||||
require_relative '../speckle_entities/speckle_entity'
|
||||
require_relative '../speckle_objects/gis/polygon_element'
|
||||
require_relative '../speckle_objects/gis/line_element'
|
||||
require_relative '../speckle_objects/other/transform'
|
||||
require_relative '../speckle_objects/other/render_material'
|
||||
require_relative '../speckle_objects/other/block_definition'
|
||||
@@ -11,10 +13,14 @@ require_relative '../speckle_objects/other/display_value'
|
||||
require_relative '../speckle_objects/revit/revit_instance'
|
||||
require_relative '../speckle_objects/geometry/point'
|
||||
require_relative '../speckle_objects/geometry/line'
|
||||
require_relative '../speckle_objects/geometry/polycurve'
|
||||
require_relative '../speckle_objects/geometry/arc'
|
||||
require_relative '../speckle_objects/geometry/circle'
|
||||
require_relative '../speckle_objects/geometry/mesh'
|
||||
require_relative '../speckle_objects/built_elements/view3d'
|
||||
require_relative '../speckle_objects/built_elements/network'
|
||||
require_relative '../speckle_objects/speckle/core/models/collection'
|
||||
require_relative '../speckle_objects/speckle/core/models/gis_layer_collection'
|
||||
require_relative '../sketchup_model/dictionary/speckle_entity_dictionary_handler'
|
||||
|
||||
module SpeckleConnector
|
||||
@@ -28,11 +34,14 @@ module SpeckleConnector
|
||||
# @return [String] source application of received object that will be converted to native
|
||||
attr_reader :source_app
|
||||
|
||||
attr_reader :converted_faces
|
||||
|
||||
def initialize(state, stream_id, stream_name, branch_name, source_app)
|
||||
super(state, stream_id)
|
||||
@stream_name = stream_name
|
||||
@branch_name = branch_name
|
||||
@source_app = source_app.downcase
|
||||
@converted_faces = []
|
||||
end
|
||||
|
||||
# Module aliases
|
||||
@@ -45,20 +54,29 @@ module SpeckleConnector
|
||||
# Class aliases
|
||||
POINT = GEOMETRY::Point
|
||||
LINE = GEOMETRY::Line
|
||||
POLYCURVE = GEOMETRY::Polycurve
|
||||
ARC = GEOMETRY::Arc
|
||||
CIRCLE = GEOMETRY::Circle
|
||||
MESH = GEOMETRY::Mesh
|
||||
BLOCK_DEFINITION = OTHER::BlockDefinition
|
||||
BLOCK_INSTANCE = OTHER::BlockInstance
|
||||
REVIT_INSTANCE = REVIT::Other::RevitInstance
|
||||
REVIT_WALL = BUILTELEMENTS::RevitWall
|
||||
RENDER_MATERIAL = OTHER::RenderMaterial
|
||||
DISPLAY_VALUE = OTHER::DisplayValue
|
||||
VIEW3D = BUILTELEMENTS::View3d
|
||||
POLYGON_ELEMENT = GIS::PolygonElement
|
||||
LINE_ELEMENT = GIS::LineElement
|
||||
COLLECTION = SpeckleObjects::Speckle::Core::Models::Collection
|
||||
GIS_LAYER_COLLECTION = SpeckleObjects::Speckle::Core::Models::GisLayerCollection
|
||||
|
||||
BASE_OBJECT_PROPS = %w[applicationId id speckle_type totalChildrenCount].freeze
|
||||
CONVERTABLE_SPECKLE_TYPES = %w[
|
||||
Objects.Geometry.Line
|
||||
Objects.Geometry.Polyline
|
||||
Objects.Geometry.Polycurve
|
||||
Objects.Geometry.Arc
|
||||
Objects.Geometry.Circle
|
||||
Objects.Geometry.Mesh
|
||||
Objects.Geometry.Brep
|
||||
Objects.Other.BlockInstance
|
||||
@@ -67,15 +85,23 @@ module SpeckleConnector
|
||||
Objects.Other.RenderMaterial
|
||||
Objects.Other.Instance:Objects.Other.BlockInstance
|
||||
Objects.BuiltElements.View:Objects.BuiltElements.View3D
|
||||
Objects.BuiltElements.Wall:Objects.BuiltElements.Revit.RevitWall
|
||||
Objects.BuiltElements.Network
|
||||
Objects.GIS.PolygonElement
|
||||
Objects.GIS.LineElement
|
||||
Speckle.Core.Models.Collection
|
||||
Speckle.Core.Models.Collection:Objects.GIS.RasterLayer
|
||||
Speckle.Core.Models.Collection:Objects.GIS.VectorLayer
|
||||
].freeze
|
||||
|
||||
def from_revit
|
||||
@from_revit ||= source_app.include?('revit')
|
||||
end
|
||||
|
||||
def from_rhino
|
||||
@from_rhino ||= source_app.include?('rhino')
|
||||
end
|
||||
|
||||
def from_sketchup
|
||||
@from_sketchup ||= source_app.include?('sketchup')
|
||||
end
|
||||
@@ -89,14 +115,9 @@ module SpeckleConnector
|
||||
# UI is responsible currently to fetch objects from ObjectLoader module by calling getAndConstruct method.
|
||||
# @param obj [Object] speckle commit object.
|
||||
def receive_commit_object(obj)
|
||||
# First create layers on the sketchup before starting traversing
|
||||
# @Named Views are exception here. It does not mean a layer. But it is anti-pattern for now.
|
||||
# layers_relation = obj['layers_relation']
|
||||
|
||||
unless from_revit
|
||||
layers_relation = SpeckleObjects::Relations::Layers.extract_relations(obj)
|
||||
# Create layers and it's folders from layers relation on the model collection.
|
||||
SpeckleObjects::Relations::Layers.to_native(layers_relation, sketchup_model) if layers_relation
|
||||
SpeckleObjects::Relations::Layers.to_native(obj, source_app, sketchup_model)
|
||||
end
|
||||
|
||||
# By default entities to fill is sketchup model's entities.
|
||||
@@ -242,7 +263,7 @@ module SpeckleConnector
|
||||
# rubocop:disable Metrics/PerceivedComplexity
|
||||
def traverse_commit_object(obj, layer, entities)
|
||||
if convertible_to_native?(obj)
|
||||
@state = convert_to_native(@state, obj, layer, entities)
|
||||
@state, _converted_entities = convert_to_native(@state, obj, layer, entities)
|
||||
elsif obj.is_a?(Hash) && obj.key?('speckle_type')
|
||||
return if ignored_speckle_type?(obj)
|
||||
|
||||
@@ -254,7 +275,7 @@ module SpeckleConnector
|
||||
end
|
||||
else
|
||||
# puts(">>> Found #{obj['speckle_type']}: #{obj['id']} with displayValue.")
|
||||
@state = convert_to_native(@state, obj, layer, entities)
|
||||
@state, _converted_entities = convert_to_native(@state, obj, layer, entities)
|
||||
end
|
||||
elsif obj.is_a?(Hash)
|
||||
obj.each_value { |value| traverse_commit_object(value, layer, entities) }
|
||||
@@ -266,7 +287,7 @@ module SpeckleConnector
|
||||
# rubocop:enable Metrics/PerceivedComplexity
|
||||
|
||||
def speckle_object_to_native(obj)
|
||||
return DISPLAY_VALUE.method(:to_native) unless obj['displayValue'].nil?
|
||||
return DISPLAY_VALUE.method(:to_native) unless obj['displayValue'].nil? && obj['@displayValue'].nil?
|
||||
|
||||
SPECKLE_OBJECT_TO_NATIVE[obj['speckle_type']]
|
||||
end
|
||||
@@ -274,6 +295,9 @@ module SpeckleConnector
|
||||
SPECKLE_OBJECT_TO_NATIVE = {
|
||||
OBJECTS_GEOMETRY_LINE => LINE.method(:to_native),
|
||||
OBJECTS_GEOMETRY_POLYLINE => LINE.method(:to_native),
|
||||
OBJECTS_GEOMETRY_POLYCURVE => POLYCURVE.method(:to_native),
|
||||
OBJECTS_GEOMETRY_ARC => ARC.method(:to_native),
|
||||
OBJECTS_GEOMETRY_CIRCLE => CIRCLE.method(:to_native),
|
||||
OBJECTS_GEOMETRY_MESH => MESH.method(:to_native),
|
||||
OBJECTS_GEOMETRY_BREP => MESH.method(:to_native),
|
||||
OBJECTS_OTHER_BLOCKDEFINITION => BLOCK_DEFINITION.method(:to_native),
|
||||
@@ -282,10 +306,14 @@ module SpeckleConnector
|
||||
OBJECTS_OTHER_REVIT_REVITINSTANCE => REVIT_INSTANCE.method(:to_native),
|
||||
OBJECTS_OTHER_RENDERMATERIAL => RENDER_MATERIAL.method(:to_native),
|
||||
OBJECTS_BUILTELEMENTS_VIEW3D => VIEW3D.method(:to_native),
|
||||
OBJECTS_BUILTELEMENTS_REVIT_WALL => REVIT_WALL.method(:to_native),
|
||||
OBJECTS_BUILTELEMENTS_REVIT_DIRECTSHAPE => BUILTELEMENTS::Revit::DirectShape.method(:to_native),
|
||||
OBJECTS_BUILTELEMENTS_NETWORK => BUILTELEMENTS::Network.method(:to_native),
|
||||
OBJECTS_GIS_POLYGONELEMENT => POLYGON_ELEMENT.method(:to_native),
|
||||
SPECKLE_CORE_MODELS_COLLECTION => COLLECTION.method(:to_native)
|
||||
OBJECTS_GIS_LINEELEMENT => LINE_ELEMENT.method(:to_native),
|
||||
SPECKLE_CORE_MODELS_COLLECTION => COLLECTION.method(:to_native),
|
||||
SPECKLE_CORE_MODELS_COLLECTION_RASTER_LAYER => GIS_LAYER_COLLECTION.method(:to_native),
|
||||
SPECKLE_CORE_MODELS_COLLECTION_VECTOR_LAYER => GIS_LAYER_COLLECTION.method(:to_native)
|
||||
}.freeze
|
||||
|
||||
# @param state [States::State] state of the speckle application
|
||||
@@ -297,6 +325,8 @@ module SpeckleConnector
|
||||
# Call 'to_native' method by passing this method itself to handle nested 'to_native' conversions.
|
||||
# It returns updated state and converted entities.
|
||||
state, converted_entities = to_native_method.call(state, obj, layer, entities, &convert_to_native)
|
||||
faces = converted_entities.select { |e| e.is_a?(Sketchup::Face) }
|
||||
@converted_faces += faces if faces.any?
|
||||
if from_revit
|
||||
# Create levels as section planes if they exists
|
||||
create_levels(state, obj)
|
||||
@@ -304,11 +334,11 @@ module SpeckleConnector
|
||||
create_layers_from_categories(state, obj, converted_entities)
|
||||
end
|
||||
# Create speckle entities from sketchup entities to achieve continuous traversal.
|
||||
convert_to_speckle_entities(state, obj, converted_entities)
|
||||
SpeckleEntities::SpeckleEntity.from_speckle_object(state, obj, converted_entities, stream_id)
|
||||
rescue StandardError => e
|
||||
puts("Failed to convert #{obj['speckle_type']} (id: #{obj['id']})")
|
||||
puts(e)
|
||||
return state
|
||||
return state, []
|
||||
end
|
||||
|
||||
# rubocop:disable Metrics/CyclomaticComplexity
|
||||
@@ -353,30 +383,9 @@ module SpeckleConnector
|
||||
end
|
||||
|
||||
# @param state [States::State] state of the application
|
||||
# rubocop:disable Metrics/PerceivedComplexity
|
||||
# rubocop:disable Metrics/CyclomaticComplexity
|
||||
def convert_to_speckle_entities(state, speckle_object, entities)
|
||||
return state if entities.empty?
|
||||
|
||||
speckle_id = speckle_object['id']
|
||||
application_id = speckle_object['applicationId']
|
||||
speckle_type = speckle_object['speckle_type']
|
||||
children = speckle_object['__closure'].nil? ? [] : speckle_object['__closure']
|
||||
speckle_state = state.speckle_state
|
||||
entities.each do |entity|
|
||||
next if entity.is_a?(Sketchup::Material) || entity.is_a?(Sketchup::Page)
|
||||
next if (entity.is_a?(Sketchup::Face) || entity.is_a?(Sketchup::Edge)) &&
|
||||
!state.user_state.user_preferences[:register_speckle_entity]
|
||||
|
||||
ent = SpeckleEntities::SpeckleEntity.new(entity, speckle_id, application_id, speckle_type, children,
|
||||
[stream_id])
|
||||
ent.write_initial_base_data
|
||||
speckle_state = speckle_state.with_speckle_entity(ent)
|
||||
end
|
||||
state.with_speckle_state(speckle_state)
|
||||
def convert_to_speckle_entities(state, speckle_objects_with_entities)
|
||||
return state if speckle_objects_with_entities.empty?
|
||||
end
|
||||
# rubocop:enable Metrics/PerceivedComplexity
|
||||
# rubocop:enable Metrics/CyclomaticComplexity
|
||||
end
|
||||
# rubocop:enable Metrics/ClassLength
|
||||
end
|
||||
|
||||
@@ -15,6 +15,7 @@ require_relative '../speckle_objects/relations/layers'
|
||||
require_relative '../speckle_objects/speckle/core/models/model_collection'
|
||||
require_relative '../constants/path_constants'
|
||||
require_relative '../sketchup_model/reader/speckle_entities_reader'
|
||||
require_relative '../sketchup_model/reader/mapper_reader'
|
||||
require_relative '../sketchup_model/query/entity'
|
||||
|
||||
module SpeckleConnector
|
||||
@@ -63,28 +64,24 @@ module SpeckleConnector
|
||||
def convert(entity, preferences, speckle_state, parent = :base)
|
||||
convert = method(:convert)
|
||||
|
||||
unless SketchupModel::Reader::SpeckleEntitiesReader.mapped_with_schema?(entity)
|
||||
unless SketchupModel::Reader::MapperReader.mapped_with_schema?(entity) &&
|
||||
!entity.is_a?(Sketchup::ComponentDefinition)
|
||||
return from_native_to_speckle(entity, preferences, speckle_state, parent, &convert)
|
||||
end
|
||||
|
||||
return speckle_state, nil
|
||||
end
|
||||
|
||||
def from_mapped_to_speckle(entity, path, preferences)
|
||||
direct_shape = SpeckleObjects::BuiltElements::Revit::DirectShape
|
||||
.from_entity(entity, path, @units, preferences)
|
||||
return [direct_shape, [entity]]
|
||||
end
|
||||
|
||||
# rubocop:disable Metrics/MethodLength
|
||||
def from_native_to_speckle(entity, preferences, speckle_state, parent, &convert)
|
||||
if entity.is_a?(Sketchup::Edge)
|
||||
line = SpeckleObjects::Geometry::Line.from_edge(entity, @units, preferences[:model]).to_h
|
||||
line = SpeckleObjects::Geometry::Line.from_edge(speckle_state: speckle_state, edge: entity,
|
||||
units: @units, model_preferences: preferences[:model]).to_h
|
||||
return speckle_state, [line, [entity]]
|
||||
end
|
||||
|
||||
if entity.is_a?(Sketchup::Face)
|
||||
mesh = SpeckleObjects::Geometry::Mesh.from_face(face: entity, units: @units,
|
||||
mesh = SpeckleObjects::Geometry::Mesh.from_face(speckle_state: speckle_state, face: entity, units: @units,
|
||||
model_preferences: preferences[:model])
|
||||
return speckle_state, [mesh, [entity]]
|
||||
end
|
||||
|
||||
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,12 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module SpeckleConnector
|
||||
# Helper module for logging.
|
||||
module Log
|
||||
def self.write_to_file(text, file_name = 'log', path = "#{ENV['HOME']}/Desktop")
|
||||
file_path = path + "/#{file_name}.json"
|
||||
File.delete(file_path) if File.exist?(file_path)
|
||||
File.write(file_path, text)
|
||||
end
|
||||
end
|
||||
end
|
||||
+3
-2
@@ -1,7 +1,7 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module SpeckleConnector
|
||||
module Mapping
|
||||
module Mapper
|
||||
module Category
|
||||
# Revit categories.
|
||||
class RevitCategory < Hash
|
||||
@@ -118,7 +118,8 @@ module SpeckleConnector
|
||||
VibrationManagement: 106,
|
||||
Walls: 107,
|
||||
StructConnectionWelds: 108,
|
||||
Windows: 109
|
||||
Windows: 109,
|
||||
Railings: 110
|
||||
}.freeze
|
||||
end
|
||||
# rubocop:enable Metrics/MethodLength
|
||||
@@ -0,0 +1,79 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module SpeckleConnector
|
||||
module Mapper
|
||||
module Category
|
||||
# Revit categories for families.
|
||||
class RevitFamilyCategory < Hash
|
||||
class << self
|
||||
# rubocop:disable Metrics/MethodLength
|
||||
def dictionary
|
||||
{
|
||||
AudioVisualDevices: 9,
|
||||
CableTrayFitting: 16,
|
||||
Casework: 19,
|
||||
Columns: 21,
|
||||
CommunicationDevices: 22,
|
||||
ConduitFitting: 23,
|
||||
DataDevices: 30,
|
||||
Doors: 32,
|
||||
DuctAccessory: 33,
|
||||
ElectricalEquipment: 38,
|
||||
ElectricalFixtures: 39,
|
||||
Entourage: 40,
|
||||
FireAlarmDevices: 42,
|
||||
FireProtection: 43,
|
||||
FoodServiceEquipment: 45,
|
||||
Furniture: 46,
|
||||
FurnitureSystems: 47,
|
||||
GenericAnnotation: 48,
|
||||
GenericModel: 49,
|
||||
Hardscape: 51,
|
||||
LightingDevices: 52,
|
||||
LightingFixtures: 53,
|
||||
Lines: 54,
|
||||
Mass: 55,
|
||||
MechanicalEquipment: 56,
|
||||
MedicalEquipment: 57,
|
||||
NurseCallDevices: 58,
|
||||
Parking: 59,
|
||||
PipeAccessory: 68,
|
||||
PipeFitting: 69,
|
||||
Planting: 74,
|
||||
PlumbingFixtures: 76,
|
||||
Roads: 80,
|
||||
SecurityDevices: 82,
|
||||
Signage: 84,
|
||||
Site: 85,
|
||||
SpecialityEquipment: 86,
|
||||
Sprinklers: 87,
|
||||
StructuralFramingSystem: 89,
|
||||
StructuralColumns: 90,
|
||||
StructConnections: 91,
|
||||
StructuralFoundation: 93,
|
||||
StructuralFraming: 94,
|
||||
StructuralStiffener: 97,
|
||||
TemporaryStructure: 100,
|
||||
VerticalCirculation: 103,
|
||||
Windows: 109,
|
||||
Railings: 110
|
||||
}.freeze
|
||||
end
|
||||
# rubocop:enable Metrics/MethodLength
|
||||
|
||||
def reverse_dictionary
|
||||
dictionary.collect { |k, v| [v, k] }.to_h
|
||||
end
|
||||
|
||||
def to_a
|
||||
dictionary.collect { |k, v| { key: k, value: v } }.to_a
|
||||
end
|
||||
|
||||
def reverse_to_a
|
||||
dictionary.collect { |k, v| { key: v, value: k } }.to_a
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,127 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative '../speckle_objects/built_elements/revit/revit_floor'
|
||||
require_relative '../speckle_objects/built_elements/revit/revit_wall'
|
||||
require_relative '../speckle_objects/built_elements/revit/direct_shape'
|
||||
require_relative '../speckle_objects/built_elements/revit/revit_column'
|
||||
require_relative '../speckle_objects/built_elements/revit/revit_beam'
|
||||
require_relative '../speckle_objects/built_elements/revit/revit_pipe'
|
||||
require_relative '../speckle_objects/built_elements/revit/revit_duct'
|
||||
require_relative '../speckle_objects/built_elements/default_floor'
|
||||
require_relative '../speckle_objects/built_elements/default_wall'
|
||||
require_relative '../speckle_objects/built_elements/default_column'
|
||||
require_relative '../speckle_objects/built_elements/default_beam'
|
||||
require_relative '../speckle_objects/built_elements/default_duct'
|
||||
require_relative '../speckle_objects/built_elements/default_pipe'
|
||||
require_relative '../speckle_objects/other/mapped_block_wrapper'
|
||||
require_relative '../sketchup_model/query/entity'
|
||||
require_relative '../sketchup_model/reader/mapper_reader'
|
||||
require_relative '../sketchup_model/dictionary/speckle_schema_dictionary_handler'
|
||||
|
||||
module SpeckleConnector
|
||||
# Mapper is a tool to convert SketchUp entities to other applications' native objects.
|
||||
module Mapper
|
||||
QUERY = SketchupModel::Query
|
||||
MAPPER_READER = SketchupModel::Reader::MapperReader
|
||||
SPECKLE_SCHEMA_DICTIONARY_HANDLER = SketchupModel::Dictionary::SpeckleSchemaDictionaryHandler
|
||||
DIRECT_SHAPE = SpeckleObjects::BuiltElements::Revit::DirectShape
|
||||
|
||||
# Collects mapped entities on selection as flat list.
|
||||
def self.mapped_entities_on_selection(sketchup_model)
|
||||
flat_selection_with_path = QUERY::Entity.flat_entities_with_path(
|
||||
sketchup_model.selection,
|
||||
[Sketchup::Edge, Sketchup::Face, Sketchup::ComponentInstance, Sketchup::Group], [sketchup_model]
|
||||
)
|
||||
mapped_selection = []
|
||||
flat_selection_with_path.each do |entities|
|
||||
entity = entities[0]
|
||||
is_entity_mapped = MAPPER_READER.mapped_with_schema?(entity)
|
||||
if entity.respond_to?(:definition)
|
||||
is_definition_mapped = MAPPER_READER.mapped_with_schema?(entity.definition)
|
||||
mapped_selection.append(entities) if is_entity_mapped || is_definition_mapped
|
||||
next
|
||||
end
|
||||
mapped_selection.append(entities) if is_entity_mapped
|
||||
end
|
||||
mapped_selection
|
||||
end
|
||||
|
||||
def self.convert_mapped_entity(speckle_state, entity_with_path, preferences, units, &convert)
|
||||
entity = entity_with_path[0]
|
||||
method = get_method(entity)
|
||||
return nil if method.nil?
|
||||
|
||||
path = entity_with_path[1..-1]
|
||||
|
||||
if face_mapping?(entity, method)
|
||||
global_transformation = QUERY::Entity.global_transformation(entity, path)
|
||||
face = SpeckleObjects::Geometry::Mesh.from_face(speckle_state: speckle_state, face: entity,
|
||||
units: units, model_preferences: preferences,
|
||||
global_transform: global_transformation)
|
||||
return [face, [entity]]
|
||||
end
|
||||
|
||||
if edge_mapping?(entity, method)
|
||||
global_transformation = QUERY::Entity.global_transformation(entity, path)
|
||||
edge = SpeckleObjects::Geometry::Line.from_edge(speckle_state: speckle_state, edge: entity,
|
||||
units: units, model_preferences: preferences,
|
||||
global_transformation: global_transformation)
|
||||
return [edge, [entity]]
|
||||
end
|
||||
|
||||
if method == 'Direct Shape'
|
||||
direct_shape = DIRECT_SHAPE.from_entity(speckle_state, entity, path, units, preferences)
|
||||
return [direct_shape, [entity]]
|
||||
end
|
||||
|
||||
if ['New Revit Family', 'Family Instance'].include?(method)
|
||||
_speckle_state, block_instance = SpeckleObjects::Other::BlockInstance.from_component_instance(
|
||||
entity, units, preferences, speckle_state, path: path, &convert
|
||||
)
|
||||
return [block_instance, [entity]]
|
||||
end
|
||||
|
||||
nil
|
||||
end
|
||||
|
||||
NATIVE_MAPPING_TO_SPECKLE = {
|
||||
'Default Column' => SpeckleObjects::BuiltElements::DefaultColumn.method(:to_speckle_schema),
|
||||
'Default Beam' => SpeckleObjects::BuiltElements::DefaultBeam.method(:to_speckle_schema),
|
||||
'Default Pipe' => SpeckleObjects::BuiltElements::DefaultPipe.method(:to_speckle_schema),
|
||||
'Default Duct' => SpeckleObjects::BuiltElements::DefaultDuct.method(:to_speckle_schema),
|
||||
'Column' => SpeckleObjects::BuiltElements::RevitColumn.method(:to_speckle_schema),
|
||||
'Beam' => SpeckleObjects::BuiltElements::RevitBeam.method(:to_speckle_schema),
|
||||
'Pipe' => SpeckleObjects::BuiltElements::RevitPipe.method(:to_speckle_schema),
|
||||
'Duct' => SpeckleObjects::BuiltElements::RevitDuct.method(:to_speckle_schema)
|
||||
}.freeze
|
||||
|
||||
def self.to_speckle(speckle_state, entity, units, global_transformation: nil)
|
||||
speckle_schema = SPECKLE_SCHEMA_DICTIONARY_HANDLER.speckle_schema_to_speckle(entity)
|
||||
return speckle_schema if speckle_schema.nil?
|
||||
|
||||
to_speckle_schema_method = NATIVE_MAPPING_TO_SPECKLE[speckle_schema['method']]
|
||||
return speckle_schema if to_speckle_schema_method.nil?
|
||||
|
||||
to_speckle_schema_method.call(speckle_state, entity, units, global_transformation: global_transformation)
|
||||
end
|
||||
|
||||
def self.get_method(entity)
|
||||
method = SPECKLE_SCHEMA_DICTIONARY_HANDLER.get_attribute(entity, 'method')
|
||||
return method if method
|
||||
|
||||
if entity.is_a?(Sketchup::ComponentInstance)
|
||||
method = SPECKLE_SCHEMA_DICTIONARY_HANDLER.get_attribute(entity.definition, 'method')
|
||||
end
|
||||
method
|
||||
end
|
||||
|
||||
def self.face_mapping?(entity, method)
|
||||
(method.include?('Floor') || method.include?('Wall')) && entity.is_a?(Sketchup::Face)
|
||||
end
|
||||
|
||||
def self.edge_mapping?(entity, method)
|
||||
(method.include?('Column') || method.include?('Beam') || method.include?('Pipe') || method.include?('Duct')) &&
|
||||
entity.is_a?(Sketchup::Edge)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,34 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative '../immutable/immutable'
|
||||
require_relative '../speckle_objects/built_elements/level'
|
||||
require_relative '../speckle_objects/built_elements/revit/revit_element_type'
|
||||
|
||||
module SpeckleConnector
|
||||
# Mapper is a tool to convert SketchUp entities to other applications' native objects.
|
||||
module Mapper
|
||||
# Mapper source object that collects information about stream id and commit id to identify source in the branch,
|
||||
# also contains levels and family types to be able to map objects with them.
|
||||
class MapperSource
|
||||
# @return [String] stream id of the mapper source.
|
||||
attr_reader :stream_id
|
||||
|
||||
# @return [String] commit id of the mapper source.
|
||||
attr_reader :commit_id
|
||||
|
||||
# @return [Array<SpeckleObjects::BuiltElements::Level>] levels in the source branch.
|
||||
attr_reader :levels
|
||||
|
||||
# @return [ImmutableHash{String=>Array<SpeckleObjects::BuiltElements::Revit::RevitElementType>}] revit element
|
||||
# types.
|
||||
attr_reader :types
|
||||
|
||||
def initialize(stream_id, commit_id, levels, types)
|
||||
@stream_id = stream_id
|
||||
@commit_id = commit_id
|
||||
@levels = levels
|
||||
@types = types
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -12,9 +12,9 @@ module SpeckleConnector
|
||||
include Immutable::ImmutableUtils
|
||||
DICT_HANDLER = SketchupModel::Dictionary::SpeckleModelDictionaryHandler
|
||||
# rubocop:disable Layout/LineLength
|
||||
DEFAULT_CONFIG = "('configSketchup', '{\"dark_theme\":false, \"diffing\":false, \"register_speckle_entity\":false}');"
|
||||
DEFAULT_CONFIG = "('configSketchup', '{\"dark_theme\":false, \"diffing\":false, \"register_speckle_entity\":false, \"fe2\":true}');"
|
||||
# rubocop:enable Layout/LineLength
|
||||
DEFAULT_PREFERENCES = '{"dark_theme":false, "diffing":false, "register_speckle_entity": false}'
|
||||
DEFAULT_PREFERENCES = '{"dark_theme":false, "diffing":false, "register_speckle_entity": false, "fe2": true}'
|
||||
|
||||
# @param sketchup_model [Sketchup::Model] active model.
|
||||
def self.read_preferences(sketchup_model)
|
||||
@@ -34,10 +34,16 @@ module SpeckleConnector
|
||||
def self.data_complete?(row_data)
|
||||
return false if row_data.empty?
|
||||
|
||||
data = JSON.parse(row_data.first.first)
|
||||
return false if data['dark_theme'].nil? || data['diffing'].nil? || data['register_speckle_entity'].nil?
|
||||
begin
|
||||
data = JSON.parse(row_data.first.first)
|
||||
if data['dark_theme'].nil? || data['fe2'].nil? || data['diffing'].nil? || data['register_speckle_entity'].nil?
|
||||
return false
|
||||
end
|
||||
|
||||
true
|
||||
true
|
||||
rescue StandardError
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
# Validates current preferences. If there are incomplete data then this method resets it with default preferences.
|
||||
@@ -65,11 +71,13 @@ module SpeckleConnector
|
||||
data_hash = JSON.parse(row_data).to_h
|
||||
# Get current theme value
|
||||
dark_theme = data_hash['dark_theme']
|
||||
fe2 = data_hash['fe2']
|
||||
diffing = data_hash['diffing']
|
||||
register_speckle_entity = data_hash['register_speckle_entity']
|
||||
|
||||
{
|
||||
dark_theme: dark_theme,
|
||||
fe2: fe2,
|
||||
diffing: diffing,
|
||||
register_speckle_entity: register_speckle_entity
|
||||
}.freeze
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative '../dictionary/speckle_schema_dictionary_handler'
|
||||
require_relative '../../speckle_entities/speckle_entity'
|
||||
require_relative '../../mapper/category/revit_category'
|
||||
require_relative '../../constants/dict_constants'
|
||||
|
||||
module SpeckleConnector
|
||||
# Operations related to {SketchupModel}.
|
||||
module SketchupModel
|
||||
# Reader model for sketchup model.
|
||||
module Reader
|
||||
# Reader module for mapper.
|
||||
module MapperReader
|
||||
# @param entities [Sketchup::Entities] entities to collect mapped entities.
|
||||
# @return [Hash{String=>Sketchup::Entity}] mapped entities with persistent id.
|
||||
def self.read_mapped_entities(entities)
|
||||
mapped_entities = {}
|
||||
Query::Entity.flat_entities(entities).each do |entity|
|
||||
mapped_entities[entity.persistent_id] = entity if mapped_with_schema?(entity)
|
||||
end
|
||||
mapped_entities
|
||||
end
|
||||
|
||||
# @param entity [Sketchup::Entity] sketchup entity to check whether mapped with speckle schema or not.
|
||||
def self.mapped_with_schema?(entity)
|
||||
is_entity_mapped = !Dictionary::SpeckleSchemaDictionaryHandler.attribute_dictionary(entity).nil?
|
||||
return is_entity_mapped if is_entity_mapped
|
||||
return is_entity_mapped unless entity.is_a?(Sketchup::ComponentInstance)
|
||||
|
||||
!Dictionary::SpeckleSchemaDictionaryHandler.attribute_dictionary(entity.definition).nil?
|
||||
end
|
||||
|
||||
def self.get_schema(entity)
|
||||
Dictionary::SpeckleSchemaDictionaryHandler.speckle_schema_to_speckle(entity)
|
||||
end
|
||||
|
||||
def self.entities_schema_details(entities)
|
||||
entities.collect do |entity|
|
||||
entity_selection_details = entity_selection_details(entity)
|
||||
if entity.is_a?(Sketchup::ComponentInstance)
|
||||
entity_selection_details = entity_selection_details.merge(
|
||||
{ definition: entity_selection_details(entity.definition) }
|
||||
)
|
||||
end
|
||||
entity_selection_details
|
||||
end
|
||||
end
|
||||
|
||||
def self.entity_selection_details(entity)
|
||||
sanitized_type = entity.class.name.split('::').last.gsub(/(?<=[a-z])(?=[A-Z])/, ' ').split
|
||||
is_definition = entity.is_a?(Sketchup::ComponentDefinition)
|
||||
entity_type = is_definition ? sanitized_type.last : sanitized_type.first
|
||||
speckle_schema = get_schema(entity)
|
||||
{
|
||||
name: speckle_schema['name'],
|
||||
entityName: entity.respond_to?(:name) ? entity.name : '',
|
||||
entityId: entity.persistent_id,
|
||||
entityType: entity_type,
|
||||
schema: speckle_schema,
|
||||
numberOfInstances: is_definition ? entity.instances.length : 1
|
||||
}
|
||||
end
|
||||
|
||||
def self.mapped_entity_details(entities)
|
||||
reverse_category_dictionary = Mapper::Category::RevitCategory.reverse_dictionary
|
||||
entities.collect do |entity|
|
||||
speckle_schema = get_schema(entity)
|
||||
speckle_schema_definition = entity.respond_to?(:definition) ? get_schema(entity.definition) : nil
|
||||
entity_type = entity.class.name.split('::').last.gsub(/(?<=[a-z])(?=[A-Z])/, ' ').split.first
|
||||
category = get_map_attribute(speckle_schema, speckle_schema_definition, 'category')
|
||||
{
|
||||
name: get_map_attribute(speckle_schema, speckle_schema_definition, 'name'),
|
||||
category: category,
|
||||
categoryName: category.nil? ? '' : reverse_category_dictionary[category],
|
||||
method: get_map_attribute(speckle_schema, speckle_schema_definition, 'method'),
|
||||
entityName: entity.respond_to?(:name) ? entity.name : '',
|
||||
entityId: entity.persistent_id,
|
||||
entityType: entity.is_a?(Sketchup::ComponentDefinition) ? 'Definition' : entity_type,
|
||||
schema: speckle_schema,
|
||||
definitionSchema: speckle_schema_definition
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
def self.get_map_attribute(schema, definition_schema, attribute)
|
||||
return schema[attribute] if schema[attribute]
|
||||
return definition_schema[attribute] if !definition_schema.nil? && definition_schema[attribute]
|
||||
|
||||
nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
require_relative '../dictionary/speckle_schema_dictionary_handler'
|
||||
require_relative '../../speckle_entities/speckle_entity'
|
||||
require_relative '../../mapping/category/revit_category'
|
||||
require_relative '../../mapper/category/revit_category'
|
||||
require_relative '../../constants/dict_constants'
|
||||
|
||||
module SpeckleConnector
|
||||
@@ -29,16 +29,6 @@ module SpeckleConnector
|
||||
speckle_entities
|
||||
end
|
||||
|
||||
# @param entities [Sketchup::Entities] entities to collect mapped entities.
|
||||
# @return [Hash{String=>Sketchup::Entity}] mapped entities with persistent id.
|
||||
def self.read_mapped_entities(entities)
|
||||
mapped_entities = {}
|
||||
Query::Entity.flat_entities(entities).each do |entity|
|
||||
mapped_entities[entity.persistent_id] = entity if mapped_with_schema?(entity)
|
||||
end
|
||||
mapped_entities
|
||||
end
|
||||
|
||||
# @param entity [Sketchup::Entity] sketchup entity to read from attribute dictionary.
|
||||
def self.read_speckle_entity(entity)
|
||||
dict = entity.attribute_dictionaries.to_a.find { |d| d.name == SPECKLE_BASE_OBJECT }
|
||||
@@ -60,70 +50,7 @@ module SpeckleConnector
|
||||
entity.attribute_dictionaries.to_a.any? { |dict| dict.name == SPECKLE_BASE_OBJECT }
|
||||
end
|
||||
|
||||
# @param entity [Sketchup::Entity] sketchup entity to check whether mapped with speckle schema or not.
|
||||
def self.mapped_with_schema?(entity)
|
||||
is_entity_mapped = !Dictionary::SpeckleSchemaDictionaryHandler.attribute_dictionary(entity).nil?
|
||||
return is_entity_mapped if is_entity_mapped
|
||||
return is_entity_mapped unless entity.is_a?(Sketchup::ComponentInstance)
|
||||
|
||||
!Dictionary::SpeckleSchemaDictionaryHandler.attribute_dictionary(entity.definition).nil?
|
||||
end
|
||||
|
||||
def self.get_schema(entity)
|
||||
Dictionary::SpeckleSchemaDictionaryHandler.speckle_schema_to_speckle(entity)
|
||||
end
|
||||
|
||||
def self.entities_schema_details(entities)
|
||||
entities.collect do |entity|
|
||||
entity_selection_details = entity_selection_details(entity)
|
||||
if entity.is_a?(Sketchup::ComponentInstance)
|
||||
entity_selection_details = entity_selection_details.merge(
|
||||
{ definition: entity_selection_details(entity.definition) }
|
||||
)
|
||||
end
|
||||
entity_selection_details
|
||||
end
|
||||
end
|
||||
|
||||
def self.entity_selection_details(entity)
|
||||
sanitized_type = entity.class.name.split('::').last.gsub(/(?<=[a-z])(?=[A-Z])/, ' ').split
|
||||
is_definition = entity.is_a?(Sketchup::ComponentDefinition)
|
||||
entity_type = is_definition ? sanitized_type.last : sanitized_type.first
|
||||
speckle_schema = get_schema(entity)
|
||||
{
|
||||
name: speckle_schema['name'],
|
||||
entityName: entity.respond_to?(:name) ? entity.name : '',
|
||||
entityId: entity.persistent_id,
|
||||
entityType: entity_type,
|
||||
schema: speckle_schema,
|
||||
numberOfInstances: is_definition ? entity.instances.length : 1
|
||||
}
|
||||
end
|
||||
|
||||
# rubocop:disable Metrics/CyclomaticComplexity
|
||||
# rubocop:disable Metrics/PerceivedComplexity
|
||||
def self.mapped_entity_details(entities)
|
||||
reverse_category_dictionary = Mapping::Category::RevitCategory.reverse_dictionary
|
||||
entities.collect do |entity|
|
||||
speckle_schema = get_schema(entity)
|
||||
speckle_schema_definition = entity.respond_to?(:definition) ? get_schema(entity.definition) : nil
|
||||
entity_type = entity.class.name.split('::').last.gsub(/(?<=[a-z])(?=[A-Z])/, ' ').split.first
|
||||
{
|
||||
name: speckle_schema['name'] || speckle_schema_definition['name'],
|
||||
category: speckle_schema['category'] || speckle_schema_definition['category'],
|
||||
categoryName: reverse_category_dictionary[speckle_schema['category']] ||
|
||||
reverse_category_dictionary[speckle_schema_definition['category']],
|
||||
method: speckle_schema['method'] || speckle_schema_definition['method'],
|
||||
entityName: entity.respond_to?(:name) ? entity.name : '',
|
||||
entityId: entity.persistent_id,
|
||||
entityType: entity.is_a?(Sketchup::ComponentDefinition) ? 'Definition' : entity_type,
|
||||
schema: speckle_schema,
|
||||
definitionSchema: speckle_schema_definition
|
||||
}
|
||||
end
|
||||
end
|
||||
# rubocop:enable Metrics/CyclomaticComplexity
|
||||
# rubocop:enable Metrics/PerceivedComplexity
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative '../../constants/geo_constants'
|
||||
|
||||
module SpeckleConnector
|
||||
# Operations related to {SketchupModel}.
|
||||
module SketchupModel
|
||||
@@ -24,6 +26,13 @@ module SpeckleConnector
|
||||
end
|
||||
adj_faces.uniq
|
||||
end
|
||||
|
||||
# @param face [Sketchup::Face] face to get max z distance for all vertices.
|
||||
def self.max_z(face)
|
||||
points = face.vertices.collect(&:position)
|
||||
points_z_values = points.collect(&:z)
|
||||
points_z_values.max - points_z_values.min
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -119,6 +119,41 @@ module SpeckleConnector
|
||||
def valid?
|
||||
sketchup_entity.valid?
|
||||
end
|
||||
|
||||
# @param state [States::State] state of the application
|
||||
# rubocop:disable Metrics/PerceivedComplexity
|
||||
# rubocop:disable Metrics/CyclomaticComplexity
|
||||
def self.from_speckle_object(state, speckle_object, entities, stream_id)
|
||||
return state, [] if entities.empty?
|
||||
|
||||
speckle_id = speckle_object['id']
|
||||
application_id = speckle_object['applicationId']
|
||||
speckle_type = speckle_object['speckle_type']
|
||||
children = speckle_object['__closure'].nil? ? [] : speckle_object['__closure']
|
||||
speckle_state = state.speckle_state
|
||||
entities.each do |entity|
|
||||
next if entity.is_a?(Sketchup::Material) || entity.is_a?(Sketchup::Page)
|
||||
next if (entity.is_a?(Sketchup::Face) || entity.is_a?(Sketchup::Edge)) &&
|
||||
!state.user_state.user_preferences[:register_speckle_entity]
|
||||
|
||||
if entity.is_a?(Sketchup::ComponentDefinition)
|
||||
definition = speckle_object['definition'] || speckle_object['@block_definition'] ||
|
||||
speckle_object['block_definition']
|
||||
if definition
|
||||
speckle_id = definition['id']
|
||||
speckle_type = definition['speckle_type']
|
||||
end
|
||||
end
|
||||
|
||||
ent = SpeckleEntity.new(entity, speckle_id, application_id, speckle_type, children, [stream_id])
|
||||
ent.write_initial_base_data
|
||||
speckle_state = speckle_state.with_speckle_entity(ent)
|
||||
end
|
||||
new_state = state.with_speckle_state(speckle_state)
|
||||
return new_state, entities
|
||||
end
|
||||
# rubocop:enable Metrics/PerceivedComplexity
|
||||
# rubocop:enable Metrics/CyclomaticComplexity
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative '../base'
|
||||
require_relative '../geometry/line'
|
||||
require_relative '../../constants/type_constants'
|
||||
require_relative '../../sketchup_model/dictionary/speckle_schema_dictionary_handler'
|
||||
|
||||
module SpeckleConnector
|
||||
module SpeckleObjects
|
||||
module BuiltElements
|
||||
# Default Beam object.
|
||||
class DefaultBeam < Base
|
||||
SPECKLE_TYPE = OBJECTS_BUILTELEMENTS_DEFAULT_BEAM
|
||||
|
||||
def initialize(base_line:, units:, application_id: nil)
|
||||
super(
|
||||
speckle_type: SPECKLE_TYPE,
|
||||
total_children_count: 0,
|
||||
application_id: application_id,
|
||||
id: nil
|
||||
)
|
||||
self[:baseLine] = base_line
|
||||
self[:units] = units
|
||||
end
|
||||
|
||||
# @param edge [Sketchup::Edge] edge to get speckle schema for beam.
|
||||
def self.to_speckle_schema(_speckle_state, edge, units, global_transformation: nil)
|
||||
base_line = Geometry::Line.to_speckle_schema(edge: edge, units: units)
|
||||
|
||||
DefaultBeam.new(
|
||||
base_line: base_line,
|
||||
units: units,
|
||||
application_id: edge.persistent_id
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,39 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative '../base'
|
||||
require_relative '../geometry/line'
|
||||
require_relative '../../constants/type_constants'
|
||||
require_relative '../../sketchup_model/dictionary/speckle_schema_dictionary_handler'
|
||||
|
||||
module SpeckleConnector
|
||||
module SpeckleObjects
|
||||
module BuiltElements
|
||||
# Default Column object.
|
||||
class DefaultColumn < Base
|
||||
SPECKLE_TYPE = OBJECTS_BUILTELEMENTS_DEFAULT_COLUMN
|
||||
|
||||
def initialize(base_line:, units:, application_id: nil)
|
||||
super(
|
||||
speckle_type: SPECKLE_TYPE,
|
||||
total_children_count: 0,
|
||||
application_id: application_id,
|
||||
id: nil
|
||||
)
|
||||
self[:baseLine] = base_line
|
||||
self[:units] = units
|
||||
end
|
||||
|
||||
# @param edge [Sketchup::Edge] edge to get speckle schema for column.
|
||||
def self.to_speckle_schema(_speckle_state, edge, units, global_transformation: nil)
|
||||
base_line = Geometry::Line.to_speckle_schema(edge: edge, units: units)
|
||||
|
||||
DefaultColumn.new(
|
||||
base_line: base_line,
|
||||
units: units,
|
||||
application_id: edge.persistent_id
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,39 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative '../base'
|
||||
require_relative '../geometry/line'
|
||||
require_relative '../../constants/type_constants'
|
||||
require_relative '../../sketchup_model/dictionary/speckle_schema_dictionary_handler'
|
||||
|
||||
module SpeckleConnector
|
||||
module SpeckleObjects
|
||||
module BuiltElements
|
||||
# Default Duct object.
|
||||
class DefaultDuct < Base
|
||||
SPECKLE_TYPE = OBJECTS_BUILTELEMENTS_DEFAULT_DUCT
|
||||
|
||||
def initialize(base_line:, units:, application_id: nil)
|
||||
super(
|
||||
speckle_type: SPECKLE_TYPE,
|
||||
total_children_count: 0,
|
||||
application_id: application_id,
|
||||
id: nil
|
||||
)
|
||||
self[:baseLine] = base_line
|
||||
self[:units] = units
|
||||
end
|
||||
|
||||
# @param edge [Sketchup::Edge] edge to get speckle schema for duct.
|
||||
def self.to_speckle_schema(_speckle_state, edge, units, global_transformation: nil)
|
||||
base_line = Geometry::Line.to_speckle_schema(edge: edge, units: units)
|
||||
|
||||
DefaultDuct.new(
|
||||
base_line: base_line,
|
||||
units: units,
|
||||
application_id: edge.persistent_id
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,53 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative '../base'
|
||||
require_relative '../built_elements/revit/parameter'
|
||||
require_relative '../other/render_material'
|
||||
require_relative '../geometry/line'
|
||||
require_relative '../geometry/polyline'
|
||||
require_relative '../../constants/type_constants'
|
||||
require_relative '../../sketchup_model/dictionary/speckle_schema_dictionary_handler'
|
||||
|
||||
module SpeckleConnector
|
||||
module SpeckleObjects
|
||||
module BuiltElements
|
||||
# Default Floor object.
|
||||
class DefaultFloor < Base
|
||||
SPECKLE_TYPE = OBJECTS_BUILTELEMENTS_DEFAULT_FLOOR
|
||||
|
||||
def initialize(outline:, voids:, units:, material:, application_id: nil)
|
||||
super(
|
||||
speckle_type: SPECKLE_TYPE,
|
||||
total_children_count: 0,
|
||||
application_id: application_id,
|
||||
id: nil
|
||||
)
|
||||
self[:outline] = outline
|
||||
self[:voids] = voids
|
||||
self[:units] = units
|
||||
self[:renderMaterial] = material
|
||||
end
|
||||
|
||||
# @param face [Sketchup::Face] face to get speckle schema for floor.
|
||||
def self.to_speckle_schema(_speckle_state, face, units, global_transformation: nil)
|
||||
outline = Geometry::Polyline.from_loop(face.loops.first, units, global_transformation: global_transformation)
|
||||
voids = []
|
||||
if face.loops.length > 1
|
||||
voids = face.loops[1..face.loops.length - 1].collect do |loop|
|
||||
Geometry::Polyline.from_loop(loop, units, global_transformation: global_transformation)
|
||||
end
|
||||
end
|
||||
material = face.material || face.back_material
|
||||
|
||||
DefaultFloor.new(
|
||||
outline: outline,
|
||||
voids: voids,
|
||||
units: units,
|
||||
material: material.nil? ? nil : Other::RenderMaterial.from_material(face.material || face.back_material),
|
||||
application_id: face.persistent_id
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,39 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative '../base'
|
||||
require_relative '../geometry/line'
|
||||
require_relative '../../constants/type_constants'
|
||||
require_relative '../../sketchup_model/dictionary/speckle_schema_dictionary_handler'
|
||||
|
||||
module SpeckleConnector
|
||||
module SpeckleObjects
|
||||
module BuiltElements
|
||||
# Default Pipe object.
|
||||
class DefaultPipe < Base
|
||||
SPECKLE_TYPE = OBJECTS_BUILTELEMENTS_DEFAULT_PIPE
|
||||
|
||||
def initialize(base_line:, units:, application_id: nil)
|
||||
super(
|
||||
speckle_type: SPECKLE_TYPE,
|
||||
total_children_count: 0,
|
||||
application_id: application_id,
|
||||
id: nil
|
||||
)
|
||||
self[:baseLine] = base_line
|
||||
self[:units] = units
|
||||
end
|
||||
|
||||
# @param edge [Sketchup::Edge] edge to get speckle schema for pipe.
|
||||
def self.to_speckle_schema(_speckle_state, edge, units, global_transformation: nil)
|
||||
base_line = Geometry::Line.to_speckle_schema(edge: edge, units: units)
|
||||
|
||||
DefaultPipe.new(
|
||||
base_line: base_line,
|
||||
units: units,
|
||||
application_id: edge.persistent_id
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,52 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative '../base'
|
||||
require_relative '../built_elements/revit/parameter'
|
||||
require_relative '../other/render_material'
|
||||
require_relative '../geometry/length'
|
||||
require_relative '../geometry/line'
|
||||
require_relative '../geometry/polyline'
|
||||
require_relative '../../constants/type_constants'
|
||||
require_relative '../../sketchup_model/dictionary/speckle_schema_dictionary_handler'
|
||||
require_relative '../../sketchup_model/utils/face_utils'
|
||||
|
||||
module SpeckleConnector
|
||||
module SpeckleObjects
|
||||
module BuiltElements
|
||||
# Default Wall object.
|
||||
class DefaultWall < Base
|
||||
SPECKLE_TYPE = OBJECTS_BUILTELEMENTS_DEFAULT_WALL
|
||||
|
||||
def initialize(base_line:, height:, flipped:, units:, material:, application_id: nil)
|
||||
super(
|
||||
speckle_type: SPECKLE_TYPE,
|
||||
total_children_count: 0,
|
||||
application_id: application_id,
|
||||
id: nil
|
||||
)
|
||||
self[:baseLine] = base_line
|
||||
self[:height] = height
|
||||
self[:flipped] = flipped
|
||||
self[:units] = units
|
||||
self[:renderMaterial] = material
|
||||
end
|
||||
|
||||
# @param face [Sketchup::Face] face to get speckle schema for floor.
|
||||
def self.to_speckle_schema(_speckle_state, face, units, global_transformation: nil)
|
||||
base_line = Geometry::Line.base_line_from_face(face, units, global_transformation: global_transformation)
|
||||
|
||||
material = face.material || face.back_material
|
||||
|
||||
DefaultWall.new(
|
||||
base_line: base_line,
|
||||
height: Geometry.length_to_speckle(SketchupModel::Utils::FaceUtils.max_z(face), units),
|
||||
flipped: false,
|
||||
units: units,
|
||||
material: material.nil? ? nil : Other::RenderMaterial.from_material(face.material || face.back_material),
|
||||
application_id: face.persistent_id
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,84 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative '../base'
|
||||
require_relative '../other/render_material'
|
||||
require_relative '../geometry/line'
|
||||
require_relative '../geometry/length'
|
||||
require_relative '../geometry/polyline'
|
||||
require_relative '../../constants/type_constants'
|
||||
require_relative '../../sketchup_model/dictionary/speckle_entity_dictionary_handler'
|
||||
|
||||
module SpeckleConnector
|
||||
module SpeckleObjects
|
||||
module BuiltElements
|
||||
# Level object.
|
||||
class Level < Base
|
||||
SPECKLE_TYPE = OBJECTS_BUILTELEMENTS_REVIT_LEVEL
|
||||
|
||||
def initialize(name:, elevation:, units:, element_id:, application_id: nil, id: nil)
|
||||
super(
|
||||
speckle_type: SPECKLE_TYPE,
|
||||
total_children_count: 0,
|
||||
application_id: application_id,
|
||||
id: id
|
||||
)
|
||||
self[:name] = name
|
||||
self[:elevation] = elevation
|
||||
self[:units] = units
|
||||
self[:elementId] = element_id
|
||||
self[:referenceOnly] = true
|
||||
self[:createView] = false
|
||||
end
|
||||
|
||||
# @param state [States::State] state of the application.
|
||||
def self.to_native(state, speckle_level, stream_id)
|
||||
sketchup_model = state.sketchup_state.sketchup_model
|
||||
levels_layer = sketchup_model.layers.layers.find { |layer| layer.display_name == 'Levels' }
|
||||
levels_layer = sketchup_model.layers.add('Levels') if levels_layer.nil?
|
||||
|
||||
name = speckle_level['name']
|
||||
elevation = speckle_level['elevation']
|
||||
units = speckle_level['units']
|
||||
element_id = speckle_level['elementId']
|
||||
application_id = speckle_level['applicationId']
|
||||
id = speckle_level['id']
|
||||
|
||||
skp_elevation = Geometry.length_to_native(elevation, units)
|
||||
|
||||
definition_name = "#{name}-#{application_id}"
|
||||
definition = sketchup_model.definitions.find { |definition| definition.name == definition_name }
|
||||
definition.entities.clear! unless definition.nil?
|
||||
definition = sketchup_model.definitions.add(definition_name) if definition.nil?
|
||||
instance = sketchup_model.entities.add_instance(definition, Geom::Transformation.new)
|
||||
instance.locked = true
|
||||
SketchupModel::Dictionary::SpeckleEntityDictionaryHandler.write_initial_base_data(
|
||||
instance, application_id, id, SPECKLE_TYPE, [], stream_id
|
||||
)
|
||||
SketchupModel::Dictionary::SpeckleEntityDictionaryHandler.set_attribute(instance, :name, name)
|
||||
|
||||
SketchupModel::Dictionary::SpeckleEntityDictionaryHandler.write_initial_base_data(
|
||||
definition, application_id, id, SPECKLE_TYPE, [], stream_id
|
||||
)
|
||||
SketchupModel::Dictionary::SpeckleEntityDictionaryHandler.set_attribute(definition, :name, name)
|
||||
|
||||
c1_e = Geom::Point3d.new(0, 10.m, skp_elevation)
|
||||
c2_e = Geom::Point3d.new(0, 0, skp_elevation)
|
||||
c3_e = Geom::Point3d.new(10.m, 0, skp_elevation)
|
||||
cline_1 = definition.entities.add_cline(c1_e, c2_e)
|
||||
cline_2 = definition.entities.add_cline(c2_e, c3_e)
|
||||
text = definition.entities.add_text(" #{name}", c1_e)
|
||||
[cline_1, cline_2, text, definition, instance].each { |o| o.layer = levels_layer }
|
||||
|
||||
Level.new(
|
||||
name: name,
|
||||
elevation: elevation,
|
||||
units: units,
|
||||
element_id: element_id,
|
||||
application_id: application_id,
|
||||
id: speckle_level['id']
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -12,7 +12,7 @@ module SpeckleConnector
|
||||
|
||||
def self.to_native(state, network, layer, entities, &convert_to_native)
|
||||
network['elements'].each do |element|
|
||||
state = convert_to_native.call(state, element['elements'], layer, entities)
|
||||
state, _converted_entities = convert_to_native.call(state, element['elements'], layer, entities)
|
||||
end
|
||||
|
||||
return state, []
|
||||
|
||||
@@ -7,7 +7,7 @@ require_relative '../../other/block_definition'
|
||||
require_relative '../../other/transform'
|
||||
require_relative '../../../constants/type_constants'
|
||||
require_relative '../../../sketchup_model/query/entity'
|
||||
require_relative '../../../sketchup_model/reader/speckle_entities_reader'
|
||||
require_relative '../../../sketchup_model/reader/mapper_reader'
|
||||
require_relative '../../../sketchup_model/dictionary/speckle_schema_dictionary_handler'
|
||||
|
||||
module SpeckleConnector
|
||||
@@ -78,9 +78,9 @@ module SpeckleConnector
|
||||
mapped_selection = []
|
||||
flat_selection_with_path.each do |entities|
|
||||
entity = entities[0]
|
||||
is_entity_mapped = READER::SpeckleEntitiesReader.mapped_with_schema?(entity)
|
||||
is_entity_mapped = READER::MapperReader.mapped_with_schema?(entity)
|
||||
if entity.respond_to?(:definition)
|
||||
is_definition_mapped = READER::SpeckleEntitiesReader.mapped_with_schema?(entity.definition)
|
||||
is_definition_mapped = READER::MapperReader.mapped_with_schema?(entity.definition)
|
||||
mapped_selection.append(entities) if is_entity_mapped || is_definition_mapped
|
||||
next
|
||||
end
|
||||
@@ -89,7 +89,7 @@ module SpeckleConnector
|
||||
mapped_selection
|
||||
end
|
||||
|
||||
def self.from_entity(entity, path, units, preferences)
|
||||
def self.from_entity(speckle_state, entity, path, units, model_preferences)
|
||||
schema = DICTIONARY::SpeckleSchemaDictionaryHandler.attribute_dictionary(entity)
|
||||
if schema.nil? && entity.respond_to?(:definition)
|
||||
schema = DICTIONARY::SpeckleSchemaDictionaryHandler.attribute_dictionary(entity.definition)
|
||||
@@ -103,7 +103,14 @@ module SpeckleConnector
|
||||
entity.definition.entities, [Sketchup::Face], path.append(entity)
|
||||
)
|
||||
end
|
||||
base_geometries = group_faces_under_mesh_by_material(entities_with_path, units, preferences)
|
||||
base_geometries = if entity.is_a?(Sketchup::Edge)
|
||||
[Geometry::Line.from_edge(speckle_state: speckle_state, edge: entity, units: units,
|
||||
model_preferences: model_preferences,
|
||||
global_transformation: nil)]
|
||||
else
|
||||
group_faces_under_mesh_by_material(speckle_state, entities_with_path, units,
|
||||
model_preferences)
|
||||
end
|
||||
DirectShape.new(
|
||||
name: schema[:name], category: schema[:category], units: units,
|
||||
base_geometries: base_geometries, application_id: entity.persistent_id
|
||||
@@ -111,13 +118,13 @@ module SpeckleConnector
|
||||
end
|
||||
|
||||
# rubocop:disable Metrics/MethodLength
|
||||
def self.group_faces_under_mesh_by_material(faces_with_path, units, preferences)
|
||||
def self.group_faces_under_mesh_by_material(speckle_state, faces_with_path, units, model_preferences)
|
||||
mesh_groups = {}
|
||||
faces_with_path.each do |face_with_path|
|
||||
face = face_with_path[0]
|
||||
entity_path = face_with_path[1..-1]
|
||||
parent_material = QUERY::Entity.parent_material(entity_path)
|
||||
mesh_group_id = Geometry::Mesh.get_mesh_group_id(face, preferences[:model], parent_material)
|
||||
mesh_group_id = Geometry::Mesh.get_mesh_group_id(face, model_preferences, parent_material)
|
||||
|
||||
if mesh_groups.key?(mesh_group_id)
|
||||
mesh_group = mesh_groups[mesh_group_id]
|
||||
@@ -125,7 +132,8 @@ module SpeckleConnector
|
||||
mesh_group[1].append(face)
|
||||
else
|
||||
mesh = Geometry::Mesh.from_face(
|
||||
face: face, units: units, model_preferences: preferences[:model],
|
||||
speckle_state: speckle_state,
|
||||
face: face, units: units, model_preferences: model_preferences,
|
||||
global_transform: QUERY::Entity.global_transformation(face, entity_path),
|
||||
parent_material: parent_material
|
||||
)
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative '../../base'
|
||||
require_relative '../../../constants/type_constants'
|
||||
|
||||
module SpeckleConnector
|
||||
module SpeckleObjects
|
||||
module BuiltElements
|
||||
module Revit
|
||||
# Family instance for Revit mappings.
|
||||
class FamilyInstance < Base
|
||||
SPECKLE_TYPE = OBJECTS_BUILTELEMENTS_REVIT_FAMILY_INSTANCE
|
||||
|
||||
# rubocop:disable Metrics/ParameterLists
|
||||
def initialize(family:, type:, level:, units:, base_point:, rotation:, application_id: nil)
|
||||
super(
|
||||
speckle_type: SPECKLE_TYPE,
|
||||
total_children_count: 0,
|
||||
application_id: application_id,
|
||||
id: nil
|
||||
)
|
||||
self[:family] = family
|
||||
self[:type] = type
|
||||
self[:level] = level
|
||||
self[:units] = units
|
||||
self[:basePoint] = base_point
|
||||
self[:rotation] = rotation
|
||||
end
|
||||
# rubocop:enable Metrics/ParameterLists
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,26 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative '../../base'
|
||||
require_relative '../../../constants/type_constants'
|
||||
|
||||
module SpeckleConnector
|
||||
module SpeckleObjects
|
||||
module BuiltElements
|
||||
module Revit
|
||||
# Revit parameter.
|
||||
class Parameter < Base
|
||||
SPECKLE_TYPE = OBJECTS_BUILTELEMENTS_REVIT_PARAMETER
|
||||
def initialize(name:, application_id: nil)
|
||||
super(
|
||||
speckle_type: SPECKLE_TYPE,
|
||||
total_children_count: 0,
|
||||
application_id: application_id,
|
||||
id: id
|
||||
)
|
||||
self[:name] = name
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,63 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative '../../base'
|
||||
require_relative '../../built_elements/revit/parameter'
|
||||
require_relative '../../geometry/line'
|
||||
require_relative '../../../constants/type_constants'
|
||||
require_relative '../../../sketchup_model/dictionary/speckle_schema_dictionary_handler'
|
||||
|
||||
module SpeckleConnector
|
||||
module SpeckleObjects
|
||||
module BuiltElements
|
||||
# Revit base object.
|
||||
class RevitBeam < Base
|
||||
SPECKLE_TYPE = OBJECTS_BUILTELEMENTS_REVIT_BEAM
|
||||
|
||||
# rubocop:disable Metrics/ParameterLists
|
||||
def initialize(family:, type:, base_line:, level:, units:, parameters:, application_id: nil)
|
||||
super(
|
||||
speckle_type: SPECKLE_TYPE,
|
||||
total_children_count: 0,
|
||||
application_id: application_id,
|
||||
id: nil
|
||||
)
|
||||
self[:family] = family
|
||||
self[:type] = type
|
||||
self[:level] = level
|
||||
self[:baseLine] = base_line
|
||||
self[:units] = units
|
||||
self[:parameters] = parameters
|
||||
end
|
||||
# rubocop:enable Metrics/ParameterLists
|
||||
|
||||
# @param edge [Sketchup::Edge] edge to get speckle schema for beam.
|
||||
def self.to_speckle_schema(speckle_state, edge, units, global_transformation: nil)
|
||||
base_line = Geometry::Line.to_speckle_schema(edge: edge, units: units)
|
||||
schema = SketchupModel::Dictionary::SpeckleSchemaDictionaryHandler.speckle_schema_to_speckle(edge).to_h
|
||||
source_exist = !speckle_state.speckle_mapper_state.mapper_source.nil?
|
||||
level = nil
|
||||
if source_exist
|
||||
level = speckle_state.speckle_mapper_state.mapper_source.levels.find { |l| l[:name] == schema['level'] }
|
||||
parameters = Base.new
|
||||
offset_parameter = BuiltElements::Revit::Parameter.new(name: 'Height Offset From Level')
|
||||
level_z = Geometry.length_to_native(level[:elevation], level[:units])
|
||||
min_z = [edge.start.position, edge.end.position].map(&:z).min
|
||||
offset_parameter['value'] = Geometry.length_to_speckle(min_z - level_z, units)
|
||||
offset_parameter['units'] = units
|
||||
parameters['Height Offset From Level'] = offset_parameter
|
||||
end
|
||||
|
||||
RevitBeam.new(
|
||||
family: schema['family'],
|
||||
type: schema['family_type'],
|
||||
base_line: base_line,
|
||||
level: level,
|
||||
units: units,
|
||||
parameters: parameters,
|
||||
application_id: edge.persistent_id
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,63 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative '../../base'
|
||||
require_relative '../../built_elements/revit/parameter'
|
||||
require_relative '../../geometry/line'
|
||||
require_relative '../../../constants/type_constants'
|
||||
require_relative '../../../sketchup_model/dictionary/speckle_schema_dictionary_handler'
|
||||
|
||||
module SpeckleConnector
|
||||
module SpeckleObjects
|
||||
module BuiltElements
|
||||
# Revit column object.
|
||||
class RevitColumn < Base
|
||||
SPECKLE_TYPE = OBJECTS_BUILTELEMENTS_REVIT_COLUMN
|
||||
|
||||
# rubocop:disable Metrics/ParameterLists
|
||||
def initialize(family:, type:, base_line:, level:, units:, parameters:, application_id: nil)
|
||||
super(
|
||||
speckle_type: SPECKLE_TYPE,
|
||||
total_children_count: 0,
|
||||
application_id: application_id,
|
||||
id: nil
|
||||
)
|
||||
self[:family] = family
|
||||
self[:type] = type
|
||||
self[:level] = level
|
||||
self[:baseLine] = base_line
|
||||
self[:units] = units
|
||||
self[:parameters] = parameters
|
||||
end
|
||||
# rubocop:enable Metrics/ParameterLists
|
||||
|
||||
# @param edge [Sketchup::Edge] edge to get speckle schema for column.
|
||||
def self.to_speckle_schema(speckle_state, edge, units, global_transformation: nil)
|
||||
base_line = Geometry::Line.to_speckle_schema(edge: edge, units: units)
|
||||
schema = SketchupModel::Dictionary::SpeckleSchemaDictionaryHandler.speckle_schema_to_speckle(edge).to_h
|
||||
source_exist = !speckle_state.speckle_mapper_state.mapper_source.nil?
|
||||
level = nil
|
||||
if source_exist
|
||||
level = speckle_state.speckle_mapper_state.mapper_source.levels.find { |l| l[:name] == schema['level'] }
|
||||
parameters = Base.new
|
||||
offset_parameter = BuiltElements::Revit::Parameter.new(name: 'Height Offset From Level')
|
||||
level_z = Geometry.length_to_native(level[:elevation], level[:units])
|
||||
min_z = [edge.start.position, edge.end.position].map(&:z).min
|
||||
offset_parameter['value'] = Geometry.length_to_speckle(min_z - level_z, units)
|
||||
offset_parameter['units'] = units
|
||||
parameters['Height Offset From Level'] = offset_parameter
|
||||
end
|
||||
|
||||
RevitColumn.new(
|
||||
family: schema['family'],
|
||||
type: schema['family_type'],
|
||||
base_line: base_line,
|
||||
level: level,
|
||||
units: units,
|
||||
parameters: parameters,
|
||||
application_id: edge.persistent_id
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,67 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative '../../base'
|
||||
require_relative '../../built_elements/revit/parameter'
|
||||
require_relative '../../geometry/line'
|
||||
require_relative '../../../constants/type_constants'
|
||||
require_relative '../../../sketchup_model/dictionary/speckle_schema_dictionary_handler'
|
||||
|
||||
module SpeckleConnector
|
||||
module SpeckleObjects
|
||||
module BuiltElements
|
||||
# Revit duct object.
|
||||
class RevitDuct < Base
|
||||
SPECKLE_TYPE = OBJECTS_BUILTELEMENTS_REVIT_DUCT
|
||||
|
||||
# rubocop:disable Metrics/ParameterLists
|
||||
def initialize(family:, type:, height:, width:, base_line:, level:, units:, parameters:, application_id: nil)
|
||||
super(
|
||||
speckle_type: SPECKLE_TYPE,
|
||||
total_children_count: 0,
|
||||
application_id: application_id,
|
||||
id: nil
|
||||
)
|
||||
self[:family] = family
|
||||
self[:type] = type
|
||||
self[:height] = height
|
||||
self[:width] = width
|
||||
self[:level] = level
|
||||
self[:baseLine] = base_line
|
||||
self[:units] = units
|
||||
self[:parameters] = parameters
|
||||
end
|
||||
# rubocop:enable Metrics/ParameterLists
|
||||
|
||||
# @param edge [Sketchup::Edge] edge to get speckle schema for duct.
|
||||
def self.to_speckle_schema(speckle_state, edge, units, global_transformation: nil)
|
||||
base_line = Geometry::Line.to_speckle_schema(edge: edge, units: units)
|
||||
schema = SketchupModel::Dictionary::SpeckleSchemaDictionaryHandler.speckle_schema_to_speckle(edge).to_h
|
||||
source_exist = !speckle_state.speckle_mapper_state.mapper_source.nil?
|
||||
level = nil
|
||||
if source_exist
|
||||
level = speckle_state.speckle_mapper_state.mapper_source.levels.find { |l| l[:name] == schema['level'] }
|
||||
parameters = Base.new
|
||||
offset_parameter = BuiltElements::Revit::Parameter.new(name: 'Height Offset From Level')
|
||||
level_z = Geometry.length_to_native(level[:elevation], level[:units])
|
||||
min_z = [edge.start.position, edge.end.position].map(&:z).min
|
||||
offset_parameter['value'] = Geometry.length_to_speckle(min_z - level_z, units)
|
||||
offset_parameter['units'] = units
|
||||
parameters['Height Offset From Level'] = offset_parameter
|
||||
end
|
||||
|
||||
RevitDuct.new(
|
||||
family: schema['family'],
|
||||
type: schema['family_type'],
|
||||
height: schema['height'],
|
||||
width: schema['width'],
|
||||
base_line: base_line,
|
||||
level: level,
|
||||
units: units,
|
||||
parameters: parameters,
|
||||
application_id: edge.persistent_id
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,42 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative '../../base'
|
||||
|
||||
module SpeckleConnector
|
||||
module SpeckleObjects
|
||||
module BuiltElements
|
||||
module Revit
|
||||
# Revit element type.
|
||||
class RevitElementType < Base
|
||||
SPECKLE_TYPE = OBJECTS_BUILTELEMENTS_REVIT_REVITELEMENTTYPE
|
||||
|
||||
# rubocop:disable Metrics/ParameterLists
|
||||
def initialize(category:, family:, type:, element_id:, application_id: nil, id: nil)
|
||||
super(
|
||||
speckle_type: SPECKLE_TYPE,
|
||||
total_children_count: 0,
|
||||
application_id: application_id,
|
||||
id: id
|
||||
)
|
||||
self[:category] = category
|
||||
self[:family] = family
|
||||
self[:type] = type
|
||||
self[:elementId] = element_id
|
||||
end
|
||||
# rubocop:enable Metrics/ParameterLists
|
||||
|
||||
def self.to_native(revit_element_type)
|
||||
RevitElementType.new(
|
||||
category: revit_element_type['category'],
|
||||
family: revit_element_type['family'],
|
||||
type: revit_element_type['type'],
|
||||
element_id: revit_element_type['elementId'],
|
||||
application_id: revit_element_type['applicationId'],
|
||||
id: revit_element_type['id']
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,77 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative '../../base'
|
||||
require_relative '../../built_elements/revit/parameter'
|
||||
require_relative '../../other/render_material'
|
||||
require_relative '../../geometry/line'
|
||||
require_relative '../../geometry/polyline'
|
||||
require_relative '../../../constants/type_constants'
|
||||
require_relative '../../../sketchup_model/dictionary/speckle_schema_dictionary_handler'
|
||||
|
||||
module SpeckleConnector
|
||||
module SpeckleObjects
|
||||
module BuiltElements
|
||||
# Revit floor object.
|
||||
class RevitFloor < Base
|
||||
SPECKLE_TYPE = OBJECTS_BUILTELEMENTS_REVIT_FLOOR
|
||||
|
||||
# rubocop:disable Metrics/ParameterLists
|
||||
def initialize(family:, type:, outline:, voids:, level:, units:, material:, parameters:nil, application_id: nil)
|
||||
super(
|
||||
speckle_type: SPECKLE_TYPE,
|
||||
total_children_count: 0,
|
||||
application_id: application_id,
|
||||
id: nil
|
||||
)
|
||||
self[:family] = family
|
||||
self[:type] = type
|
||||
self[:level] = level
|
||||
self[:outline] = outline
|
||||
self[:voids] = voids
|
||||
self[:units] = units
|
||||
self[:parameters] = parameters
|
||||
self[:renderMaterial] = material
|
||||
end
|
||||
# rubocop:enable Metrics/ParameterLists
|
||||
|
||||
# @param face [Sketchup::Face] face to get speckle schema for floor.
|
||||
def self.to_speckle_schema(speckle_state, face, units, global_transformation: nil)
|
||||
outline = Geometry::Polyline.from_loop(face.loops.first, units, global_transformation: global_transformation)
|
||||
voids = []
|
||||
if face.loops.length > 1
|
||||
voids = face.loops[1..face.loops.length - 1].collect do |loop|
|
||||
Geometry::Polyline.from_loop(loop, units, global_transformation: global_transformation)
|
||||
end
|
||||
end
|
||||
material = face.material || face.back_material
|
||||
schema = SketchupModel::Dictionary::SpeckleSchemaDictionaryHandler.speckle_schema_to_speckle(face).to_h
|
||||
source_exist = !speckle_state.speckle_mapper_state.mapper_source.nil?
|
||||
level = nil
|
||||
parameters = nil
|
||||
if source_exist
|
||||
level = speckle_state.speckle_mapper_state.mapper_source.levels.find { |l| l[:name] == schema['level'] }
|
||||
parameters = Base.new
|
||||
offset_parameter = BuiltElements::Revit::Parameter.new(name: 'Height Offset From Level')
|
||||
level_z = Geometry.length_to_native(level[:elevation], level[:units])
|
||||
min_z = face.vertices.collect(&:position).map(&:z).min
|
||||
offset_parameter['value'] = Geometry.length_to_speckle(min_z - level_z, units)
|
||||
offset_parameter['units'] = units
|
||||
parameters['Height Offset From Level'] = offset_parameter
|
||||
end
|
||||
|
||||
RevitFloor.new(
|
||||
family: schema['family'],
|
||||
type: schema['family_type'],
|
||||
outline: outline,
|
||||
voids: voids,
|
||||
level: level,
|
||||
units: units,
|
||||
parameters: parameters,
|
||||
material: material.nil? ? nil : Other::RenderMaterial.from_material(face.material || face.back_material),
|
||||
application_id: face.persistent_id
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,65 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative '../../base'
|
||||
require_relative '../../built_elements/revit/parameter'
|
||||
require_relative '../../geometry/line'
|
||||
require_relative '../../../constants/type_constants'
|
||||
require_relative '../../../sketchup_model/dictionary/speckle_schema_dictionary_handler'
|
||||
|
||||
module SpeckleConnector
|
||||
module SpeckleObjects
|
||||
module BuiltElements
|
||||
# Revit pipe object.
|
||||
class RevitPipe < Base
|
||||
SPECKLE_TYPE = OBJECTS_BUILTELEMENTS_REVIT_PIPE
|
||||
|
||||
# rubocop:disable Metrics/ParameterLists
|
||||
def initialize(family:, type:, diameter:, base_line:, level:, units:, parameters:, application_id: nil)
|
||||
super(
|
||||
speckle_type: SPECKLE_TYPE,
|
||||
total_children_count: 0,
|
||||
application_id: application_id,
|
||||
id: nil
|
||||
)
|
||||
self[:family] = family
|
||||
self[:type] = type
|
||||
self[:diameter] = diameter
|
||||
self[:level] = level
|
||||
self[:baseLine] = base_line
|
||||
self[:units] = units
|
||||
self[:parameters] = parameters
|
||||
end
|
||||
# rubocop:enable Metrics/ParameterLists
|
||||
|
||||
# @param edge [Sketchup::Edge] edge to get speckle schema for pipe.
|
||||
def self.to_speckle_schema(speckle_state, edge, units, global_transformation: nil)
|
||||
base_line = Geometry::Line.to_speckle_schema(edge: edge, units: units)
|
||||
schema = SketchupModel::Dictionary::SpeckleSchemaDictionaryHandler.speckle_schema_to_speckle(edge).to_h
|
||||
source_exist = !speckle_state.speckle_mapper_state.mapper_source.nil?
|
||||
level = nil
|
||||
if source_exist
|
||||
level = speckle_state.speckle_mapper_state.mapper_source.levels.find { |l| l[:name] == schema['level'] }
|
||||
parameters = Base.new
|
||||
offset_parameter = BuiltElements::Revit::Parameter.new(name: 'Height Offset From Level')
|
||||
level_z = Geometry.length_to_native(level[:elevation], level[:units])
|
||||
min_z = [edge.start.position, edge.end.position].map(&:z).min
|
||||
offset_parameter['value'] = Geometry.length_to_speckle(min_z - level_z, units)
|
||||
offset_parameter['units'] = units
|
||||
parameters['Height Offset From Level'] = offset_parameter
|
||||
end
|
||||
|
||||
RevitPipe.new(
|
||||
family: schema['family'],
|
||||
type: schema['family_type'],
|
||||
diameter: schema['diameter'],
|
||||
base_line: base_line,
|
||||
level: level,
|
||||
units: units,
|
||||
parameters: parameters,
|
||||
application_id: edge.persistent_id
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,102 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative '../../base'
|
||||
require_relative '../../built_elements/revit/parameter'
|
||||
require_relative '../../other/render_material'
|
||||
require_relative '../../geometry/line'
|
||||
require_relative '../../geometry/length'
|
||||
require_relative '../../../constants/type_constants'
|
||||
require_relative '../../../sketchup_model/dictionary/speckle_schema_dictionary_handler'
|
||||
require_relative '../../../sketchup_model/utils/face_utils'
|
||||
|
||||
module SpeckleConnector
|
||||
module SpeckleObjects
|
||||
module BuiltElements
|
||||
# Revit wall object.
|
||||
class RevitWall < Base
|
||||
SPECKLE_TYPE = OBJECTS_BUILTELEMENTS_REVIT_WALL
|
||||
|
||||
# rubocop:disable Metrics/ParameterLists
|
||||
def initialize(family:, type:, base_line:, height:, flipped:, level:, units:, material:, parameters: nil, application_id: nil)
|
||||
super(
|
||||
speckle_type: SPECKLE_TYPE,
|
||||
total_children_count: 0,
|
||||
application_id: application_id,
|
||||
id: nil
|
||||
)
|
||||
self[:family] = family
|
||||
self[:type] = type
|
||||
self[:height] = height
|
||||
self[:flipped] = flipped
|
||||
self[:level] = level
|
||||
self[:baseLine] = base_line
|
||||
self[:units] = units
|
||||
self[:parameters] = parameters
|
||||
self[:renderMaterial] = material
|
||||
end
|
||||
# rubocop:enable Metrics/ParameterLists
|
||||
|
||||
def self.to_native(state, wall, layer, entities, &convert_to_native)
|
||||
obj = Other::DisplayValue.collect_definition_geometries(wall)
|
||||
obj['name'] = Other::DisplayValue.get_definition_name(obj)
|
||||
|
||||
state, _definitions = Other::BlockDefinition.to_native(
|
||||
state, obj, layer, entities, &convert_to_native
|
||||
)
|
||||
|
||||
definition = state.sketchup_state.sketchup_model.definitions[Other::BlockDefinition.get_definition_name(obj)]
|
||||
|
||||
Other::BlockInstance.find_and_erase_existing_instance(definition, obj['id'], obj['applicationId'])
|
||||
t_arr = obj['transform']
|
||||
transform = t_arr.nil? ? Geom::Transformation.new : Other::Transform.to_native(t_arr, obj['units'])
|
||||
instance = entities.add_instance(definition, transform)
|
||||
instance.name = Other::DisplayValue.get_instance_name(obj['name']) unless obj['name'].nil?
|
||||
instance.layer = layer unless layer.nil?
|
||||
# Align instance axes that created from display value. (without any transform)
|
||||
# BlockInstance.align_instance_axes(instance)
|
||||
return state, [instance, definition]
|
||||
end
|
||||
|
||||
# @param face [Sketchup::Face] face to get speckle schema for wall.
|
||||
def self.to_speckle_schema(speckle_state, face, units, global_transformation: nil)
|
||||
base_line = Geometry::Line.base_line_from_face(face, units, global_transformation: global_transformation)
|
||||
|
||||
material = face.material || face.back_material
|
||||
schema = SketchupModel::Dictionary::SpeckleSchemaDictionaryHandler.speckle_schema_to_speckle(face).to_h
|
||||
source_exist = !speckle_state.speckle_mapper_state.mapper_source.nil?
|
||||
level = nil
|
||||
parameters = nil
|
||||
if source_exist
|
||||
level = speckle_state.speckle_mapper_state.mapper_source.levels.find { |l| l[:name] == schema['level'] }
|
||||
parameters = Base.new
|
||||
offset_parameter = BuiltElements::Revit::Parameter.new(name: 'Height Offset From Level')
|
||||
level_z = Geometry.length_to_native(level[:elevation], level[:units])
|
||||
min_z = face.vertices.collect(&:position).map(&:z).min
|
||||
offset_parameter['value'] = Geometry.length_to_speckle(min_z - level_z, units)
|
||||
offset_parameter['units'] = units
|
||||
parameters['Height Offset From Level'] = offset_parameter
|
||||
end
|
||||
|
||||
RevitWall.new(
|
||||
family: schema['family'],
|
||||
type: schema['family_type'],
|
||||
base_line: base_line,
|
||||
height: Geometry.length_to_speckle(SketchupModel::Utils::FaceUtils.max_z(face), units),
|
||||
flipped: false,
|
||||
level: level,
|
||||
units: units,
|
||||
parameters: parameters,
|
||||
material: material.nil? ? nil : Other::RenderMaterial.from_material(face.material || face.back_material),
|
||||
application_id: face.persistent_id
|
||||
)
|
||||
end
|
||||
|
||||
def self.get_wall_height(face, units)
|
||||
points = face.vertices.collect(&:position)
|
||||
points_z_values = points.collect(&:z)
|
||||
Geometry.length_to_speckle(points_z_values.max - points_z_values.min, units)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -19,7 +19,7 @@ module SpeckleConnector
|
||||
# @param direction [SpeckleObjects::Geometry::Vector] direction of the view from eye to target.
|
||||
# @param up_direction [SpeckleObjects::Geometry::Vector] up direction of the view.
|
||||
# @param is_perspective [Boolean] whether view is perspective or not.
|
||||
# @param lens [Boolean] fov value of the view camera.
|
||||
# @param lens [Numeric] focal length value of the view camera.
|
||||
# @param units [String] units of the camera.
|
||||
# @param application_id [String] application_id of the view.
|
||||
# @param update_properties [Hash{Symbol=>boolean}] properties of the view.
|
||||
@@ -63,42 +63,44 @@ module SpeckleConnector
|
||||
rendering_options = SpeckleObjects::Other::RenderingOptions.to_speckle(page.rendering_options)
|
||||
View3d.new(
|
||||
page.name, origin, target, direction, SpeckleObjects::Geometry::Vector.new(0, 0, 1, units),
|
||||
cam.perspective?, cam.fov, units, page.name, update_properties, rendering_options
|
||||
cam.perspective?, cam.perspective? ? cam.focal_length : 35, units, page.name,
|
||||
update_properties, rendering_options
|
||||
)
|
||||
end
|
||||
|
||||
# @param state [States::State] state of the speckle app.
|
||||
# @param obj [Hash] commit object.
|
||||
# rubocop:disable Metrics/AbcSize
|
||||
# rubocop:disable Metrics/CyclomaticComplexity
|
||||
# rubocop:disable Metrics/PerceivedComplexity
|
||||
def self.to_native(state, view, _layer, _entities, &_convert_to_native)
|
||||
sketchup_model = state.sketchup_state.sketchup_model
|
||||
|
||||
return state, [] unless view['speckle_type'] == 'Objects.BuiltElements.View:Objects.BuiltElements.View3D'
|
||||
|
||||
name = view['name'] || view['id']
|
||||
return state, [] if sketchup_model.pages.any? { |page| page.name == name }
|
||||
|
||||
origin = view['origin']
|
||||
target = view['target']
|
||||
lens = view['lens'] || 50
|
||||
origin = SpeckleObjects::Geometry::Point.to_native(origin['x'], origin['y'], origin['z'], origin['units'])
|
||||
target = SpeckleObjects::Geometry::Point.to_native(target['x'], target['y'], target['z'], target['units'])
|
||||
view_direction = (origin - target).normalize
|
||||
up = view_direction.parallel?([0, 0, 1]) ? [0, 1, 0] : [0, 0, 1]
|
||||
# Set camera position before creating scene on it.
|
||||
my_camera = Sketchup::Camera.new(origin, target, up, !view['isOrthogonal'], lens)
|
||||
sketchup_model.active_view.camera = my_camera
|
||||
camera = create_camera(view)
|
||||
sketchup_model.active_view.camera = camera
|
||||
sketchup_model.pages.add(name)
|
||||
page = sketchup_model.pages[name]
|
||||
set_page_update_properties(page, view['update_properties']) if view['update_properties']
|
||||
set_rendering_options(page.rendering_options, view['rendering_options']) if view['rendering_options']
|
||||
return state, [page]
|
||||
end
|
||||
# rubocop:enable Metrics/AbcSize
|
||||
# rubocop:enable Metrics/CyclomaticComplexity
|
||||
# rubocop:enable Metrics/PerceivedComplexity
|
||||
|
||||
def self.create_camera(view)
|
||||
origin = view['origin']
|
||||
target = view['target']
|
||||
focal_length = view['lens'] || 35
|
||||
origin = SpeckleObjects::Geometry::Point.to_native(origin['x'], origin['y'], origin['z'], origin['units'])
|
||||
target = SpeckleObjects::Geometry::Point.to_native(target['x'], target['y'], target['z'], target['units'])
|
||||
view_direction = (origin - target).normalize
|
||||
up = view_direction.parallel?([0, 0, 1]) ? [0, 1, 0] : [0, 0, 1]
|
||||
# Set camera position before creating scene on it.
|
||||
is_perspective = !view['isOrthogonal']
|
||||
camera = Sketchup::Camera.new(origin, target, up, is_perspective)
|
||||
camera.focal_length = focal_length if is_perspective
|
||||
camera.height = (origin - target).length * 2 unless is_perspective
|
||||
camera
|
||||
end
|
||||
|
||||
# @param page [Sketchup::Page] scene to update -update properties-
|
||||
def self.set_page_update_properties(page, update_properties)
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative '../base'
|
||||
require_relative '../../constants/type_constants'
|
||||
|
||||
module SpeckleConnector
|
||||
module SpeckleObjects
|
||||
module Geometry
|
||||
# Arc object definition for Speckle.
|
||||
class Arc < Base
|
||||
SPECKLE_TYPE = OBJECTS_GEOMETRY_ARC
|
||||
|
||||
# @param [States::State] state of the current application.
|
||||
# @param arc [Object] object represents Speckle Arc.
|
||||
# @param layer [Sketchup::Layer] layer to add {Sketchup::Edge} into it.
|
||||
# @param entities [Sketchup::Entities] entities collection to add {Sketchup::Edge} into it.
|
||||
def self.to_native(state, arc, layer, entities, &_convert_to_native)
|
||||
plane = arc['plane']
|
||||
units = arc['units']
|
||||
origin = Point.to_native(plane['origin']['x'], plane['origin']['y'], plane['origin']['z'], units)
|
||||
normal = Vector.to_native(plane['normal']['x'], plane['normal']['y'], plane['normal']['z'], units)
|
||||
x_axis = Vector.to_native(plane['xdir']['x'], plane['xdir']['y'], plane['xdir']['z'], units)
|
||||
radius = Geometry.length_to_native(arc['radius'], units)
|
||||
edges = entities.add_arc(origin, x_axis, normal, radius, arc['startAngle'], arc['endAngle'])
|
||||
edges.each { |edge| edge.layer = layer }
|
||||
return state, edges
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,33 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative 'point'
|
||||
require_relative 'vector'
|
||||
require_relative 'length'
|
||||
require_relative '../base'
|
||||
require_relative '../../constants/type_constants'
|
||||
|
||||
module SpeckleConnector
|
||||
module SpeckleObjects
|
||||
module Geometry
|
||||
# Circle object definition for Speckle.
|
||||
class Circle < Base
|
||||
SPECKLE_TYPE = OBJECTS_GEOMETRY_CIRCLE
|
||||
|
||||
# @param [States::State] state of the current application.
|
||||
# @param circle [Object] object represents Speckle Circle.
|
||||
# @param layer [Sketchup::Layer] layer to add {Sketchup::Edge} into it.
|
||||
# @param entities [Sketchup::Entities] entities collection to add {Sketchup::Edge} into it.
|
||||
def self.to_native(state, circle, layer, entities, &_convert_to_native)
|
||||
plane = circle['plane']
|
||||
units = circle['units']
|
||||
origin = Point.to_native(plane['origin']['x'], plane['origin']['y'], plane['origin']['z'], units)
|
||||
normal = Vector.to_native(plane['normal']['x'], plane['normal']['y'], plane['normal']['z'], units)
|
||||
radius = Geometry.length_to_native(circle['radius'], units)
|
||||
edges = entities.add_circle(origin, normal, radius)
|
||||
edges.each { |edge| edge.layer = layer }
|
||||
return state, edges
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -11,6 +11,10 @@ module SpeckleConnector
|
||||
end
|
||||
|
||||
def self.length_to_native(length, units)
|
||||
if units == 'none'
|
||||
units = SpeckleConnector::Converters::
|
||||
SKETCHUP_UNITS[Sketchup.active_model.options['UnitsOptions']['LengthUnit']]
|
||||
end
|
||||
length.__send__(SpeckleConnector::Converters::SKETCHUP_UNIT_STRINGS[units])
|
||||
end
|
||||
end
|
||||
|
||||
@@ -34,17 +34,33 @@ module SpeckleConnector
|
||||
self[:domain] = domain
|
||||
self[:units] = units
|
||||
self[:layer] = layer unless layer.nil?
|
||||
self[:SpeckleSchema] = speckle_schema if speckle_schema.any?
|
||||
self['@SpeckleSchema'] = speckle_schema if speckle_schema.any?
|
||||
self[:sketchup_attributes] = sketchup_attributes if sketchup_attributes.any?
|
||||
end
|
||||
# rubocop:enable Metrics/ParameterLists
|
||||
|
||||
def self.to_speckle_schema(edge:, units:)
|
||||
start_pt = Geometry::Point.from_vertex(edge.start.position, units)
|
||||
end_pt = Geometry::Point.from_vertex(edge.end.position, units)
|
||||
domain = Primitive::Interval.from_numeric(0, Float(edge.length), units)
|
||||
Line.new(
|
||||
start_pt: start_pt,
|
||||
end_pt: end_pt,
|
||||
domain: domain,
|
||||
units: units,
|
||||
layer: SketchupModel::Query::Layer.entity_path(edge),
|
||||
sketchup_attributes: {},
|
||||
speckle_schema: {},
|
||||
application_id: edge.persistent_id.to_s
|
||||
)
|
||||
end
|
||||
|
||||
# @param edge [Sketchup::Edge] edge to convert line.
|
||||
def self.from_edge(edge, units, model_preferences)
|
||||
def self.from_edge(speckle_state:, edge:, units:, model_preferences:, global_transformation: nil)
|
||||
dictionaries = SketchupModel::Dictionary::BaseDictionaryHandler
|
||||
.attribute_dictionaries_to_speckle(edge, model_preferences)
|
||||
att = dictionaries.any? ? { dictionaries: dictionaries } : {}
|
||||
speckle_schema = SketchupModel::Dictionary::SpeckleSchemaDictionaryHandler.speckle_schema_to_speckle(edge)
|
||||
speckle_schema = Mapper.to_speckle(speckle_state, edge, units, global_transformation: global_transformation)
|
||||
start_pt = Geometry::Point.from_vertex(edge.start.position, units)
|
||||
end_pt = Geometry::Point.from_vertex(edge.end.position, units)
|
||||
domain = Primitive::Interval.from_numeric(0, Float(edge.length), units)
|
||||
@@ -60,7 +76,42 @@ module SpeckleConnector
|
||||
)
|
||||
end
|
||||
|
||||
# @param _state [States::State] state of the application.
|
||||
# @param edge [Sketchup::Face] face to get base line from face.
|
||||
def self.base_line_from_face(face, units, global_transformation: nil)
|
||||
points = face.vertices.collect(&:position)
|
||||
points_z_values = points.collect(&:z)
|
||||
height = Geometry.length_to_speckle(points_z_values.max - points_z_values.min, units)
|
||||
min_z = points_z_values.min
|
||||
projected_points = points.map { |p| Geom::Point3d.new(p.x, p.y, min_z) }
|
||||
distance_with_points = Struct.new(:distance, :point_1, :point_2)
|
||||
lines_with_distances = []
|
||||
projected_points.each do |p|
|
||||
projected_points.each do |p_other|
|
||||
next if p_other == p
|
||||
|
||||
lines_with_distances.append(distance_with_points.new(p.distance(p_other), p, p_other))
|
||||
end
|
||||
end
|
||||
lines_with_distances.sort_by!(&:distance).reverse!
|
||||
p_1 = lines_with_distances.first.point_1
|
||||
p_2 = lines_with_distances.first.point_2
|
||||
unless global_transformation.nil?
|
||||
p_1 = p_1.transform!(global_transformation)
|
||||
p_2 = p_2.transform!(global_transformation)
|
||||
end
|
||||
Line.new(
|
||||
start_pt: Geometry::Point.from_vertex(p_1, units),
|
||||
end_pt: Geometry::Point.from_vertex(p_2, units),
|
||||
domain: Primitive::Interval.from_numeric(0, Geometry.length_to_speckle(p_1.distance(p_2), units), units),
|
||||
units: units,
|
||||
layer: SketchupModel::Query::Layer.entity_path(face),
|
||||
sketchup_attributes: {},
|
||||
speckle_schema: {},
|
||||
application_id: face.persistent_id.to_s
|
||||
)
|
||||
end
|
||||
|
||||
# @param state [States::State] state of the application.
|
||||
# @param line [Object] object represents Speckle line.
|
||||
# @param layer [Sketchup::Layer] layer to add {Sketchup::Edge} into it.
|
||||
# @param entities [Sketchup::Entities] entities collection to add {Sketchup::Edge} into it.
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
require_relative '../base'
|
||||
require_relative '../geometry/bounding_box'
|
||||
require_relative '../other/render_material'
|
||||
require_relative '../../mapper/mapper'
|
||||
require_relative '../../sketchup_model/query/entity'
|
||||
require_relative '../../convertors/clean_up'
|
||||
require_relative '../../sketchup_model/dictionary/base_dictionary_handler'
|
||||
@@ -51,7 +52,7 @@ module SpeckleConnector
|
||||
self[:'@(31250)vertices'] = vertices
|
||||
self[:'@(62500)faces'] = faces
|
||||
self[:sketchup_attributes] = sketchup_attributes if sketchup_attributes.any?
|
||||
self[:SpeckleSchema] = speckle_schema if speckle_schema.any?
|
||||
self['@SpeckleSchema'] = speckle_schema if speckle_schema.any?
|
||||
end
|
||||
# rubocop:enable Metrics/ParameterLists
|
||||
|
||||
@@ -119,6 +120,10 @@ module SpeckleConnector
|
||||
added_faces = entities.grep(Sketchup::Face).last(native_mesh.polygons.length)
|
||||
mesh_layer_name = SketchupModel::Query::Layer.entity_layer_from_path(mesh['layer'])
|
||||
mesh_layer = state.sketchup_state.sketchup_model.layers.to_a.find { |l| l.display_name == mesh_layer_name }
|
||||
# Merge only added faces in this scope
|
||||
# if model_preferences[:merge_coplanar_faces]
|
||||
# added_faces = Converters::CleanUp.merge_coplanar_faces(added_faces)
|
||||
# end
|
||||
added_faces.each do |face|
|
||||
face.layer = mesh_layer unless mesh_layer.nil?
|
||||
# Smooth edges if they already soft
|
||||
@@ -129,10 +134,7 @@ module SpeckleConnector
|
||||
.attribute_dictionaries_to_native(face, mesh['sketchup_attributes']['dictionaries'])
|
||||
end
|
||||
end
|
||||
# Merge only added faces in this scope
|
||||
if model_preferences[:merge_coplanar_faces]
|
||||
added_faces = Converters::CleanUp.merge_coplanar_faces(added_faces)
|
||||
end
|
||||
|
||||
return state, added_faces
|
||||
end
|
||||
# rubocop:enable Metrics/MethodLength
|
||||
@@ -146,13 +148,13 @@ module SpeckleConnector
|
||||
# @param global_transform [Geom::Transformation, nil] global transformation value of face if it is not included
|
||||
# into any component.
|
||||
# rubocop:disable Style/MultilineTernaryOperator
|
||||
def self.from_face(face:, units:, model_preferences:, global_transform: nil, parent_material: nil)
|
||||
def self.from_face(speckle_state:, face:, units:, model_preferences:, global_transform: nil, parent_material: nil)
|
||||
dictionaries = SketchupModel::Dictionary::BaseDictionaryHandler
|
||||
.attribute_dictionaries_to_speckle(face, model_preferences)
|
||||
has_any_soften_edge = face.edges.any?(&:soft?)
|
||||
att = dictionaries.any? ? { is_soften: has_any_soften_edge, dictionaries: dictionaries }
|
||||
: { is_soften: has_any_soften_edge }
|
||||
speckle_schema = SketchupModel::Dictionary::SpeckleSchemaDictionaryHandler.speckle_schema_to_speckle(face)
|
||||
speckle_schema = Mapper.to_speckle(speckle_state, face, units, global_transformation: global_transform)
|
||||
material = face.material || face.back_material || parent_material
|
||||
speckle_mesh = Mesh.new(
|
||||
units: units,
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative '../base'
|
||||
require_relative '../../constants/type_constants'
|
||||
|
||||
module SpeckleConnector
|
||||
module SpeckleObjects
|
||||
module Geometry
|
||||
# Polycurve object definition for Speckle.
|
||||
# It basically groups the lines-curves under it's `segments` property.
|
||||
class Polycurve < Base
|
||||
SPECKLE_TYPE = OBJECTS_GEOMETRY_POLYCURVE
|
||||
|
||||
def self.to_native(state, polycurve, layer, entities, &convert_to_native)
|
||||
polycurve['displayValue'] = polycurve['segments']
|
||||
convert_to_native.call(state, polycurve, layer, entities)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,65 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative 'length'
|
||||
require_relative 'point'
|
||||
require_relative 'bounding_box'
|
||||
require_relative '../base'
|
||||
require_relative '../primitive/interval'
|
||||
|
||||
module SpeckleConnector
|
||||
module SpeckleObjects
|
||||
module Geometry
|
||||
# Polyline object definition for Speckle.
|
||||
class Polyline < Base
|
||||
SPECKLE_TYPE = OBJECTS_GEOMETRY_POLYLINE
|
||||
|
||||
# @param value [Array<Numeric>] polygon vertex coordinates as flat list.
|
||||
# @param domain [Primitive::Interval] domain of the polyline.
|
||||
# @param length [Numeric] length of the polyline.
|
||||
# @param closed [Boolean] whether polyline is closed or not.
|
||||
# @param units [String] units of the polyline.
|
||||
# @param application_id [String] application id of the polyline which corresponds to persistent_id of the Loop.
|
||||
# rubocop:disable Metrics/ParameterLists
|
||||
def initialize(value:, domain:, length:, closed:, units:, application_id: nil)
|
||||
super(
|
||||
speckle_type: SPECKLE_TYPE,
|
||||
total_children_count: 0,
|
||||
application_id: application_id,
|
||||
id: nil
|
||||
)
|
||||
self[:value] = value
|
||||
self[:domain] = domain
|
||||
self[:length] = length
|
||||
self[:closed] = closed
|
||||
self[:units] = units
|
||||
end
|
||||
# rubocop:enable Metrics/ParameterLists
|
||||
|
||||
# @param loop [Sketchup::Loop] loop to convert closed speckle polyline.
|
||||
def self.from_loop(loop, units, global_transformation: nil)
|
||||
points = loop.vertices.collect do |vertex|
|
||||
position = vertex.position
|
||||
position = vertex.position.transform!(global_transformation) unless global_transformation.nil?
|
||||
position
|
||||
end
|
||||
values = points.collect do |p|
|
||||
[Geometry.length_to_speckle(p.x, units),
|
||||
Geometry.length_to_speckle(p.y, units),
|
||||
Geometry.length_to_speckle(p.z, units)]
|
||||
end.flatten
|
||||
loop_length = loop.edges.sum(&:length)
|
||||
length = Geometry.length_to_speckle(loop_length, units)
|
||||
domain = Primitive::Interval.from_lengths(0, loop_length, units)
|
||||
Polyline.new(
|
||||
value: values,
|
||||
domain: domain,
|
||||
length: length,
|
||||
units: units,
|
||||
closed: true,
|
||||
application_id: loop.persistent_id.to_s
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,207 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module SpeckleConnector
|
||||
module SpeckleObjects
|
||||
module Geometry
|
||||
module Units
|
||||
MILLIMETERS = 'mm'
|
||||
CENTIMETERS = 'cm'
|
||||
METERS = 'm'
|
||||
KILOMETERS = 'km'
|
||||
INCHES = 'in'
|
||||
FEET = 'ft'
|
||||
YARDS = 'yd'
|
||||
MILES = 'mi'
|
||||
NONE = 'none'
|
||||
|
||||
# USInches = "us_in" the smelliest ones, can add later if people scream "USA #1"
|
||||
USFEET = 'us_ft' # it happened, absolutely gross
|
||||
|
||||
SUPPORTED_UNITS = [MILLIMETERS, CENTIMETERS, METERS, KILOMETERS,
|
||||
INCHES, FEET, USFEET, YARDS, MILES, NONE].freeze
|
||||
|
||||
CONVERSION_TABLE = {
|
||||
MILLIMETERS => {
|
||||
CENTIMETERS => 0.1,
|
||||
METERS => 0.001,
|
||||
KILOMETERS => 1e-6,
|
||||
INCHES => 0.0393701,
|
||||
FEET => 0.00328084,
|
||||
USFEET => 0.0032808333,
|
||||
YARDS => 0.00109361,
|
||||
MILES => 6.21371e-7
|
||||
},
|
||||
CENTIMETERS => {
|
||||
MILLIMETERS => 10,
|
||||
METERS => 0.01,
|
||||
KILOMETERS => 1e-5,
|
||||
INCHES => 0.393701,
|
||||
FEET => 0.0328084,
|
||||
USFEET => 0.0328083333,
|
||||
YARDS => 0.0109361,
|
||||
MILES => 6.21371e-6
|
||||
},
|
||||
METERS => {
|
||||
MILLIMETERS => 1000,
|
||||
CENTIMETERS => 100,
|
||||
KILOMETERS => 0.001,
|
||||
INCHES => 39.3701,
|
||||
FEET => 3.28084,
|
||||
USFEET => 3.28083333,
|
||||
YARDS => 1.09361,
|
||||
MILES => 0.000621371
|
||||
},
|
||||
KILOMETERS => {
|
||||
MILLIMETERS => 1e6,
|
||||
CENTIMETERS => 100000,
|
||||
METERS => 1000,
|
||||
INCHES => 39370.1,
|
||||
FEET => 3280.84,
|
||||
USFEET => 3280.83333,
|
||||
YARDS => 1093.61,
|
||||
MILES => 0.621371
|
||||
},
|
||||
INCHES => {
|
||||
MILLIMETERS => 25.4,
|
||||
CENTIMETERS => 2.54,
|
||||
METERS => 0.0254,
|
||||
KILOMETERS => 2.54e-5,
|
||||
FEET => 0.0833333,
|
||||
USFEET => 0.0833331667,
|
||||
YARDS => 0.027777694,
|
||||
MILES => 1.57828e-5
|
||||
},
|
||||
FEET => {
|
||||
MILLIMETERS => 304.8,
|
||||
CENTIMETERS => 30.48,
|
||||
METERS => 0.3048,
|
||||
KILOMETERS => 0.0003048,
|
||||
INCHES => 12,
|
||||
USFEET => 0.999998,
|
||||
YARDS => 0.333332328,
|
||||
MILES => 0.000189394
|
||||
},
|
||||
USFEET => {
|
||||
MILLIMETERS => 120000.0 / 3937.0,
|
||||
CENTIMETERS => 12000.0 / 3937.0,
|
||||
METERS => 1200.0 / 3937.0,
|
||||
KILOMETERS => 1.2 / 3937.0,
|
||||
INCHES => 12.000024,
|
||||
FEET => 1.000002,
|
||||
YARDS => 1.000002 / 3.0,
|
||||
MILES => 1.000002 / 5280.0
|
||||
},
|
||||
YARDS => {
|
||||
MILLIMETERS => 914.4,
|
||||
CENTIMETERS => 91.44,
|
||||
METERS => 0.9144,
|
||||
KILOMETERS => 0.0009144,
|
||||
INCHES => 36,
|
||||
FEET => 3,
|
||||
USFEET => 2.999994,
|
||||
MILES => 1.0 / 1760.0
|
||||
},
|
||||
MILES => {
|
||||
MILLIMETERS => 1.609e6,
|
||||
CENTIMETERS => 160934,
|
||||
METERS => 1609.34,
|
||||
KILOMETERS => 1.60934,
|
||||
INCHES => 63360,
|
||||
FEET => 5280,
|
||||
USFEET => 5279.98944002112,
|
||||
YARDS => 1759.99469184
|
||||
},
|
||||
NONE => { NONE => 1 }
|
||||
}.freeze
|
||||
|
||||
def self.unit_supported?(unit)
|
||||
SUPPORTED_UNITS.include?(unit)
|
||||
end
|
||||
|
||||
# USYards = "us_yd" the smelliest ones, can add later if people scream "USA #1"
|
||||
# USMiles = "us_mi" the smelliest ones, can add later if people scream "USA #1"
|
||||
|
||||
def self.get_conversion_factor(from, to)
|
||||
from = get_units_from_string(from)
|
||||
to = get_units_from_string(to)
|
||||
CONVERSION_TABLE[from][to] || 1
|
||||
end
|
||||
|
||||
def self.get_units_from_string(unit)
|
||||
return nil if unit.nil?
|
||||
|
||||
case unit.downcase
|
||||
when 'mm', 'mil', 'millimeter', 'millimeters', 'millimetres'
|
||||
MILLIMETERS
|
||||
when 'cm', 'centimetre', 'centimeter', 'centimetres', 'centimeters'
|
||||
CENTIMETERS
|
||||
when 'm', 'meter', 'metre', 'meters', 'metres'
|
||||
METERS
|
||||
when 'inches', 'inch', 'in'
|
||||
INCHES
|
||||
when 'feet', 'foot', 'ft'
|
||||
FEET
|
||||
when 'ussurveyfeet'
|
||||
USFEET
|
||||
when 'yard', 'yards', 'yd'
|
||||
YARDS
|
||||
when 'miles', 'mile', 'mi'
|
||||
MILES
|
||||
when 'kilometers', 'kilometer', 'km'
|
||||
KILOMETERS
|
||||
when 'none'
|
||||
NONE
|
||||
else
|
||||
raise "Cannot understand what unit #{unit} is."
|
||||
end
|
||||
end
|
||||
|
||||
def self.get_encoding_from_unit(unit)
|
||||
case unit
|
||||
when MILLIMETERS
|
||||
1
|
||||
when CENTIMETERS
|
||||
2
|
||||
when METERS
|
||||
3
|
||||
when KILOMETERS
|
||||
4
|
||||
when INCHES
|
||||
5
|
||||
when FEET
|
||||
6
|
||||
when YARDS
|
||||
7
|
||||
when MILES
|
||||
8
|
||||
else
|
||||
0
|
||||
end
|
||||
end
|
||||
|
||||
def self.get_unit_from_encoding(unit)
|
||||
case unit
|
||||
when 1
|
||||
MILLIMETERS
|
||||
when 2
|
||||
CENTIMETERS
|
||||
when 3
|
||||
METERS
|
||||
when 4
|
||||
KILOMETERS
|
||||
when 5
|
||||
INCHES
|
||||
when 6
|
||||
FEET
|
||||
when 7
|
||||
YARDS
|
||||
when 8
|
||||
MILES
|
||||
else
|
||||
NONE
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,5 +1,6 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative 'length'
|
||||
require_relative '../base'
|
||||
|
||||
module SpeckleConnector
|
||||
@@ -25,6 +26,14 @@ module SpeckleConnector
|
||||
self[:z] = z
|
||||
self[:units] = units
|
||||
end
|
||||
|
||||
def self.to_native(x, y, z, units)
|
||||
Geom::Vector3d.new(
|
||||
Geometry.length_to_native(x, units),
|
||||
Geometry.length_to_native(y, units),
|
||||
Geometry.length_to_native(z, units)
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative 'utils'
|
||||
require_relative '../base'
|
||||
require_relative '../other/transform'
|
||||
require_relative '../other/block_definition'
|
||||
require_relative '../other/block_instance'
|
||||
require_relative '../../constants/type_constants'
|
||||
require_relative '../../sketchup_model/dictionary/dictionary_handler'
|
||||
|
||||
module SpeckleConnector
|
||||
module SpeckleObjects
|
||||
module GIS
|
||||
# Line element in GIS tools.
|
||||
class LineElement < Base
|
||||
SPECKLE_TYPE = OBJECTS_GIS_LINEELEMENT
|
||||
|
||||
# Handles polygon element differently from display value.
|
||||
def self.to_native(state, obj, layer, entities, &convert_to_native)
|
||||
attributes = GIS.get_qgis_attributes(obj)
|
||||
obj = collect_definition_geometries(obj)
|
||||
obj['name'] = GIS.get_definition_name(obj, attributes)
|
||||
|
||||
state, _definitions = Other::BlockDefinition.to_native(
|
||||
state, obj, layer, entities, &convert_to_native
|
||||
)
|
||||
|
||||
definition = state.sketchup_state.sketchup_model
|
||||
.definitions[Other::BlockDefinition.get_definition_name(obj)]
|
||||
|
||||
Other::BlockInstance.find_and_erase_existing_instance(definition, obj['id'], obj['applicationId'])
|
||||
t_arr = obj['transform']
|
||||
transform = t_arr.nil? ? Geom::Transformation.new : Other::Transform.to_native(t_arr, obj['units'])
|
||||
instance = entities.add_instance(definition, transform)
|
||||
instance.name = obj['name'] unless obj['name'].nil?
|
||||
SketchupModel::Dictionary::DictionaryHandler.set_hash(instance, attributes, 'qgis')
|
||||
SketchupModel::Dictionary::DictionaryHandler.set_hash(definition, attributes, 'qgis')
|
||||
# Align instance axes that created from display value. (without any transform)
|
||||
Other::BlockInstance.align_instance_axes(instance)
|
||||
return state, [instance, definition]
|
||||
end
|
||||
|
||||
def self.collect_definition_geometries(obj)
|
||||
geometries = []
|
||||
|
||||
# FIXME: This type check needed because of QGIS. It can send geometries both way, object or array..
|
||||
# This is something need to be fixed by QGIS.
|
||||
if obj['geometry'].is_a?(Array)
|
||||
obj['geometry'].each do |geometry|
|
||||
geometries << geometry
|
||||
end
|
||||
else
|
||||
geometries += obj['geometry']
|
||||
end
|
||||
|
||||
geometries.each do |geo|
|
||||
if geo['speckle_type'] && geo['speckle_type'] == OBJECTS_GEOMETRY_MESH
|
||||
geo['sketchup_attributes'] = { 'is_soften' => false }
|
||||
end
|
||||
end
|
||||
|
||||
obj['geometry'] = geometries
|
||||
obj
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,5 +1,6 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative 'utils'
|
||||
require_relative '../base'
|
||||
require_relative '../other/transform'
|
||||
require_relative '../other/block_definition'
|
||||
@@ -14,26 +15,11 @@ module SpeckleConnector
|
||||
class PolygonElement < Base
|
||||
SPECKLE_TYPE = OBJECTS_GIS_POLYGONELEMENT
|
||||
|
||||
def self.get_definition_name(obj, attributes)
|
||||
return obj['name'] unless obj['name'].nil?
|
||||
|
||||
return attributes['name'] unless attributes['name'].nil?
|
||||
|
||||
return "def::#{obj['id']}"
|
||||
end
|
||||
|
||||
def self.get_qgis_attributes(obj)
|
||||
attributes = obj['attributes'].to_h
|
||||
speckle_properties = %w[id speckle_type totalChildrenCount units applicationId]
|
||||
speckle_properties.each { |key| attributes.delete(key) }
|
||||
attributes
|
||||
end
|
||||
|
||||
# Handles polygon element differently from display value.
|
||||
def self.to_native(state, obj, layer, entities, &convert_to_native)
|
||||
attributes = get_qgis_attributes(obj)
|
||||
attributes = GIS.get_qgis_attributes(obj)
|
||||
obj = collect_definition_geometries(obj)
|
||||
obj['name'] = get_definition_name(obj, attributes)
|
||||
obj['name'] = GIS.get_definition_name(obj, attributes)
|
||||
|
||||
state, _definitions = Other::BlockDefinition.to_native(
|
||||
state, obj, layer, entities, &convert_to_native
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative '../base'
|
||||
require_relative '../other/transform'
|
||||
require_relative '../other/block_definition'
|
||||
require_relative '../other/block_instance'
|
||||
require_relative '../../constants/type_constants'
|
||||
require_relative '../../sketchup_model/dictionary/dictionary_handler'
|
||||
|
||||
module SpeckleConnector
|
||||
module SpeckleObjects
|
||||
module GIS
|
||||
def self.get_definition_name(obj, attributes)
|
||||
return obj['name'] unless obj['name'].nil?
|
||||
|
||||
return attributes['name'] unless attributes['name'].nil?
|
||||
|
||||
return "def::#{obj['id']}"
|
||||
end
|
||||
|
||||
def self.get_qgis_attributes(obj)
|
||||
attributes = obj['attributes'].to_h
|
||||
speckle_properties = %w[id speckle_type totalChildrenCount units applicationId]
|
||||
speckle_properties.each { |key| attributes.delete(key) }
|
||||
attributes
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -122,13 +122,23 @@ module SpeckleConnector
|
||||
definition&.entities&.clear!
|
||||
definition ||= sketchup_model.definitions.add(definition_name)
|
||||
|
||||
ngon_faces = []
|
||||
if geometry.is_a?(Array)
|
||||
geometry.each do |obj|
|
||||
state = convert_to_native.call(state, obj, layer, definition.entities)
|
||||
state, added_entities = convert_to_native.call(state, obj, layer, definition.entities)
|
||||
if added_entities.length == 1 && added_entities.first.is_a?(Sketchup::Face)
|
||||
ngon_faces.append(added_entities.first)
|
||||
end
|
||||
end
|
||||
end
|
||||
ngon_faces.each do |f|
|
||||
f.edges.each do |e|
|
||||
e.soft = false
|
||||
e.smooth = false
|
||||
end
|
||||
end
|
||||
if geometry.is_a?(Hash) && !definition_obj['speckle_type'].nil?
|
||||
state = convert_to_native.call(state, geometry, layer, definition.entities)
|
||||
state, _converted_entities = convert_to_native.call(state, geometry, layer, definition.entities)
|
||||
end
|
||||
# puts("definition finished: #{name} (#{application_id})")
|
||||
# puts(" entity count: #{definition.entities.count}")
|
||||
@@ -149,6 +159,7 @@ module SpeckleConnector
|
||||
# rubocop:disable Metrics/CyclomaticComplexity
|
||||
# rubocop:disable Metrics/PerceivedComplexity
|
||||
def self.group_entities_to_speckle(entities, preferences, speckle_state, parent, &convert)
|
||||
entities = entities.reject(&:hidden?)
|
||||
orphan_edges = entities.grep(Sketchup::Edge).filter { |edge| edge.faces.none? }
|
||||
lines = orphan_edges.collect do |orphan_edge|
|
||||
new_speckle_state, converted = convert.call(orphan_edge, preferences, speckle_state, parent)
|
||||
|
||||
@@ -5,6 +5,8 @@ require_relative 'transform'
|
||||
require_relative 'block_definition'
|
||||
require_relative '../base'
|
||||
require_relative '../geometry/bounding_box'
|
||||
require_relative '../other/mapped_block_wrapper'
|
||||
require_relative '../built_elements/revit/family_instance'
|
||||
require_relative '../../sketchup_model/dictionary/base_dictionary_handler'
|
||||
require_relative '../../sketchup_model/dictionary/speckle_schema_dictionary_handler'
|
||||
require_relative '../../sketchup_model/query/layer'
|
||||
@@ -40,7 +42,7 @@ module SpeckleConnector
|
||||
self[:renderMaterial] = render_material
|
||||
self[:transform] = transform
|
||||
self[:sketchup_attributes] = sketchup_attributes if sketchup_attributes.any?
|
||||
self[:SpeckleSchema] = speckle_schema if speckle_schema.any?
|
||||
self[:speckle_schema] = speckle_schema if speckle_schema.any?
|
||||
# FIXME: Since blockDefinition sends with @ as detached, block basePlane renders on viewer.
|
||||
self['@@definition'] = block_definition
|
||||
end
|
||||
@@ -72,7 +74,7 @@ module SpeckleConnector
|
||||
|
||||
# @param component_instance [Sketchup::ComponentInstance] component instance to convert Speckle BlockInstance
|
||||
# rubocop:disable Metrics/MethodLength
|
||||
def self.from_component_instance(component_instance, units, preferences, speckle_state, &convert)
|
||||
def self.from_component_instance(component_instance, units, preferences, speckle_state, path: nil, &convert)
|
||||
new_speckle_state, block_definition = convert.call(
|
||||
component_instance.definition,
|
||||
preferences,
|
||||
@@ -87,6 +89,15 @@ module SpeckleConnector
|
||||
speckle_schema = SketchupModel::Dictionary::SpeckleSchemaDictionaryHandler
|
||||
.speckle_schema_to_speckle(component_instance)
|
||||
|
||||
if speckle_schema.empty?
|
||||
speckle_schema = SketchupModel::Dictionary::SpeckleSchemaDictionaryHandler
|
||||
.speckle_schema_to_speckle(component_instance.definition)
|
||||
end
|
||||
|
||||
# transform into global if any path provided
|
||||
transformation = component_instance.transformation
|
||||
transformation = SketchupModel::Query::Entity.global_transformation(component_instance, path) if path
|
||||
|
||||
block_instance = BlockInstance.new(
|
||||
units: units,
|
||||
is_sketchup_group: false,
|
||||
@@ -96,13 +107,45 @@ module SpeckleConnector
|
||||
else
|
||||
RenderMaterial.from_material(component_instance.material)
|
||||
end,
|
||||
transform: Other::Transform.from_transformation(component_instance.transformation, units),
|
||||
transform: Other::Transform.from_transformation(transformation, units),
|
||||
block_definition: block_definition,
|
||||
layer: SketchupModel::Query::Layer.entity_path(component_instance),
|
||||
sketchup_attributes: att,
|
||||
speckle_schema: speckle_schema,
|
||||
application_id: component_instance.persistent_id.to_s
|
||||
)
|
||||
|
||||
if speckle_schema
|
||||
case speckle_schema['method']
|
||||
when 'New Revit Family'
|
||||
# duplicate already converted one to attach without speckle schema into mapped block wrapper
|
||||
copy_block_instance = block_instance.clone(freeze: true)
|
||||
block_instance['@SpeckleSchema'] = SpeckleObjects::Other::MappedBlockWrapper.new(
|
||||
category: speckle_schema['category'],
|
||||
units: units,
|
||||
instance: copy_block_instance,
|
||||
application_id: component_instance.persistent_id.to_s
|
||||
)
|
||||
when 'Family Instance'
|
||||
level = speckle_state.speckle_mapper_state.mapper_source
|
||||
.levels.find { |l| l[:name] == speckle_schema['level'] }
|
||||
family = speckle_schema['family']
|
||||
type = speckle_schema['family_type']
|
||||
block_instance['@SpeckleSchema'] = SpeckleObjects::BuiltElements::Revit::FamilyInstance.new(
|
||||
family: family,
|
||||
type: type,
|
||||
level: level,
|
||||
units: units,
|
||||
base_point: SpeckleObjects::Geometry::Point.from_vertex(
|
||||
component_instance.definition.insertion_point.transform(transformation),
|
||||
units
|
||||
),
|
||||
rotation: calculate_rotation(transformation.to_a),
|
||||
application_id: component_instance.persistent_id.to_s
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
return speckle_state, block_instance
|
||||
end
|
||||
# rubocop:enable Metrics/MethodLength
|
||||
@@ -228,6 +271,26 @@ module SpeckleConnector
|
||||
instance_transform = instance.transformation
|
||||
instance.transform!(instance_transform * transform.inverse * instance_transform.inverse)
|
||||
end
|
||||
|
||||
def self.calculate_rotation(matrix)
|
||||
# Ensure the matrix is a flat array with 16 elements
|
||||
unless matrix.is_a?(Array) && matrix.size == 16
|
||||
raise ArgumentError, 'Matrix must be an array with 16 elements'
|
||||
end
|
||||
|
||||
# Extract the elements of the 2x2 rotation sub-matrix
|
||||
cos_theta = matrix[0] # First column, first row
|
||||
sin_theta = matrix[1] # Second column, first row
|
||||
|
||||
# Calculate the rotation angle in radians
|
||||
theta = Math.atan2(sin_theta, cos_theta)
|
||||
|
||||
# Ensure the angle is between -π and π
|
||||
theta -= 2 * Math::PI while theta > Math::PI
|
||||
theta += 2 * Math::PI while theta < -Math::PI
|
||||
|
||||
theta
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -9,7 +9,6 @@ module SpeckleConnector
|
||||
module Other
|
||||
# DisplayStyle object for layer.
|
||||
class DisplayStyle < Base
|
||||
|
||||
def initialize(name:, color:, line_type:)
|
||||
super(
|
||||
speckle_type: OBJECTS_OTHER_DISPLAYSTYLE,
|
||||
|
||||
@@ -22,9 +22,15 @@ module SpeckleConnector
|
||||
|
||||
return format_naming_convention([family, type, category, element_id]) unless element_id.nil?
|
||||
|
||||
return "def::#{def_obj['applicationId']}" unless def_obj['applicationId'].nil?
|
||||
name = def_obj['name']
|
||||
return "#{name}::#{def_obj['applicationId']}" if !name.nil? && !def_obj['applicationId'].nil?
|
||||
|
||||
return "def::#{def_obj['id']}"
|
||||
return "#{name}::#{def_obj['id']}" unless name.nil?
|
||||
|
||||
speckle_type = def_obj['speckle_type'].split('.').last
|
||||
return "#{speckle_type}::#{def_obj['applicationId']}" unless def_obj['applicationId'].nil?
|
||||
|
||||
return "#{speckle_type}::#{def_obj['id']}"
|
||||
end
|
||||
|
||||
def self.format_naming_convention(entries)
|
||||
@@ -41,6 +47,13 @@ module SpeckleConnector
|
||||
name
|
||||
end
|
||||
|
||||
# Get instance name as speckle_type if it is structured as `speckle_type::application_id`
|
||||
def self.get_instance_name(definition_name)
|
||||
return definition_name unless definition_name.include?('::')
|
||||
|
||||
definition_name.split('::').first
|
||||
end
|
||||
|
||||
# Creates a component definition and instance from a speckle object with a display value
|
||||
# @param state [States::State] state of the application.
|
||||
def self.to_native(state, obj, layer, entities, &convert_to_native)
|
||||
@@ -49,11 +62,7 @@ module SpeckleConnector
|
||||
obj['name'] = get_definition_name(obj)
|
||||
|
||||
state, _definitions = BlockDefinition.to_native(
|
||||
state,
|
||||
obj,
|
||||
layer,
|
||||
entities,
|
||||
&convert_to_native
|
||||
state, obj, layer, entities, &convert_to_native
|
||||
)
|
||||
|
||||
definition = state.sketchup_state.sketchup_model.definitions[BlockDefinition.get_definition_name(obj)]
|
||||
@@ -62,7 +71,7 @@ module SpeckleConnector
|
||||
t_arr = obj['transform']
|
||||
transform = t_arr.nil? ? Geom::Transformation.new : Other::Transform.to_native(t_arr, obj['units'])
|
||||
instance = entities.add_instance(definition, transform)
|
||||
instance.name = obj['name'] unless obj['name'].nil?
|
||||
instance.name = get_instance_name(obj['name']) unless obj['name'].nil?
|
||||
instance.layer = layer unless layer.nil?
|
||||
# Align instance axes that created from display value. (without any transform)
|
||||
# BlockInstance.align_instance_axes(instance)
|
||||
@@ -70,15 +79,23 @@ module SpeckleConnector
|
||||
end
|
||||
|
||||
def self.collect_definition_geometries(obj)
|
||||
obj['geometry'] = obj['displayValue']
|
||||
obj['geometry'] = obj['displayValue'] || obj['@displayValue']
|
||||
|
||||
if !obj['elements'].nil? && obj['elements'].is_a?(Array)
|
||||
obj['elements'].each do |element|
|
||||
# Mullions is a special case here, they are extracted as base object with @displayValue from revit..
|
||||
if element['@displayValue'].nil?
|
||||
obj['geometry'].append(element)
|
||||
else
|
||||
obj['geometry'] += element['@displayValue']
|
||||
elements = obj['elements'] || obj['@elements']
|
||||
|
||||
# if only elements are there then assign only elements, there are some cases that RevitWalls can only
|
||||
# have elements instead of display value
|
||||
if obj['geometry'].nil? && !elements.nil?
|
||||
obj['geometry'] = elements
|
||||
else
|
||||
if !elements.nil? && elements.is_a?(Array)
|
||||
elements.each do |element|
|
||||
# Mullions is a special case here, they are extracted as base object with @displayValue from revit..
|
||||
if element['@displayValue'].nil?
|
||||
obj['geometry'].append(element)
|
||||
else
|
||||
obj['geometry'] += element['@displayValue']
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative '../base'
|
||||
|
||||
module SpeckleConnector
|
||||
module SpeckleObjects
|
||||
module Other
|
||||
# MappedBlockWrapper object definition for Speckle.
|
||||
class MappedBlockWrapper < Base
|
||||
SPECKLE_TYPE = 'Objects.Other.MappedBlockWrapper'
|
||||
def initialize(category:, units:, instance:, application_id: nil)
|
||||
super(
|
||||
speckle_type: SPECKLE_TYPE,
|
||||
total_children_count: 0,
|
||||
application_id: application_id,
|
||||
id: nil
|
||||
)
|
||||
self[:category] = category
|
||||
self[:units] = units
|
||||
self[:instance] = instance
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -19,7 +19,7 @@ module SpeckleConnector
|
||||
id: nil
|
||||
)
|
||||
self[:units] = units
|
||||
self[:value] = value
|
||||
self[:matrix] = value
|
||||
end
|
||||
|
||||
def self.from_transformation(transformation, units)
|
||||
|
||||
@@ -11,7 +11,7 @@ module SpeckleConnector
|
||||
SPECKLE_TYPE = 'Speckle.Core.Models.Collection'
|
||||
|
||||
# rubocop:disable Metrics/ParameterLists
|
||||
def initialize(name:, visible:, is_folder:, line_style: nil, color: nil, layers_and_folders: [],
|
||||
def initialize(name:, visible:, is_folder:, full_path: nil, line_style: nil, color: nil, layers_and_folders: [],
|
||||
application_id: nil)
|
||||
super(
|
||||
speckle_type: SPECKLE_TYPE,
|
||||
@@ -23,6 +23,7 @@ module SpeckleConnector
|
||||
self[:color] = color
|
||||
self[:visible] = visible
|
||||
self[:is_folder] = is_folder
|
||||
self[:full_path] = full_path unless full_path.nil?
|
||||
self[:line_style] = line_style unless line_style.nil?
|
||||
self[:collectionType] = 'layer'
|
||||
self[:elements] = layers_and_folders if layers_and_folders.any?
|
||||
@@ -43,14 +44,31 @@ module SpeckleConnector
|
||||
folder.add_layer(layer) if folder.is_a?(Sketchup::LayerFolder)
|
||||
end
|
||||
|
||||
def self.to_native_layer_folder(speckle_layer_folder, folder, sketchup_model)
|
||||
speckle_layers = speckle_layer_folder[:elements].select { |layer_or_fol| layer_or_fol[:elements].nil? }
|
||||
# Flat layer conversion.
|
||||
def self.to_native_flat_layers(layers_relation, sketchup_model)
|
||||
speckle_layers = layers_relation[:elements]
|
||||
|
||||
elements_to_layers(speckle_layers, sketchup_model)
|
||||
end
|
||||
|
||||
# Converts elements to layers with it's full path.
|
||||
def self.elements_to_layers(elements, sketchup_model)
|
||||
elements.each do |element|
|
||||
element[:name] = element[:full_path]
|
||||
to_native_layer(element, sketchup_model.layers, sketchup_model)
|
||||
elements_to_layers(element[:elements], sketchup_model) unless element[:elements].nil?
|
||||
end
|
||||
end
|
||||
|
||||
# Nested layer conversion with folders.
|
||||
def self.to_native_layer_folder(layers_relation, folder, sketchup_model)
|
||||
speckle_layers = layers_relation[:elements].select { |layer_or_fol| layer_or_fol[:elements].nil? }
|
||||
|
||||
speckle_layers.each do |speckle_layer|
|
||||
to_native_layer(speckle_layer, folder, sketchup_model)
|
||||
end
|
||||
|
||||
speckle_folders = speckle_layer_folder[:elements].reject { |layer_or_fol| layer_or_fol[:elements].nil? }
|
||||
speckle_folders = layers_relation[:elements].reject { |layer_or_fol| layer_or_fol[:elements].nil? }
|
||||
|
||||
speckle_folders.each do |speckle_folder|
|
||||
sub_folder = folder.add_folder(speckle_folder[:name])
|
||||
|
||||
@@ -22,26 +22,18 @@ module SpeckleConnector
|
||||
self[:elements] = layers
|
||||
end
|
||||
|
||||
def self.element_to_relation(elements)
|
||||
elements.collect do |element|
|
||||
next unless element['speckle_type'] == SPECKLE_CORE_MODELS_COLLECTION
|
||||
|
||||
is_folder = element['elements'].any? { |e| e['speckle_type'] == SPECKLE_CORE_MODELS_COLLECTION }
|
||||
color = element['color'] || element['displayStyle']['color'] unless element['displayStyle'].nil?
|
||||
Layer.new(
|
||||
name: element['name'],
|
||||
visible: element['visible'],
|
||||
is_folder: is_folder,
|
||||
color: color,
|
||||
layers_and_folders: element_to_relation(element['elements'])
|
||||
)
|
||||
end.compact
|
||||
end
|
||||
|
||||
def self.extract_relations(commit_obj)
|
||||
# Extract relations from commit obj to create layers in advance.
|
||||
# By doing this, also checks layers will be created as flat list or nested structure according to source app.
|
||||
# @param commit_obj [Hash] commit object to extract layer relations.
|
||||
# @param source_app [String] source application to decide layer creation strategy.
|
||||
# Currently for
|
||||
# - Revit: we don't create layers in advance because we create layers according to categories.
|
||||
# - SketchUp: we create layers in advance as nested.
|
||||
# - Rhino: we create layers in advance as flat list with it's full path.
|
||||
def self.extract_relations(commit_obj, source_app)
|
||||
return nil unless commit_obj['speckle_type'] == SPECKLE_CORE_MODELS_COLLECTION
|
||||
|
||||
elements = element_to_relation(commit_obj['elements'])
|
||||
elements = element_to_relation(commit_obj['elements'], source_app, [])
|
||||
|
||||
Layers.new(
|
||||
active: commit_obj['active_layer'],
|
||||
@@ -49,10 +41,41 @@ module SpeckleConnector
|
||||
)
|
||||
end
|
||||
|
||||
def self.to_native(layers_relation, sketchup_model)
|
||||
folder = sketchup_model.layers
|
||||
# rubocop:disable Metrics/CyclomaticComplexity
|
||||
def self.element_to_relation(elements, source_app, parent_layers)
|
||||
elements.collect do |element|
|
||||
next unless element['speckle_type'] == SPECKLE_CORE_MODELS_COLLECTION
|
||||
|
||||
SpeckleObjects::Relations::Layer.to_native_layer_folder(layers_relation, folder, sketchup_model)
|
||||
layers_tree = parent_layers.dup.append(element['name'])
|
||||
full_path = ''
|
||||
parent_layers.each { |parent| full_path += "#{parent}::" }
|
||||
full_path += element['name']
|
||||
# Add this info to commit object to check later layer_collection conversion
|
||||
element['full_path'] = full_path if source_app.include?('rhino')
|
||||
|
||||
is_folder = element['elements'].any? { |e| e['speckle_type'] == SPECKLE_CORE_MODELS_COLLECTION }
|
||||
color = element['color'] || element['displayStyle']['color'] unless element['displayStyle'].nil?
|
||||
Layer.new(
|
||||
name: element['name'], visible: element['visible'], is_folder: is_folder,
|
||||
color: color, full_path: full_path,
|
||||
layers_and_folders: element_to_relation(element['elements'], source_app, layers_tree)
|
||||
)
|
||||
end.compact
|
||||
end
|
||||
# rubocop:enable Metrics/CyclomaticComplexity
|
||||
|
||||
def self.to_native(obj, source_app, sketchup_model)
|
||||
layers_relation = extract_relations(obj, source_app)
|
||||
return if layers_relation.nil?
|
||||
|
||||
folder = sketchup_model.layers
|
||||
is_flat = source_app.include?('rhino')
|
||||
|
||||
if is_flat
|
||||
SpeckleObjects::Relations::Layer.to_native_flat_layers(layers_relation, sketchup_model)
|
||||
else
|
||||
SpeckleObjects::Relations::Layer.to_native_layer_folder(layers_relation, folder, sketchup_model)
|
||||
end
|
||||
|
||||
active_layer = folder.to_a.find { |layer| layer.display_name == layers_relation['active_layer'] }
|
||||
sketchup_model.active_layer = active_layer unless active_layer.nil?
|
||||
|
||||
@@ -15,8 +15,10 @@ module SpeckleConnector
|
||||
family = def_obj['family']
|
||||
type = def_obj['type']
|
||||
category = def_obj['category']
|
||||
element_id = def_obj['elementId']
|
||||
id = def_obj['id']
|
||||
|
||||
return "#{family}-#{type}-#{category}-#{def_obj['elementId']}"
|
||||
return "#{family}-#{type}-#{category}-#{element_id}-#{id}"
|
||||
end
|
||||
|
||||
def self.to_native(state, definition, layer, entities, &convert_to_native)
|
||||
|
||||
@@ -31,10 +31,8 @@ module SpeckleConnector
|
||||
|
||||
if collection_type.include?('model')
|
||||
ModelCollection.to_native(state, collection, layer, entities, &convert_to_native)
|
||||
elsif ['layer', 'Revit Category'].include?(collection_type)
|
||||
LayerCollection.to_native(state, collection, layer, entities, &convert_to_native)
|
||||
else
|
||||
return state, []
|
||||
LayerCollection.to_native(state, collection, layer, entities, &convert_to_native)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative 'collection'
|
||||
|
||||
module SpeckleConnector
|
||||
module SpeckleObjects
|
||||
module Speckle
|
||||
module Core
|
||||
module Models
|
||||
# VectorLayerCollection object that collect GIS vector elements under it's elements.
|
||||
class GisLayerCollection < Collection
|
||||
# @param state [States::State] state of the Speckle application.
|
||||
def self.to_native(state, vector_layer_collection, layer_or_folder, entities, &convert_to_native)
|
||||
elements = vector_layer_collection['elements']
|
||||
|
||||
elements.each do |element|
|
||||
new_state, _converted_entities = convert_to_native.call(state, element, layer_or_folder, entities)
|
||||
state = new_state
|
||||
end
|
||||
|
||||
return state, []
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -99,12 +99,13 @@ module SpeckleConnector
|
||||
sketchup_model = state.sketchup_state.sketchup_model
|
||||
elements = layer_collection['elements']
|
||||
name = layer_collection['name']
|
||||
name = layer_collection['full_path'] if layer_collection['full_path']
|
||||
|
||||
layer = sketchup_model.layers.find { |l| l.display_name == name }
|
||||
layer_or_folder = layer if layer
|
||||
|
||||
elements.each do |element|
|
||||
new_state = convert_to_native.call(state, element, layer_or_folder, entities)
|
||||
new_state, _converted_entities = convert_to_native.call(state, element, layer_or_folder, entities)
|
||||
state = new_state
|
||||
end
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ require_relative 'collection'
|
||||
require_relative 'layer_collection'
|
||||
require_relative '../../../built_elements/view3d'
|
||||
require_relative '../../../built_elements/revit/direct_shape'
|
||||
require_relative '../../../../mapper/mapper'
|
||||
|
||||
module SpeckleConnector
|
||||
module SpeckleObjects
|
||||
@@ -13,7 +14,9 @@ module SpeckleConnector
|
||||
# ModelCollection object that collect other speckle objects under it's elements.
|
||||
class ModelCollection < Collection
|
||||
DIRECT_SHAPE = SpeckleObjects::BuiltElements::Revit::DirectShape
|
||||
QUERY = SketchupModel::Query
|
||||
VIEW3D = SpeckleObjects::BuiltElements::View3d
|
||||
SPECKLE_SCHEMA_DICTIONARY_HANDLER = SketchupModel::Dictionary::SpeckleSchemaDictionaryHandler
|
||||
def initialize(name:, active_layer:, elements: [], application_id: nil)
|
||||
super(
|
||||
name: name,
|
||||
@@ -24,6 +27,27 @@ module SpeckleConnector
|
||||
self[:active_layer] = active_layer
|
||||
end
|
||||
|
||||
def self.to_native(state, model_collection, layer, entities, &convert_to_native)
|
||||
elements = model_collection['elements']
|
||||
views = model_collection['@Views']
|
||||
if views
|
||||
views.each do |view|
|
||||
new_state, _converted_entities = convert_to_native.call(state, view, layer, entities)
|
||||
state = new_state
|
||||
end
|
||||
end
|
||||
|
||||
elements.each do |element|
|
||||
new_state, _converted_entities = convert_to_native.call(state, element, layer, entities)
|
||||
state = new_state
|
||||
end
|
||||
|
||||
active_layer = model_collection['active_layer']
|
||||
state.sketchup_state.sketchup_model.active_layer = active_layer unless active_layer.nil?
|
||||
|
||||
return state, []
|
||||
end
|
||||
|
||||
def self.from_sketchup_model(sketchup_model, speckle_state, units, preferences, &convert)
|
||||
model_collection = ModelCollection.new(
|
||||
name: 'Sketchup Model', active_layer: sketchup_model.active_layer.display_name,
|
||||
@@ -31,7 +55,8 @@ module SpeckleConnector
|
||||
)
|
||||
|
||||
# Direct shapes will pass directly to elements which are already flattened with all children
|
||||
model_collection[:elements] += collect_direct_shapes(sketchup_model, units, preferences)
|
||||
model_collection[:elements] += collect_mapped_entities(speckle_state, sketchup_model, units,
|
||||
preferences, &convert)
|
||||
|
||||
# Views will pass directly to elements since they don't have any relation with layers and geometries.
|
||||
model_collection[:elements] += VIEW3D.from_model(sketchup_model, units) if sketchup_model.pages.any?
|
||||
@@ -52,29 +77,13 @@ module SpeckleConnector
|
||||
return speckle_state, model_collection
|
||||
end
|
||||
|
||||
def self.collect_direct_shapes(sketchup_model, units, preferences)
|
||||
DIRECT_SHAPE.direct_shapes_on_selection(sketchup_model).collect do |entities|
|
||||
entity = entities[0]
|
||||
path = entities[1..-1]
|
||||
|
||||
direct_shape = DIRECT_SHAPE.from_entity(entity, path, units, preferences)
|
||||
[direct_shape, [entity]]
|
||||
# @param sketchup_model [Sketchup::Model] active model to retrieve and convert mapped entities.
|
||||
def self.collect_mapped_entities(speckle_state, sketchup_model, units, preferences, &convert)
|
||||
mapped_entities = Mapper.mapped_entities_on_selection(sketchup_model)
|
||||
mapped_entities.collect do |entity_with_path|
|
||||
Mapper.convert_mapped_entity(speckle_state, entity_with_path, preferences, units, &convert)
|
||||
end
|
||||
end
|
||||
|
||||
def self.to_native(state, model_collection, layer, entities, &convert_to_native)
|
||||
elements = model_collection['elements']
|
||||
|
||||
elements.each do |element|
|
||||
new_state = convert_to_native.call(state, element, layer, entities)
|
||||
state = new_state
|
||||
end
|
||||
|
||||
active_layer = model_collection['active_layer']
|
||||
state.sketchup_state.sketchup_model.active_layer = active_layer unless active_layer.nil?
|
||||
|
||||
return state, []
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative '../immutable/immutable'
|
||||
require_relative '../callbacks/callback_message'
|
||||
require_relative '../speckle_entities/speckle_entity'
|
||||
require_relative '../mapper/mapper_source'
|
||||
|
||||
module SpeckleConnector
|
||||
module States
|
||||
# State of the speckle on ruby.
|
||||
class SpeckleMapperState
|
||||
include Immutable::ImmutableUtils
|
||||
|
||||
# @return [ImmutableHash{Integer=>Sketchup::Entity}] persistent_id of the sketchup entity and itself
|
||||
attr_reader :mapped_entities
|
||||
|
||||
# @return [Mapper::MapperSource] source of the mapper.
|
||||
attr_reader :mapper_source
|
||||
|
||||
def initialize
|
||||
@mapped_entities = Immutable::EmptyHash
|
||||
@mapper_source = nil
|
||||
end
|
||||
|
||||
def with_mapped_entity(entity)
|
||||
new_mapped_entities = mapped_entities.put(entity.persistent_id, entity)
|
||||
with_mapped_entities(new_mapped_entities)
|
||||
end
|
||||
|
||||
def with_removed_mapped_entity(entity)
|
||||
new_mapped_entities = mapped_entities.delete(entity.persistent_id)
|
||||
with_mapped_entities(new_mapped_entities)
|
||||
end
|
||||
|
||||
def with_mapped_entities(new_mapped_entities)
|
||||
with(:@mapped_entities => new_mapped_entities)
|
||||
end
|
||||
|
||||
def with_mapper_source(mapper_source)
|
||||
# TODO: Check/Sync here parameters of the mapped entities.
|
||||
with(:@mapper_source => mapper_source)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,5 +1,6 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative 'speckle_mapper_state'
|
||||
require_relative '../immutable/immutable'
|
||||
require_relative '../callbacks/callback_message'
|
||||
require_relative '../speckle_entities/speckle_entity'
|
||||
@@ -10,13 +11,13 @@ module SpeckleConnector
|
||||
class SpeckleState
|
||||
include Immutable::ImmutableUtils
|
||||
|
||||
# @return [States::SpeckleMapperState] state of the mapper.
|
||||
attr_reader :speckle_mapper_state
|
||||
|
||||
# @return [ImmutableHash{Integer=>SpeckleEntities::SpeckleEntity}] persistent_id of the sketchup entity and
|
||||
# corresponding speckle entity
|
||||
attr_reader :speckle_entities
|
||||
|
||||
# @return [ImmutableHash{Integer=>Sketchup::Entity}] persistent_id of the sketchup entity and itself
|
||||
attr_reader :mapped_entities
|
||||
|
||||
# @return [Array] accounts on appdata.
|
||||
attr_reader :accounts
|
||||
|
||||
@@ -47,10 +48,10 @@ module SpeckleConnector
|
||||
@message_queue = queue
|
||||
@stream_queue = stream_queue
|
||||
@speckle_entities = Immutable::EmptyHash
|
||||
@mapped_entities = Immutable::EmptyHash
|
||||
@render_materials = Immutable::EmptyHash
|
||||
@definitions = Immutable::EmptyHash
|
||||
@relation = Relations::ManyToOneRelation.new
|
||||
@speckle_mapper_state = SpeckleMapperState.new
|
||||
end
|
||||
|
||||
# @param callback_name [String] name of the callback command
|
||||
@@ -68,13 +69,19 @@ module SpeckleConnector
|
||||
with(:@message_queue => new_queue)
|
||||
end
|
||||
|
||||
def with_selection_queue(selection_parameters)
|
||||
def with_mapper_selection_queue(selection_parameters)
|
||||
new_queue = message_queue.merge({ "entitySelected":
|
||||
"entitySelected(#{JSON.generate(selection_parameters)})" })
|
||||
with(:@message_queue => new_queue)
|
||||
end
|
||||
|
||||
def with_deselection_queue
|
||||
def with_mapper_init_queue(init_parameters)
|
||||
new_queue = message_queue.merge({ "mapperInitialized":
|
||||
"mapperInitialized(#{JSON.generate(init_parameters)})" })
|
||||
with(:@message_queue => new_queue)
|
||||
end
|
||||
|
||||
def with_mapper_deselection_queue
|
||||
new_queue = message_queue.merge({ "entitiesDeselected": 'entitiesDeselected()' })
|
||||
with(:@message_queue => new_queue)
|
||||
end
|
||||
@@ -95,14 +102,29 @@ module SpeckleConnector
|
||||
with(:@accounts => new_accounts)
|
||||
end
|
||||
|
||||
def with_mapper_source(mapper_source)
|
||||
new_speckle_mapper_state = speckle_mapper_state.with_mapper_source(mapper_source)
|
||||
with(:@speckle_mapper_state => new_speckle_mapper_state)
|
||||
end
|
||||
|
||||
def with_removed_mapper_source
|
||||
new_speckle_mapper_state = speckle_mapper_state.with_mapper_source(nil)
|
||||
with(:@speckle_mapper_state => new_speckle_mapper_state)
|
||||
end
|
||||
|
||||
def with_mapped_entity(entity)
|
||||
new_mapped_entities = mapped_entities.put(entity.persistent_id, entity)
|
||||
with_mapped_entities(new_mapped_entities)
|
||||
new_speckle_mapper_state = speckle_mapper_state.with_mapped_entity(entity)
|
||||
with(:@speckle_mapper_state => new_speckle_mapper_state)
|
||||
end
|
||||
|
||||
def with_removed_mapped_entity(entity)
|
||||
new_mapped_entities = mapped_entities.delete(entity.persistent_id)
|
||||
with_mapped_entities(new_mapped_entities)
|
||||
new_speckle_mapper_state = speckle_mapper_state.with_removed_mapped_entity(entity)
|
||||
with(:@speckle_mapper_state => new_speckle_mapper_state)
|
||||
end
|
||||
|
||||
def with_mapped_entities(new_mapped_entities)
|
||||
new_speckle_mapper_state = speckle_mapper_state.with_mapped_entities(new_mapped_entities)
|
||||
with(:@speckle_mapper_state => new_speckle_mapper_state)
|
||||
end
|
||||
|
||||
def with_speckle_entity(traversed_entity)
|
||||
@@ -114,10 +136,6 @@ module SpeckleConnector
|
||||
with(:@speckle_entities => new_speckle_entities)
|
||||
end
|
||||
|
||||
def with_mapped_entities(new_mapped_entities)
|
||||
with(:@mapped_entities => new_mapped_entities)
|
||||
end
|
||||
|
||||
def with_relation(new_relation)
|
||||
with(:@relation => new_relation)
|
||||
end
|
||||
|
||||
@@ -41,15 +41,20 @@ module SpeckleConnector
|
||||
with(:@speckle_state => new_speckle_state)
|
||||
end
|
||||
|
||||
def with_selection_queue(selection_parameters)
|
||||
def with_mapper_selection_queue(selection_parameters)
|
||||
new_speckle_state = if selection_parameters[:selection].any?
|
||||
speckle_state.with_selection_queue(selection_parameters)
|
||||
speckle_state.with_mapper_selection_queue(selection_parameters)
|
||||
else
|
||||
speckle_state.with_deselection_queue
|
||||
speckle_state.with_mapper_deselection_queue
|
||||
end
|
||||
with(:@speckle_state => new_speckle_state)
|
||||
end
|
||||
|
||||
def with_mapper_init_queue(init_parameters)
|
||||
new_speckle_state = speckle_state.with_mapper_init_queue(init_parameters)
|
||||
with(:@speckle_state => new_speckle_state)
|
||||
end
|
||||
|
||||
def with_empty_stream_queue
|
||||
new_speckle_state = speckle_state.with(:@stream_queue => {})
|
||||
with(:@speckle_state => new_speckle_state)
|
||||
|
||||
@@ -57,6 +57,10 @@ module SpeckleConnector
|
||||
html_dialog.execute_script(data)
|
||||
end
|
||||
|
||||
def reset_dialog_location
|
||||
html_dialog.center
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# @return [UI::HtmlDialog] the Sketchup interface to dialog
|
||||
@@ -77,8 +81,9 @@ module SpeckleConnector
|
||||
dialog.set_can_close do
|
||||
true
|
||||
end
|
||||
File.exist?(@htm_file) ? dialog.set_file(@htm_file) : dialog.set_url('http://localhost:8081')
|
||||
# File.exist?(@htm_file) ? dialog.set_file(@htm_file) : dialog.set_url('http://localhost:8081')
|
||||
# dialog.set_url('http://localhost:8081') # uncomment this line if you want to use your local version of ui
|
||||
dialog.set_url('https://development--speckle-sketchup-dui2.netlify.app/')
|
||||
add_exec_callback(dialog)
|
||||
dialog
|
||||
end
|
||||
|
||||
@@ -5,7 +5,7 @@ module SpeckleConnector
|
||||
# An interface to Sketchup user interface. This object controls the menu `Extensions->Speckle` in Sketchup's menu,
|
||||
# the Speckle toolbar and sending message to the user via Sketchup.
|
||||
class SketchupUi
|
||||
MENU_TITLE = 'Speckle'
|
||||
MENU_TITLE = 'Speckle (Legacy)'
|
||||
BEFORE_NEVER_SHOWN = -1
|
||||
|
||||
# @return [Sketchup::Menu] the menu of the Speckle
|
||||
|
||||
@@ -16,7 +16,9 @@ require_relative '../commands/model_preferences_updated'
|
||||
require_relative '../commands/activate_diffing'
|
||||
require_relative '../commands/apply_mappings'
|
||||
require_relative '../commands/clear_mappings'
|
||||
require_relative '../commands/mapper_source_updated'
|
||||
|
||||
require_relative '../actions/mapper_initialized'
|
||||
require_relative '../actions/reload_accounts'
|
||||
require_relative '../actions/load_saved_streams'
|
||||
require_relative '../actions/init_local_accounts'
|
||||
@@ -29,6 +31,7 @@ require_relative '../actions/isolate_mappings_from_table'
|
||||
require_relative '../actions/hide_mappings_from_table'
|
||||
require_relative '../actions/select_mappings_from_table'
|
||||
require_relative '../actions/show_all_entities'
|
||||
require_relative '../actions/clear_mapper_source'
|
||||
|
||||
module SpeckleConnector
|
||||
module Ui
|
||||
@@ -89,7 +92,10 @@ module SpeckleConnector
|
||||
isolate_mappings_from_table: Commands::ActionCommand.new(@app, Actions::IsolateMappingsFromTable),
|
||||
hide_mappings_from_table: Commands::ActionCommand.new(@app, Actions::HideMappingsFromTable),
|
||||
select_mappings_from_table: Commands::ActionCommand.new(@app, Actions::SelectMappingsFromTable),
|
||||
show_all_entities: Commands::ActionCommand.new(@app, Actions::ShowAllEntities)
|
||||
show_all_entities: Commands::ActionCommand.new(@app, Actions::ShowAllEntities),
|
||||
mapper_source_updated: Commands::MapperSourceUpdated.new(@app),
|
||||
clear_mapper_source: Commands::ActionCommand.new(@app, Actions::ClearMapperSource),
|
||||
mapper_initialized: Commands::ActionCommand.new(@app, Actions::MapperInitialized)
|
||||
}.freeze
|
||||
end
|
||||
# rubocop:enable Metrics/MethodLength
|
||||
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
VUE_APP_DEV_TOKEN=
|
||||
VUE_APP_SPECKLE_NAME=SpeckleSketchup
|
||||
VUE_APP_DEFAULT_SERVER=https://latest.speckle.dev
|
||||
VUE_APP_DEFAULT_SERVER=https://latest.speckle.systems
|
||||
+61
-33
@@ -1,6 +1,7 @@
|
||||
<template>
|
||||
<v-app>
|
||||
<v-main>
|
||||
<legacy-dialog/>
|
||||
<v-app-bar app flat height="50">
|
||||
<v-img
|
||||
class="mx-auto px-0"
|
||||
@@ -15,7 +16,7 @@
|
||||
>
|
||||
<v-tabs-slider class="mx-sm-1"></v-tabs-slider>
|
||||
<v-tab href="#streams">
|
||||
{{"Streams"}}
|
||||
{{ streamsText }}
|
||||
</v-tab>
|
||||
<v-tab href="#mapper">
|
||||
{{"Mapper"}}
|
||||
@@ -48,21 +49,25 @@
|
||||
<v-img v-if="user.avatar" :src="user.avatar" />
|
||||
<v-img v-else :src="`https://robohash.org/` + user.id + `.png?size=40x40`" />
|
||||
</v-avatar>
|
||||
<div>
|
||||
<b>{{ user.name }}</b>
|
||||
</div>
|
||||
<div class="caption">
|
||||
{{ user.company }}
|
||||
<br />
|
||||
{{ user.bio ? 'Bio: ' + user.bio : '' }}
|
||||
</div>
|
||||
<div>
|
||||
<b>{{ user.name }}</b>
|
||||
<br />
|
||||
<b>{{ user.email }}</b>
|
||||
</div>
|
||||
<div class="caption">
|
||||
<b>{{ activeAccount().serverInfo.url }}</b>
|
||||
</div>
|
||||
</v-card-text>
|
||||
<v-card-text v-if="accounts()">
|
||||
<v-divider class="my-3" />
|
||||
|
||||
<div v-for="account in accounts()" :key="account.id">
|
||||
<v-btn
|
||||
v-if="account.userInfo.id != user.id"
|
||||
v-if="account.id != activeAccount().id"
|
||||
rounded
|
||||
large
|
||||
class="my-1 elevation-0"
|
||||
@@ -88,7 +93,7 @@
|
||||
<v-text-field
|
||||
v-model="streamSearchQuery"
|
||||
prepend-inner-icon="mdi-magnify"
|
||||
label="Search streams"
|
||||
:label="searchText"
|
||||
background-color="background"
|
||||
hide-details
|
||||
clearable
|
||||
@@ -100,12 +105,13 @@
|
||||
/>
|
||||
</v-container>
|
||||
<create-stream-dialog
|
||||
v-if="accounts().length !== 0"
|
||||
v-if="accounts() && accounts().length !== 0"
|
||||
:is-f-e2-terms="preferences && preferences.user && preferences.user.fe2"
|
||||
:account-id="activeAccount().userInfo.id"
|
||||
:server-url="activeAccount().serverInfo.url"
|
||||
/>
|
||||
<v-container v-if="accounts().length !== 0" fluid>
|
||||
<router-view :stream-search-query="streamSearchQuery" />
|
||||
<v-container v-if="accounts() && accounts().length !== 0" fluid>
|
||||
<router-view :stream-search-query="streamSearchQuery"/>
|
||||
</v-container>
|
||||
<v-container v-else>
|
||||
<login/>
|
||||
@@ -115,7 +121,7 @@
|
||||
</v-tab-item>
|
||||
<v-tab-item :key="2" value="mapper">
|
||||
<v-card flat>
|
||||
<mapper></mapper>
|
||||
<mapper :stream-text="streamText" :branch-text="branchText"></mapper>
|
||||
</v-card>
|
||||
</v-tab-item>
|
||||
</v-tabs-items>
|
||||
@@ -127,8 +133,10 @@
|
||||
/*global sketchup*/
|
||||
import { bus } from './main'
|
||||
import userQuery from './graphql/user.gql'
|
||||
import serverInfoQuery from './graphql/serverInfo.gql'
|
||||
import { onLogin } from './vue-apollo'
|
||||
import Login from "@/views/Login";
|
||||
import LegacyDialog from './components/dialogs/LegacyDialog.vue';
|
||||
|
||||
global.collectPreferences = function (preferences) {
|
||||
bus.$emit('update-preferences', preferences)
|
||||
@@ -143,13 +151,16 @@ global.collectVersions = function (versions) {
|
||||
global.loadAccounts = function (accounts) {
|
||||
console.log('>>> SpeckleSketchup: Loading accounts', accounts)
|
||||
localStorage.setItem('localAccounts', JSON.stringify(accounts))
|
||||
let uuid = localStorage.getItem('uuid')
|
||||
let selectedAccountId = localStorage.getItem('selectedAccountId')
|
||||
if (accounts.length !== 0){
|
||||
if (uuid) {
|
||||
global.setSelectedAccount(accounts.find((acct) => acct['userInfo']['id'] === uuid))
|
||||
} else {
|
||||
global.setSelectedAccount(accounts.find((acct) => acct['isDefault']))
|
||||
if (selectedAccountId) {
|
||||
var account = accounts.find((acct) => acct['id'] === selectedAccountId)
|
||||
if (account){
|
||||
global.setSelectedAccount(account)
|
||||
return
|
||||
}
|
||||
}
|
||||
global.setSelectedAccount(accounts.find((acct) => acct['isDefault']))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,7 +168,8 @@ global.setSelectedAccount = function (account) {
|
||||
localStorage.setItem('selectedAccount', JSON.stringify(account))
|
||||
localStorage.setItem('serverUrl', account['serverInfo']['url'])
|
||||
localStorage.setItem('SpeckleSketchup.AuthToken', account['token'])
|
||||
localStorage.setItem('uuid', account['userInfo']['id'])
|
||||
localStorage.setItem('selectedAccountId', account['id'])
|
||||
localStorage.setItem('frontend2', account['serverInfo']['frontend2'])
|
||||
bus.$emit('selected-account-reloaded')
|
||||
}
|
||||
|
||||
@@ -168,13 +180,14 @@ export default {
|
||||
CreateStreamDialog: () => import('@/components/dialogs/CreateStreamDialog'),
|
||||
SettingsDialog: () => import('@/components/dialogs/SettingsDialog'),
|
||||
GlobalToast: () => import('@/components/GlobalToast'),
|
||||
Mapper: () => import('@/components/Mapper')
|
||||
Mapper: () => import('@/components/Mapper'),
|
||||
LegacyDialog: () => import('@/components/dialogs/LegacyDialog')
|
||||
},
|
||||
props: {
|
||||
size: {
|
||||
type: Number,
|
||||
default: 42
|
||||
},
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@@ -183,7 +196,11 @@ export default {
|
||||
createStreamByIdDialog: false,
|
||||
createStreamByIdText: "",
|
||||
preferences: {},
|
||||
tab: "streams"
|
||||
tab: "streams",
|
||||
searchText: '',
|
||||
streamsText: 'Streams',
|
||||
streamText: 'Stream',
|
||||
branchText: 'Branch'
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -194,8 +211,19 @@ export default {
|
||||
apollo: {
|
||||
user: {
|
||||
query: userQuery
|
||||
},
|
||||
serverInfo: {
|
||||
query: serverInfoQuery
|
||||
}
|
||||
},
|
||||
beforeMount() {
|
||||
// Collect accounts from 'Accounts.db' by ruby sqlite3
|
||||
sketchup.exec({name: "init_local_accounts", data: {}})
|
||||
// Collect preferences to render UI according to it
|
||||
sketchup.exec({name: "collect_preferences", data: {}})
|
||||
// Collect versions to inform mixpanel
|
||||
sketchup.exec({name: "collect_versions", data: {}})
|
||||
},
|
||||
mounted() {
|
||||
bus.$on('selected-account-reloaded', async () => {
|
||||
await onLogin(this.$apollo.provider.defaultClient)
|
||||
@@ -209,30 +237,30 @@ export default {
|
||||
})
|
||||
|
||||
bus.$on('update-preferences', async (preferences) => {
|
||||
let prefs = JSON.parse(preferences)
|
||||
this.preferences = prefs
|
||||
this.preferences = JSON.parse(preferences)
|
||||
this.searchText = this.preferences.user.fe2 ? 'Search projects' : 'Search streams'
|
||||
this.streamsText = this.preferences.user.fe2 ? 'Projects' : 'Streams'
|
||||
this.streamText = this.preferences.user.fe2 ? 'Project' : 'Stream'
|
||||
this.branchText = this.preferences.user.fe2 ? 'Model' : 'Branch'
|
||||
this.$vuetify.theme.dark = this.preferences.user.dark_theme
|
||||
})
|
||||
|
||||
// Collect versions to inform mixpanel
|
||||
sketchup.exec({name: "collect_versions", data: {}})
|
||||
|
||||
// Collect preferences to render UI according to it
|
||||
sketchup.exec({name: "collect_preferences", data: {}})
|
||||
|
||||
// Collect accounts from 'Accounts.db' by ruby sqlite3
|
||||
sketchup.exec({name: "init_local_accounts", data: {}})
|
||||
},
|
||||
methods: {
|
||||
accounts() {
|
||||
return JSON.parse(localStorage.getItem('localAccounts'))
|
||||
},
|
||||
activeAccount(){
|
||||
return this.accounts().find((account) => account['isDefault'])
|
||||
activeAccount() {
|
||||
return JSON.parse(localStorage.getItem('selectedAccount'))
|
||||
},
|
||||
switchAccount(account) {
|
||||
this.$mixpanel.track('Connector Action', { name: 'Account Select' })
|
||||
global.setSelectedAccount(account)
|
||||
|
||||
// Force pushes to reload page to create ApolloClient from scratch
|
||||
// setTimeout(() => {
|
||||
// // timeout to wait a bit for potential sketchup.exec in the mean time calls
|
||||
// location.reload()
|
||||
// }, 200);
|
||||
},
|
||||
requestRefresh() {
|
||||
sketchup.exec({name: 'reload_accounts', data: {}})
|
||||
|
||||
@@ -232,22 +232,27 @@ export default {
|
||||
// }
|
||||
},
|
||||
clearMappingsFromTableSelection(){
|
||||
sketchup.exec({ name: "clear_mappings_from_table", data: this.elementSelection })
|
||||
sketchup.exec({ name: "clear_mappings_from_table", data: this.elementSelection })
|
||||
this.$mixpanel.track('MappingsAction', { name: 'Mappings Clear' })
|
||||
},
|
||||
isolateMappedElementsOnSketchup(){
|
||||
if (this.isIsolated){
|
||||
this.isIsolated = false
|
||||
sketchup.exec({ name: "show_all_entities", data: {} })
|
||||
this.$mixpanel.track('MappingsAction', { name: 'Mappings Un-Isolate' })
|
||||
} else {
|
||||
this.isIsolated = true
|
||||
sketchup.exec({ name: "isolate_mappings_from_table", data: this.elementSelection })
|
||||
this.$mixpanel.track('MappingsAction', { name: 'Mappings Isolate' })
|
||||
}
|
||||
},
|
||||
hideMappedElementsOnSketchup(){
|
||||
sketchup.exec({ name: "hide_mappings_from_table", data: this.elementSelection })
|
||||
sketchup.exec({ name: "hide_mappings_from_table", data: this.elementSelection })
|
||||
this.$mixpanel.track('MappingsAction', { name: 'Mappings Hide' })
|
||||
},
|
||||
selectMappedElementsOnSketchup(){
|
||||
sketchup.exec({ name: "select_mappings_from_table", data: this.elementSelection })
|
||||
sketchup.exec({ name: "select_mappings_from_table", data: this.elementSelection })
|
||||
this.$mixpanel.track('MappingsAction', { name: 'Mappings Select Elements' })
|
||||
},
|
||||
// Update mapped elements table whenever mapped elements has changed.
|
||||
getMappedElementsTableData(){
|
||||
|
||||
+395
-28
@@ -58,6 +58,41 @@
|
||||
</v-expansion-panel-content>
|
||||
</v-expansion-panel>
|
||||
|
||||
<v-expansion-panel key="source">
|
||||
<v-expansion-panel-header class="flex">
|
||||
<v-container class="ma-0 pa-0">
|
||||
<v-icon>
|
||||
mdi-source-branch
|
||||
</v-icon>
|
||||
{{ `Source` }}
|
||||
<v-tooltip right>
|
||||
<template #activator="{ on, attrs }">
|
||||
<v-btn
|
||||
class="ma-0 ml-1"
|
||||
height="20px"
|
||||
width="20px"
|
||||
icon
|
||||
x-small
|
||||
:color="getSourceStateIconColor()"
|
||||
v-bind="attrs"
|
||||
v-on="on"
|
||||
@click="refreshSourceBranch"
|
||||
>
|
||||
<v-icon>
|
||||
{{ getSourceStateIcon() }}
|
||||
</v-icon>
|
||||
</v-btn>
|
||||
</template>
|
||||
<span>{{ getSourceStateToolTip() }}</span>
|
||||
</v-tooltip>
|
||||
|
||||
</v-container>
|
||||
</v-expansion-panel-header>
|
||||
<v-expansion-panel-content>
|
||||
<mapper-source :stream-text="streamText" :branch-text="branchText" :source-state="this.sourceState"/>
|
||||
</v-expansion-panel-content>
|
||||
</v-expansion-panel>
|
||||
|
||||
<v-expansion-panel key="mapping">
|
||||
<v-expansion-panel-header>
|
||||
<div>
|
||||
@@ -124,16 +159,56 @@
|
||||
class="pt-0"
|
||||
label="Mapper Method"
|
||||
:disabled="!entitySelected"
|
||||
:items="enabledMethods"
|
||||
:items="availableMethods"
|
||||
density="compact"
|
||||
clearable
|
||||
@change="onSelectedMethodChange"
|
||||
></v-autocomplete>
|
||||
|
||||
<v-autocomplete
|
||||
v-if="familySelectionActive"
|
||||
v-model="selectedFamily"
|
||||
class="pt-0"
|
||||
label="Family"
|
||||
:disabled="!entitySelected"
|
||||
:items="inputFamilies"
|
||||
density="compact"
|
||||
clearable
|
||||
@change="onSelectedFamilyChange"
|
||||
></v-autocomplete>
|
||||
|
||||
<v-autocomplete
|
||||
v-if="typeSelectionActive"
|
||||
v-model="selectedFamilyType"
|
||||
class="pt-0"
|
||||
label="Type"
|
||||
:disabled="!entitySelected"
|
||||
item-value="type"
|
||||
item-text="type"
|
||||
:items="familyTypes"
|
||||
density="compact"
|
||||
clearable
|
||||
></v-autocomplete>
|
||||
|
||||
<v-autocomplete
|
||||
v-if="levelSelectionActive"
|
||||
v-model="selectedLevel"
|
||||
class="pt-0"
|
||||
label="Base Level"
|
||||
:disabled="!entitySelected"
|
||||
:items="levels"
|
||||
item-value="name"
|
||||
item-text="name"
|
||||
density="compact"
|
||||
clearable
|
||||
></v-autocomplete>
|
||||
|
||||
<v-autocomplete
|
||||
v-if="categorySelectionActive"
|
||||
v-model="selectedCategory"
|
||||
class="pt-0"
|
||||
label="Category"
|
||||
:items="availableCategories"
|
||||
:items="selectedMethod === 'New Revit Family' ? familyCategories : categories"
|
||||
item-value="value"
|
||||
item-text="key"
|
||||
:disabled="!entitySelected"
|
||||
@@ -142,6 +217,7 @@
|
||||
></v-autocomplete>
|
||||
|
||||
<v-text-field
|
||||
v-if="nameSelectionActive"
|
||||
v-model="name"
|
||||
class="pt-0"
|
||||
label="Name"
|
||||
@@ -153,6 +229,7 @@
|
||||
<v-row justify="center" align="center">
|
||||
<v-col cols="auto" class="pa-1 pb-2">
|
||||
<v-btn
|
||||
small
|
||||
:disabled="!entitySelected"
|
||||
@click="applyMapping"
|
||||
>
|
||||
@@ -163,6 +240,7 @@
|
||||
</v-col>
|
||||
<v-col cols="auto" class="pa-1 pb-2">
|
||||
<v-btn
|
||||
small
|
||||
:disabled="!entitySelected"
|
||||
@click="clearMapping"
|
||||
>
|
||||
@@ -173,10 +251,7 @@
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
|
||||
</v-container>
|
||||
|
||||
|
||||
</v-expansion-panel-content>
|
||||
</v-expansion-panel>
|
||||
|
||||
@@ -204,11 +279,22 @@
|
||||
/*global sketchup*/
|
||||
import {bus} from "@/main";
|
||||
import {groupBy} from "@/utils/groupBy";
|
||||
import MappingSource from "@/components/MapperSource.vue";
|
||||
import {sourceMap} from "@vue/cli-service/lib/config/terserOptions";
|
||||
|
||||
global.mapperSourceUpdated = function (streamId, levels, types, familyInstances) {
|
||||
console.log(`Mapper source updated for ${streamId}.`)
|
||||
bus.$emit('mapper-source-updated', JSON.stringify(levels), JSON.stringify(types), JSON.stringify(familyInstances))
|
||||
}
|
||||
|
||||
global.entitySelected = function (selectionParameters) {
|
||||
bus.$emit('entities-selected', JSON.stringify(selectionParameters))
|
||||
}
|
||||
|
||||
global.mapperInitialized = function (initParameters) {
|
||||
bus.$emit('mapper-initialized', JSON.stringify(initParameters))
|
||||
}
|
||||
|
||||
global.entitiesDeselected = function () {
|
||||
bus.$emit('entities-deselected')
|
||||
}
|
||||
@@ -219,12 +305,35 @@ global.mappedEntitiesUpdated = function (mappedEntities) {
|
||||
|
||||
export default {
|
||||
name: "Mapper",
|
||||
props: {
|
||||
streamText: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
branchText: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
components: {
|
||||
MapperSource: () => import('@/components/MapperSource.vue'),
|
||||
GlobalToast: () => import('@/components/GlobalToast'),
|
||||
MappedElements: () => import('@/components/MappedElements.vue')
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
nativeFaceMethods: ['Floor', 'Wall'],
|
||||
nativeEdgeMethods: ['Column', 'Beam', 'Brace', 'Pipe', 'Duct'],
|
||||
nativeDefaultFaceMethods: ['Default Floor', 'Default Wall'],
|
||||
nativeDefaultEdgeMethods: ['Default Column', 'Default Beam', 'Default Brace', 'Default Pipe', 'Default Duct'],
|
||||
|
||||
familySelectionActive: false,
|
||||
typeSelectionActive: false,
|
||||
levelSelectionActive: false,
|
||||
categorySelectionActive: false,
|
||||
nameSelectionActive: false,
|
||||
|
||||
sourceState: 'Not Set',
|
||||
// Expanded indexes for selection table (Types)
|
||||
selectionExpandedIndexes: [],
|
||||
// Expanded indexes for mapped element table (Categories)
|
||||
@@ -239,15 +348,33 @@ export default {
|
||||
entitySelected: false,
|
||||
selectedEntityCount: 0,
|
||||
selectedEntities: [],
|
||||
|
||||
familyTypes: [],
|
||||
lastSelectedEntity: null,
|
||||
|
||||
selectedMethod: null,
|
||||
selectedCategory: null,
|
||||
selectedFamily: null,
|
||||
selectedFamilyType: null,
|
||||
selectedLevel: null,
|
||||
name: "",
|
||||
enabledMethods: [],
|
||||
availableCategories: [],
|
||||
|
||||
availableMethods: [],
|
||||
categories: [],
|
||||
familyCategories: [],
|
||||
|
||||
inputCategories: [],
|
||||
inputFamilies: [],
|
||||
inputFamilyTypes: {},
|
||||
|
||||
// comes from source
|
||||
types: {},
|
||||
levels: [],
|
||||
familyInstanceTypes: {}, // comes from source as filtered
|
||||
|
||||
mappedEntityCount: 0,
|
||||
mappedEntities: [],
|
||||
panel: [1],
|
||||
panel: [2],
|
||||
selectionHeaders: [
|
||||
{ text: 'Type', sortable: false, value: 'entityType', width: '60%' },
|
||||
{ text: 'Count', sortable: false, align: 'center', value: 'count', width: '20%' },
|
||||
@@ -354,9 +481,164 @@ export default {
|
||||
}
|
||||
},
|
||||
methods:{
|
||||
getSourceStateIcon(){
|
||||
switch (this.sourceState){
|
||||
case "Not Set":
|
||||
return `mdi-cloud-off-outline`;
|
||||
case "Set":
|
||||
return `mdi-checkbox-marked-circle-outline`;
|
||||
case "Outdated":
|
||||
return `mdi-update`;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
},
|
||||
getSourceStateToolTip(){
|
||||
switch (this.sourceState){
|
||||
case "Not Set":
|
||||
return 'Source disconnected.';
|
||||
case "Set":
|
||||
return 'Source connected.';
|
||||
case "Outdated":
|
||||
return 'Source branch is not up-to-date!';
|
||||
default:
|
||||
break;
|
||||
}
|
||||
},
|
||||
getSourceStateIconColor(){
|
||||
switch (this.sourceState){
|
||||
case "Not Set":
|
||||
return `grey`;
|
||||
case "Set":
|
||||
return `green`;
|
||||
case "Outdated":
|
||||
return `red`;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
},
|
||||
onSelectedMethodChange(){
|
||||
this.hideOptionalMappingInputs()
|
||||
this.updateMappingInputs()
|
||||
this.getFamiliesFromSelectedMethod()
|
||||
this.getTypesFromSelectedFamily()
|
||||
this.$mixpanel.track('MappingsAction', { name: 'Mappings Set', schema: this.selectedMethod })
|
||||
},
|
||||
onSelectedFamilyChange(){
|
||||
this.getTypesFromSelectedFamily();
|
||||
},
|
||||
updateMappingInputs(){
|
||||
if (this.selectedMethod === null){
|
||||
this.typeSelectionActive = false
|
||||
this.familySelectionActive = false
|
||||
this.levelSelectionActive = false
|
||||
this.categorySelectionActive = false
|
||||
this.nameSelectionActive = false
|
||||
return
|
||||
}
|
||||
const nativeDefaultMethods = this.nativeDefaultEdgeMethods.concat(this.nativeDefaultFaceMethods)
|
||||
const nativeMethods = this.nativeEdgeMethods.concat(this.nativeFaceMethods)
|
||||
|
||||
if (this.selectedMethod === 'Direct Shape'){
|
||||
this.categorySelectionActive = true
|
||||
this.nameSelectionActive = true
|
||||
}
|
||||
else if (this.selectedMethod === 'New Revit Family'){
|
||||
this.categorySelectionActive = true
|
||||
}
|
||||
else if (this.selectedMethod === 'Family Instance'){
|
||||
this.typeSelectionActive = true
|
||||
this.familySelectionActive = true
|
||||
this.levelSelectionActive = true
|
||||
}
|
||||
else if (nativeDefaultMethods.includes(this.selectedMethod)){
|
||||
this.typeSelectionActive = false
|
||||
this.familySelectionActive = false
|
||||
this.levelSelectionActive = false
|
||||
this.categorySelectionActive = false
|
||||
this.nameSelectionActive = false
|
||||
}
|
||||
else if (nativeMethods.includes(this.selectedMethod)){
|
||||
this.typeSelectionActive = true
|
||||
this.familySelectionActive = true
|
||||
this.levelSelectionActive = true
|
||||
}
|
||||
},
|
||||
getTypesFromSelectedFamily(){
|
||||
// There is no sense to set selected family type if method is not selected
|
||||
if (this.selectedMethod){
|
||||
if (this.sourceState !== 'Not Set'){
|
||||
this.familyTypes = this.inputFamilyTypes[this.selectedFamily]
|
||||
this.selectedFamilyType = this.familyTypes[0].type
|
||||
if (this.selectedFamilyType === null || this.selectedFamilyType === undefined){
|
||||
this.selectedFamilyType = this.familyTypes[0].type
|
||||
}
|
||||
}
|
||||
if (this.selectedFamily === null || this.selectedFamily === undefined){
|
||||
this.selectedFamily = this.inputFamilies[0]
|
||||
}
|
||||
if (this.familyTypes === null ||this.familyTypes === undefined){
|
||||
this.familyTypes = this.inputFamilyTypes[this.selectedFamily]
|
||||
}
|
||||
}
|
||||
},
|
||||
getFamiliesFromSelectedMethod(){
|
||||
switch (this.selectedMethod) {
|
||||
case 'Floor':
|
||||
this.inputFamilies = Object.keys(this.types['Floors']);
|
||||
this.inputFamilyTypes = this.types['Floors']
|
||||
break;
|
||||
case 'Wall':
|
||||
this.inputFamilies = Object.keys(this.types['Walls']);
|
||||
this.inputFamilyTypes = this.types['Walls']
|
||||
break;
|
||||
case 'Column':
|
||||
this.inputFamilies = Object.keys(this.types['Columns']);
|
||||
this.inputFamilyTypes = this.types['Columns']
|
||||
break;
|
||||
case 'Beam':
|
||||
this.inputFamilies = Object.keys(this.types['Beams']);
|
||||
this.inputFamilyTypes = this.types['Beams']
|
||||
break;
|
||||
case 'Pipe':
|
||||
this.inputFamilies = Object.keys(this.types['Piping System']);
|
||||
this.inputFamilyTypes = this.types['Piping System']
|
||||
break;
|
||||
case 'Duct':
|
||||
this.inputFamilies = Object.keys(this.types['Duct System']);
|
||||
this.inputFamilyTypes = this.types['Duct System']
|
||||
break;
|
||||
case 'Family Instance':
|
||||
this.inputFamilies = Object.keys(this.familyInstanceTypes);
|
||||
this.inputFamilyTypes = this.familyInstanceTypes
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (this.selectedMethod){
|
||||
if (this.selectedFamily === null || this.selectedFamily === undefined){
|
||||
this.selectedFamily = this.inputFamilies[0]
|
||||
}
|
||||
if (this.selectedLevel === null || this.selectedLevel === undefined){
|
||||
this.selectedLevel = this.levels[0].name
|
||||
}
|
||||
}
|
||||
},
|
||||
hideOptionalMappingInputs(){
|
||||
this.categorySelectionActive = false
|
||||
this.nameSelectionActive = false
|
||||
this.typeSelectionActive = false
|
||||
this.familySelectionActive = false
|
||||
this.levelSelectionActive = false
|
||||
},
|
||||
refreshSourceBranch(){
|
||||
if (this.sourceState === 'Outdated'){
|
||||
bus.$emit('refresh-source-branch')
|
||||
this.$mixpanel.track('MappingsAction', { name: 'Mappings Source Update' })
|
||||
}
|
||||
},
|
||||
clearInputs(){
|
||||
this.enabledMethods = []
|
||||
this.availableCategories = []
|
||||
this.availableMethods = []
|
||||
this.selectedEntities = []
|
||||
this.selectionTableData = []
|
||||
this.selectedEntityCount = 0
|
||||
@@ -365,6 +647,9 @@ export default {
|
||||
this.selectedCategory = null
|
||||
this.entityMapped = false
|
||||
this.definitionMapped = false
|
||||
this.selectedLevel = null
|
||||
this.selectedFamily = null
|
||||
this.selectedFamilyType = null
|
||||
},
|
||||
getSelectionTableData(){
|
||||
let groupByClass = groupBy('entityType')
|
||||
@@ -403,12 +688,12 @@ export default {
|
||||
return summary
|
||||
},
|
||||
setInputValuesFromSelection(){
|
||||
// Clear all inputs if entity is not selected.
|
||||
if (!this.entitySelected){
|
||||
this.name = ""
|
||||
this.selectedMethod = null
|
||||
this.selectedCategory = null
|
||||
this.clearMappingInputs()
|
||||
return
|
||||
}
|
||||
// Check if definition card is selected and set definition mappings.
|
||||
if (this.definitionSelected) {
|
||||
if (!this.definitionMapped){
|
||||
if (this.selectedEntityCount > 1){
|
||||
@@ -416,7 +701,7 @@ export default {
|
||||
}else{
|
||||
this.name = this.lastSelectedEntity['definition']['entityName']
|
||||
}
|
||||
this.selectedMethod = 'Direct Shape'
|
||||
// this.selectedMethod = 'Direct Shape'
|
||||
this.selectedCategory = 49
|
||||
} else {
|
||||
if (this.selectedEntityCount > 1){
|
||||
@@ -426,15 +711,26 @@ export default {
|
||||
}
|
||||
this.selectedMethod = this.lastSelectedEntity['definition']['schema']['method']
|
||||
this.selectedCategory = this.lastSelectedEntity['definition']['schema']['category']
|
||||
this.selectedFamily = this.lastSelectedEntity['definition']['schema']['family']
|
||||
this.getFamiliesFromSelectedMethod()
|
||||
this.getTypesFromSelectedFamily()
|
||||
this.selectedFamilyType = this.lastSelectedEntity['definition']['schema']['family_type']
|
||||
this.selectedLevel = this.lastSelectedEntity['definition']['schema']['level']
|
||||
this.updateMappingInputs()
|
||||
}
|
||||
} else {
|
||||
}
|
||||
// Otherwise set entity mappings.
|
||||
else
|
||||
{
|
||||
if (!this.entityMapped){
|
||||
if (this.selectedEntityCount > 1){
|
||||
this.name = '<Mixed>'
|
||||
}else{
|
||||
this.name = this.lastSelectedEntity['entityName']
|
||||
}
|
||||
this.selectedMethod = 'Direct Shape'
|
||||
this.updateMappingInputs()
|
||||
this.getFamiliesFromSelectedMethod()
|
||||
this.getTypesFromSelectedFamily()
|
||||
this.selectedCategory = 49
|
||||
} else {
|
||||
if (this.selectedEntityCount > 1){
|
||||
@@ -443,7 +739,13 @@ export default {
|
||||
this.name = this.lastSelectedEntity['schema']['name']
|
||||
}
|
||||
this.selectedMethod = this.lastSelectedEntity['schema']['method']
|
||||
this.updateMappingInputs()
|
||||
this.selectedFamily = this.lastSelectedEntity['schema']['family']
|
||||
this.selectedCategory = this.lastSelectedEntity['schema']['category']
|
||||
this.getFamiliesFromSelectedMethod()
|
||||
this.getTypesFromSelectedFamily()
|
||||
this.selectedFamilyType = this.lastSelectedEntity['schema']['family_type']
|
||||
this.selectedLevel = this.lastSelectedEntity['schema']['level']
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -482,10 +784,29 @@ export default {
|
||||
this.mappedElementsExpandedIndexes.push(slotData.item);
|
||||
}
|
||||
},
|
||||
inputsReadyToApply(){
|
||||
if (this.selectedMethod === null || this.selectedMethod === undefined){
|
||||
return false;
|
||||
}
|
||||
|
||||
const nativeMethods = this.nativeEdgeMethods.concat(this.nativeFaceMethods)
|
||||
|
||||
if (this.selectedMethod === 'Direct Shape'){
|
||||
return this.selectedCategory !== null
|
||||
}
|
||||
else if (nativeMethods.includes(this.selectedMethod)){
|
||||
return this.selectedFamily !== null &&
|
||||
this.selectedFamilyType !== null &&
|
||||
this.selectedLevel !== null
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
applyMapping(){
|
||||
if (this.selectedMethod === null || this.selectedCategory === null){
|
||||
if (!this.inputsReadyToApply()){
|
||||
this.$eventHub.$emit('error', {
|
||||
text: 'Method and category are not set.\n'
|
||||
text: 'Some inputs are not set to apply mapping.\n'
|
||||
})
|
||||
return
|
||||
}
|
||||
@@ -493,6 +814,9 @@ export default {
|
||||
entitiesToMap: this.selectedEntities.map((entity) => entity['entityId']),
|
||||
method: this.selectedMethod,
|
||||
category: this.selectedCategory,
|
||||
family: this.selectedFamily,
|
||||
familyType: this.selectedFamilyType,
|
||||
level: this.selectedLevel,
|
||||
name: this.name,
|
||||
isDefinition: this.definitionSelected
|
||||
}
|
||||
@@ -500,6 +824,8 @@ export default {
|
||||
this.$eventHub.$emit('success', {
|
||||
text: 'Mapping Applied.\n'
|
||||
})
|
||||
|
||||
this.$mixpanel.track('MappingsAction', { name: 'Mappings Applied' })
|
||||
},
|
||||
clearMapping(){
|
||||
const mapping = {
|
||||
@@ -511,32 +837,73 @@ export default {
|
||||
this.$eventHub.$emit('error', {
|
||||
text: 'Mapping Cleared.\n'
|
||||
})
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
sketchup.exec({name: "collect_mapped_entities", data: {}})
|
||||
|
||||
bus.$on('entities-selected', async (selectionParameters) => {
|
||||
const selectionPars = JSON.parse(selectionParameters)
|
||||
this.enabledMethods = selectionPars.mappingMethods
|
||||
this.availableCategories = selectionPars.categories
|
||||
this.selectedEntities = selectionPars.selection
|
||||
this.$mixpanel.track('MappingsAction', { name: 'Mappings Clear' })
|
||||
},
|
||||
clearMappingInputs(){
|
||||
this.selectedMethod = null
|
||||
this.selectedCategory = null
|
||||
this.name = ""
|
||||
this.selectedFamily = null
|
||||
this.selectedFamilyType = null
|
||||
this.selectedLevel = null
|
||||
this.availableMethods = null
|
||||
},
|
||||
getDataFromSelection(selectionParameters){
|
||||
this.availableMethods = selectionParameters.mappingMethods
|
||||
this.selectedEntities = selectionParameters.selection
|
||||
this.selectedLevel = selectionParameters.selectedLevelName
|
||||
},
|
||||
updateStatesFromSelectionData(){
|
||||
this.lastSelectedEntity = this.selectedEntities[this.selectedEntities.length - 1]
|
||||
this.entityMapped = this.isEntitiesMapped(this.selectedEntities)
|
||||
this.definitionMapped = this.isEntityDefinitionsMapped(this.selectedEntities)
|
||||
this.definitionSelected = !this.entityMapped && this.definitionMapped
|
||||
this.selectedEntityCount = this.selectedEntities.length
|
||||
this.entitySelected = this.selectedEntityCount !== 0
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
sketchup.exec({name: "mapper_initialized", data: {}})
|
||||
sketchup.exec({name: "collect_mapped_entities", data: {}})
|
||||
|
||||
bus.$on('mapper-initialized', async (initParameters) => {
|
||||
const initPars = JSON.parse(initParameters)
|
||||
this.categories = initPars.categories
|
||||
this.familyCategories = initPars.familyCategories
|
||||
})
|
||||
|
||||
bus.$on('mapper-source-updated', async (levels, types, familyInstances) => {
|
||||
// Parse data to json object
|
||||
this.familyInstanceTypes = JSON.parse(familyInstances)
|
||||
this.levels = JSON.parse(levels)
|
||||
this.types = JSON.parse(types)
|
||||
})
|
||||
|
||||
bus.$on('entities-selected', async (selectionParameters) => {
|
||||
// Parse data to json object
|
||||
const selectionPars = JSON.parse(selectionParameters)
|
||||
// Reset mapping inputs with nulls and empties.
|
||||
this.clearMappingInputs()
|
||||
// Get data from selection into objects and arrays. These data basically constructs the dropdowns.
|
||||
this.getDataFromSelection(selectionPars)
|
||||
// Update inner state of the mapper component according to selection data.
|
||||
this.updateStatesFromSelectionData()
|
||||
// Get selection table data.
|
||||
this.getSelectionTableData()
|
||||
// Set mapping input values from selection data.
|
||||
this.setInputValuesFromSelection()
|
||||
})
|
||||
bus.$on('entities-deselected', async () => {
|
||||
this.entitySelected = false
|
||||
this.clearInputs()
|
||||
this.hideOptionalMappingInputs()
|
||||
})
|
||||
bus.$on('mapped-entities-updated', async (mappedEntities) => {
|
||||
this.mappedEntityCount = mappedEntities.length
|
||||
})
|
||||
bus.$on('set-source-up-to-date', (isUpToDate) => {
|
||||
this.sourceState = isUpToDate
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -0,0 +1,223 @@
|
||||
<template>
|
||||
<v-container class="pa-0">
|
||||
<v-autocomplete
|
||||
v-model="sourceStreamId"
|
||||
:label="streamText"
|
||||
:items="allStreamsList"
|
||||
item-text="name"
|
||||
item-value="id"
|
||||
density="compact"
|
||||
></v-autocomplete>
|
||||
|
||||
<v-autocomplete
|
||||
v-model="sourceBranchId"
|
||||
class="pt-0 mb-n5"
|
||||
:label="branchText"
|
||||
:items="allBranchesList"
|
||||
:disabled="sourceStreamId === null"
|
||||
item-text="name"
|
||||
item-value="id"
|
||||
density="compact"
|
||||
></v-autocomplete>
|
||||
|
||||
<v-container class="pa-0 mt-2">
|
||||
<v-row justify="center" align="center">
|
||||
<v-col cols="auto" class="pa-1 pb-2">
|
||||
<v-btn
|
||||
small
|
||||
@click="applySource"
|
||||
>
|
||||
<v-icon dark left>
|
||||
mdi-checkbox-marked-circle
|
||||
</v-icon>Apply
|
||||
</v-btn>
|
||||
</v-col>
|
||||
<v-col cols="auto" class="pa-1 pb-2">
|
||||
<v-btn
|
||||
small
|
||||
:disabled="!sourceApplied"
|
||||
@click="clearSource"
|
||||
>
|
||||
<v-icon dark left>
|
||||
mdi-close-circle
|
||||
</v-icon>Clear
|
||||
</v-btn>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
</v-container>
|
||||
</v-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/*global sketchup*/
|
||||
import gql from "graphql-tag";
|
||||
import streamQuery from "@/graphql/stream.gql";
|
||||
import {bus} from "@/main";
|
||||
import ObjectLoader from "@speckle/objectloader";
|
||||
|
||||
const streamLimit = 20
|
||||
|
||||
export default {
|
||||
name: "MappingSource",
|
||||
props: {
|
||||
streamSearchQuery: { type: String, default: null },
|
||||
sourceState: { type: String, default: 'Not Set' },
|
||||
streamText: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
branchText: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
sourceApplied: false,
|
||||
sourceStreamId: null,
|
||||
sourceBranchId: null,
|
||||
sourceStreamName: null,
|
||||
sourceBranchName: null
|
||||
}
|
||||
},
|
||||
apollo: {
|
||||
streams: {
|
||||
prefetch: true,
|
||||
debounce: 300,
|
||||
fetchPolicy: 'cache-and-network',
|
||||
query: gql`
|
||||
query Streams($query: String, $limit: Int, $cursor: String) {
|
||||
streams(query: $query, limit: $limit, cursor: $cursor) {
|
||||
totalCount
|
||||
cursor
|
||||
items {
|
||||
id
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables() {
|
||||
return {
|
||||
query: this.streamSearchQuery,
|
||||
limit: streamLimit,
|
||||
cursor: null
|
||||
}
|
||||
},
|
||||
update(data) {
|
||||
bus.$emit('streams-loaded')
|
||||
this.showMoreEnabled = data.streams?.items.length < data.streams.totalCount
|
||||
return data.streams
|
||||
},
|
||||
},
|
||||
$subscribe: {
|
||||
commitCreated: {
|
||||
query: gql`
|
||||
subscription ($streamId: String!) {
|
||||
commitCreated(streamId: $streamId)
|
||||
}
|
||||
`,
|
||||
variables() {
|
||||
return {
|
||||
streamId: this.sourceStreamId
|
||||
}
|
||||
},
|
||||
result(data) {
|
||||
if (data.data.commitCreated.sourceApplication.includes('Revit')){
|
||||
if (data.data.commitCreated.branchName === this.selectedBranch.name){
|
||||
this.afterCommitCreated()
|
||||
this.$eventHub.$emit('notification', {
|
||||
text: `A new commit was created on Revit!`,
|
||||
})
|
||||
this.$apollo.queries.stream.refetch()
|
||||
}
|
||||
}
|
||||
},
|
||||
skip() {
|
||||
// Return true to skip the initial query execution
|
||||
return this.sourceStreamId === null;
|
||||
},
|
||||
}
|
||||
},
|
||||
stream: {
|
||||
query: streamQuery,
|
||||
prefetch: true,
|
||||
variables() {
|
||||
return {
|
||||
id: this.sourceStreamId,
|
||||
limit: 100
|
||||
}
|
||||
},
|
||||
skip() {
|
||||
// Return true to skip the initial query execution
|
||||
return this.sourceStreamId === null;
|
||||
},
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
selectedBranch() {
|
||||
if (!this.stream) return
|
||||
return this.stream.branches.items.find((branch) => branch.id === this.sourceBranchId)
|
||||
},
|
||||
allStreamsList() {
|
||||
if (this.$apollo.loading) return
|
||||
return this.streams?.items
|
||||
},
|
||||
allBranchesList() {
|
||||
if (this.$apollo.loading) return
|
||||
return this.stream?.branches.items
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
bus.$on('refresh-source-branch', () => {
|
||||
this.onSourceBranchChanged()
|
||||
bus.$emit('set-source-up-to-date', 'Set')
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
applySource(){
|
||||
bus.$emit('set-source-up-to-date', 'Set')
|
||||
this.onSourceBranchChanged()
|
||||
this.$eventHub.$emit('success', {
|
||||
text: 'Mapper source applied.\n'
|
||||
})
|
||||
this.$mixpanel.track('MappingsAction', { name: 'Mappings Source Apply' })
|
||||
},
|
||||
clearSource(){
|
||||
sketchup.exec({name:"clear_mapper_source" , data: {}})
|
||||
bus.$emit('set-source-up-to-date', 'Not Set')
|
||||
this.sourceApplied = false
|
||||
this.sourceBranchName = null
|
||||
this.sourceStreamName = null
|
||||
this.sourceBranchId = null
|
||||
this.sourceStreamId = null
|
||||
this.$eventHub.$emit('error', {
|
||||
text: 'Mapper source cleared.\n'
|
||||
})
|
||||
},
|
||||
afterCommitCreated(){
|
||||
bus.$emit('set-source-up-to-date', 'Outdated')
|
||||
},
|
||||
async onSourceBranchChanged() {
|
||||
const commitRefId = this.selectedBranch.commits.items[0]?.referencedObject
|
||||
if (!commitRefId) { return }
|
||||
|
||||
const loader = new ObjectLoader({
|
||||
serverUrl: localStorage.getItem('serverUrl'),
|
||||
token: localStorage.getItem('SpeckleSketchup.AuthToken'),
|
||||
streamId: this.sourceStreamId,
|
||||
objectId: commitRefId
|
||||
})
|
||||
|
||||
let rootObj = await loader.getAndConstructObject(this.updateLoadingStage)
|
||||
sketchup.exec({name:"mapper_source_updated" , data: {
|
||||
base: rootObj,
|
||||
stream_id: this.sourceStreamId,
|
||||
commit_id: commitRefId
|
||||
}})
|
||||
this.sourceApplied = true
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -13,7 +13,7 @@
|
||||
<v-toolbar-title class="ml-0" style="position: relative; left: -10px">
|
||||
<!-- Uncomment when pinning is in place and add style="position: relative; left: -10px" to the element above :) -->
|
||||
<v-btn
|
||||
v-tooltip="'Pin this stream - it will be saved to this file.'"
|
||||
v-tooltip="`Pin this ${streamText.toLowerCase()} - it will be saved to this file.`"
|
||||
icon
|
||||
x-small
|
||||
@click="toggleSavedStream"
|
||||
@@ -66,7 +66,11 @@
|
||||
<template #activator="{ on, attrs }">
|
||||
<v-slide-x-transition>
|
||||
<div v-show="hover">
|
||||
<create-branch-dialog :stream-name="stream.name" :stream-id="streamId"/>
|
||||
<create-branch-dialog
|
||||
:is-f-e2="preferences && preferences.user && preferences.user.fe2"
|
||||
:stream-name="stream.name"
|
||||
:stream-id="streamId"
|
||||
/>
|
||||
</div>
|
||||
</v-slide-x-transition>
|
||||
<v-chip v-if="stream.branches" small v-bind="attrs" class="mr-1" v-on="on">
|
||||
@@ -87,19 +91,19 @@
|
||||
mdi-check
|
||||
</v-icon>
|
||||
<v-icon v-else small class="mr-1 float-left">mdi-source-branch</v-icon>
|
||||
{{ branch.name }} ({{ branch.commits.totalCount }})
|
||||
{{ branch.name }} ({{ branch && branch.commits ? branch.commits.totalCount : 0 }})
|
||||
</v-list-item-title>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</v-menu>
|
||||
<v-menu offset-y>
|
||||
<template #activator="{ on, attrs }">
|
||||
<v-chip v-if="stream.commits" small v-bind="attrs" v-on="on">
|
||||
<v-chip v-if="stream && stream.commits" small v-bind="attrs" v-on="on">
|
||||
<v-icon small class="mr-1 float-left">mdi-source-commit</v-icon>
|
||||
{{ selectedBranch.commits.items.length ? commitId : 'no commits' }}
|
||||
{{ selectedBranch.commits.items.length ? commitId : 'no commits' }}
|
||||
</v-chip>
|
||||
</template>
|
||||
<v-list dense>
|
||||
<v-list v-if="selectedBranch && selectedBranch.commits" dense>
|
||||
<v-list-item
|
||||
v-for="(commit, index) in selectedBranch.commits.items"
|
||||
:key="index"
|
||||
@@ -133,7 +137,7 @@
|
||||
hide-details
|
||||
dense
|
||||
flat
|
||||
placeholder="Write your commit message here"
|
||||
:placeholder="`Write your ${commitText.toLowerCase()} message here`"
|
||||
/>
|
||||
</div>
|
||||
</v-slide-y-transition>
|
||||
@@ -204,7 +208,11 @@ export default {
|
||||
commitId: 'latest',
|
||||
commitMessage: null,
|
||||
invalid: false,
|
||||
diffing: false
|
||||
diffing: false,
|
||||
streamText: '',
|
||||
branchText: '',
|
||||
commitText: '',
|
||||
preferences: {}
|
||||
}
|
||||
},
|
||||
apollo: {
|
||||
@@ -213,7 +221,8 @@ export default {
|
||||
query: streamQuery,
|
||||
variables() {
|
||||
return {
|
||||
id: this.streamId
|
||||
id: this.streamId,
|
||||
limit: 100
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -286,6 +295,16 @@ export default {
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
bus.$on('update-preferences', async (preferences) => {
|
||||
const pref = JSON.parse(preferences)
|
||||
this.preferences = pref
|
||||
this.streamText = pref.user.fe2 ? 'Project' : 'Stream'
|
||||
this.branchText = pref.user.fe2 ? 'Model' : 'Branch'
|
||||
this.commitText = pref.user.fe2 ? 'Version' : 'Commit'
|
||||
})
|
||||
// Collect preferences to render UI according to it
|
||||
sketchup.exec({name: "collect_preferences", data: {}})
|
||||
|
||||
bus.$on(`deactivate-diffing-${this.streamId}`, () => {
|
||||
this.diffing = false
|
||||
})
|
||||
@@ -343,7 +362,9 @@ export default {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms))
|
||||
},
|
||||
openInWeb() {
|
||||
window.open(`${localStorage.getItem('serverUrl')}/streams/${this.streamId}`)
|
||||
var url = localStorage.getItem('frontend2') === "true" ? `${localStorage.getItem('serverUrl')}/projects/${this.streamId}` : `${localStorage.getItem('serverUrl')}/streams/${this.streamId}`
|
||||
window.open(url)
|
||||
|
||||
this.$mixpanel.track('Connector Action', { name: 'Open In Web' })
|
||||
},
|
||||
switchBranch(branchName) {
|
||||
@@ -483,13 +504,12 @@ export default {
|
||||
}
|
||||
})
|
||||
console.log('>>> SpeckleSketchUp: Sent to stream: ' + this.streamId, commit)
|
||||
const url = localStorage.getItem('frontend2') === 'true' ? `${localStorage.getItem('serverUrl')}/projects/${this.streamId}/models/${this.selectedBranch.id}@${res.data.commitCreate}` : `${localStorage.getItem('serverUrl')}/streams/${this.streamId}/commits/${res.data.commitCreate}`
|
||||
this.$eventHub.$emit('notification', {
|
||||
text: 'Model selection sent!\n',
|
||||
action: {
|
||||
name: 'View in Web',
|
||||
url: `${localStorage.getItem('serverUrl')}/streams/${this.streamId}/commits/${
|
||||
res.data.commitCreate
|
||||
}`
|
||||
url: url
|
||||
}
|
||||
})
|
||||
this.$apollo.queries.stream.refetch()
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<v-dialog v-model="showCreateBranch">
|
||||
<template #activator="{ on: dialog, attrs }">
|
||||
<v-btn
|
||||
v-tooltip="'Create Branch'"
|
||||
v-tooltip="`Create ${isFE2 ? 'Model' : 'Branch'}`"
|
||||
icon x-small class="ml-0 mr-1"
|
||||
v-bind="attrs"
|
||||
v-on="{...dialog}"
|
||||
@@ -15,10 +15,10 @@
|
||||
</template>
|
||||
<v-card>
|
||||
<v-card-title class="text-h5 mb-1">
|
||||
Create a New Branch
|
||||
{{ `Create a New ${isFE2 ? 'Model' : 'Branch'}` }}
|
||||
</v-card-title>
|
||||
<v-card-subtitle class="py-0 my-0 font-italic">
|
||||
under {{ streamName }} stream
|
||||
{{ `under ${streamName} ${isFE2 ? 'project' : 'stream'}` }}
|
||||
</v-card-subtitle>
|
||||
<v-container class="px-6" pb-0>
|
||||
<v-text-field
|
||||
@@ -27,7 +27,7 @@
|
||||
hide-details
|
||||
dense
|
||||
flat
|
||||
placeholder="Branch Name"
|
||||
:placeholder="`${isFE2 ? 'Model' : 'Branch'} Name`"
|
||||
/>
|
||||
<v-text-field
|
||||
v-model="description"
|
||||
@@ -75,6 +75,14 @@ export default {
|
||||
streamName: {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
isFE2: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
branchTooltipName: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
data() {
|
||||
|
||||
@@ -16,13 +16,14 @@
|
||||
left
|
||||
>
|
||||
mdi-plus-circle
|
||||
</v-icon>Create New Stream
|
||||
</v-icon>
|
||||
{{ `Create New ${isFE2Terms ? 'Project': 'Stream'}` }}
|
||||
</v-btn>
|
||||
</template>
|
||||
|
||||
<v-card>
|
||||
<v-card-title class="text-h5">
|
||||
Create a New Stream
|
||||
{{ `Create a New ${isFE2Terms ? 'Project' : 'Stream'}` }}
|
||||
</v-card-title>
|
||||
<v-container class="px-6" pb-0>
|
||||
<!--
|
||||
@@ -55,7 +56,7 @@
|
||||
hide-details
|
||||
dense
|
||||
flat
|
||||
placeholder="Stream Name (Optional)"
|
||||
:placeholder="`${isFE2Terms ? 'Project' : 'Stream'} Name (Optional)`"
|
||||
/>
|
||||
<v-text-field
|
||||
v-model="description"
|
||||
@@ -67,7 +68,7 @@
|
||||
/>
|
||||
<v-switch
|
||||
v-model="privateStream"
|
||||
:label="'Private Stream'"
|
||||
:label="`Private ${isFE2Terms ? 'Project' : 'Stream'}`"
|
||||
></v-switch>
|
||||
</v-container>
|
||||
|
||||
@@ -169,6 +170,10 @@ export default {
|
||||
serverUrl: {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
isFE2Terms: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
@@ -201,6 +206,13 @@ export default {
|
||||
async getStream(){
|
||||
try {
|
||||
const streamWrapper = new StreamWrapper(this.createStreamByIdText, this.accountId, this.serverUrl)
|
||||
const match = streamWrapper.matchUrl(this.createStreamByIdText)
|
||||
if (match.groups.additionalModels !== undefined){
|
||||
this.$eventHub.$emit('error', {
|
||||
text: 'Multi-model URLs are not supported!\nTry to select just one single model in the web app and paste that in.',
|
||||
})
|
||||
return
|
||||
}
|
||||
let res = await this.$apollo.query({
|
||||
query: gql`
|
||||
query Stream($id: String!){
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
<template>
|
||||
<v-dialog v-model="dialog" max-width="400">
|
||||
<v-card>
|
||||
<v-card-title class="headline">Legacy Version</v-card-title>
|
||||
<v-card-text>
|
||||
⚠️Warning: This is a legacy connector.
|
||||
<br /><br />
|
||||
<a
|
||||
href="https://app.speckle.systems/connectors"
|
||||
target="_blank"
|
||||
style="color: #1976D2; text-decoration: none; font-weight: 500;"
|
||||
>
|
||||
Download next-gen SketchUp connector
|
||||
</a>
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn color="grey" text @click="dialog = false">Dismiss</v-btn>
|
||||
<v-btn color="primary" @click="downloadLatest">Download</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
dialog: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async downloadLatest() {
|
||||
const response = await fetch(
|
||||
`https://releases.speckle.dev/manager2/feeds/sketchup-v3.json`,
|
||||
{
|
||||
method: 'GET'
|
||||
}
|
||||
)
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to fetch versions')
|
||||
}
|
||||
|
||||
const data = await response.json()
|
||||
const sortedVersions = data.Versions.sort(function (a, b) {
|
||||
return new Date(b.Date).getTime() - new Date(a.Date).getTime()
|
||||
})
|
||||
const latestAvailableVersion = sortedVersions[0]
|
||||
|
||||
latestAvailableVersion.value = sortedVersions[0]
|
||||
window.open(latestAvailableVersion.value?.Url)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -16,14 +16,25 @@
|
||||
Settings
|
||||
</v-card-title>
|
||||
<v-container class="px-6" pb-0>
|
||||
<!-- Switch Theme -->
|
||||
|
||||
<!-- User preferences -->
|
||||
<div class="sm1 mt-3">User Preferences</div>
|
||||
<v-divider class="mb-2"/>
|
||||
|
||||
<!-- Switch Theme -->
|
||||
<v-btn icon small class="mx-1" @click="switchTheme">
|
||||
<v-icon>mdi-theme-light-dark</v-icon>
|
||||
</v-btn>
|
||||
<span>Color Mode</span>
|
||||
|
||||
<!-- FE2 -->
|
||||
<v-switch
|
||||
:input-value="fe2"
|
||||
class="pt-3 mt-n2 mb-n7"
|
||||
:label="'FE2'"
|
||||
@change="fe2Handler"
|
||||
/>
|
||||
|
||||
<!-- Register objects as Speckle Entity on send/receive -->
|
||||
<v-switch
|
||||
:input-value="registerSpeckleEntity"
|
||||
@@ -133,6 +144,7 @@ export default {
|
||||
includeComponentAttributes: this.preferences.model.include_component_entity_attributes,
|
||||
mergeCoplanarFaces: this.preferences.model.merge_coplanar_faces,
|
||||
diffing: this.preferences.user.diffing,
|
||||
fe2: this.preferences.user.fe2,
|
||||
registerSpeckleEntity: this.preferences.user.register_speckle_entity
|
||||
}
|
||||
},
|
||||
@@ -147,6 +159,7 @@ export default {
|
||||
this.includeComponentAttributes = newValue.model.include_component_entity_attributes
|
||||
this.mergeCoplanarFaces = newValue.model.merge_coplanar_faces
|
||||
this.diffing = newValue.user.diffing
|
||||
this.fe2 = newValue.user.fe2
|
||||
this.registerSpeckleEntity = newValue.user.register_speckle_entity
|
||||
},
|
||||
deep: true,
|
||||
@@ -161,6 +174,15 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
fe2Handler(newValue){
|
||||
this.fe2 = !!newValue
|
||||
sketchup.exec({
|
||||
name: "user_preferences_updated",
|
||||
data: {preference_hash: "configSketchup", preference: "fe2", value: this.fe2}
|
||||
})
|
||||
this.$mixpanel.track('Connector Action', { name: 'Toggle FE2' })
|
||||
sketchup.exec({name: "collect_preferences", data: {}})
|
||||
},
|
||||
diffingHandler(newValue){
|
||||
this.diffing = !!newValue
|
||||
sketchup.exec({
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user