Compare commits

...

41 Commits

Author SHA1 Message Date
Jedd Morgan df3b673064 refactor(ci): Update workflow to use new consolidated deployment workflow (#428)
Build and deploy / build (push) Has been cancelled
Build and deploy / deploy-installers (push) Has been cancelled
* Updated workflow

* update workflow

* target main
2025-04-25 10:43:27 +01:00
Oğuzhan Koral 69bde5539c Add serverUrl and workspaceSlug to model cards (#427)
Build and deploy / build (push) Has been cancelled
Build and deploy / deploy-installers (push) Has been cancelled
2025-04-21 15:06:19 +03:00
Oğuzhan Koral aa12b7b11b remove unnessary logging (#426) 2025-04-21 14:11:45 +03:00
Oğuzhan Koral e0b3b3cca2 Convert revit data object natively (#425) 2025-04-21 14:08:20 +03:00
Jedd Morgan ea9a5741d7 Update config.yml (#424) 2025-04-21 10:30:19 +03:00
Oğuzhan Koral 1fe1c8d5a8 Fix the source of the issue (#423)
Build and deploy / build (push) Has been cancelled
Build and deploy / deploy-installers (push) Has been cancelled
2025-03-28 16:47:56 +03:00
Oğuzhan Koral ac58560a69 Verbose about menu commands and guard about name (#422)
Build and deploy / build (push) Has been cancelled
Build and deploy / deploy-installers (push) Has been cancelled
2025-03-24 15:32:39 +03:00
Oğuzhan Koral d0b234bf3d delete ruby.yml temp (#421)
Build and deploy / build (push) Has been cancelled
Build and deploy / deploy-installers (push) Has been cancelled
2025-03-19 13:32:09 +03:00
oguzhankoral 981fe05c15 deploy over main 2025-03-19 11:50:17 +03:00
Oğuzhan Koral 918550465b No more beta (#418) 2025-03-19 10:20:46 +03:00
Oğuzhan Koral 963d4f1738 Add remove account and remove models (#417) 2025-03-19 10:16:34 +03:00
oguzhankoral d809732280 Merge branch 'dui3/alpha'
# Conflicts:
#	.circleci/config.yml
2025-03-17 23:16:02 +03:00
oguzhankoral c4e38a11b7 run on ubuntu-22.04 2025-03-17 20:03:42 +03:00
oguzhankoral 7abe215bc2 sorry circleci, have you back for now 2025-03-17 20:01:04 +03:00
oguzhankoral 0f269430bc no more circleci 2025-03-17 19:29:39 +03:00
Oğuzhan Koral b8a298c54b Fix: various papercuts (#409)
Build and deploy / build (push) Has been cancelled
Build and deploy / deploy-installers (push) Has been cancelled
* Do not report converted grouped meshes

* remember last selected account on db
2025-03-10 18:36:58 +03:00
Oğuzhan Koral e1d33cd250 fix the highlight freeze (#408) 2025-03-10 16:18:07 +03:00
Oğuzhan Koral 4563dec9bc Debounce progress update (#407) 2025-03-07 21:07:44 +03:00
Oğuzhan Koral de284083fd add defintiion and layer name to instance proxy (#406)
Build and deploy / build (push) Has been cancelled
Build and deploy / deploy-installers (push) Has been cancelled
2025-03-07 12:19:11 +03:00
Oğuzhan Koral 85ee66ca4d Fix(instances): instance name prop is missing (#405)
Build and deploy / build (push) Has been cancelled
Build and deploy / deploy-installers (push) Has been cancelled
* add name to instances

* set name only if it is not empty
2025-03-07 12:04:16 +03:00
Jedd Morgan 5365dc858e Jedd/cxpla 169 update connector deployment ci to error on publishing zero (#404)
* Update deploy.yml

* Update build.yml
2025-03-05 11:47:56 +03:00
Oğuzhan Koral 69f9544638 get accounts always from sqlite - not from cached state (#403)
Build and deploy / build (push) Has been cancelled
Build and deploy / deploy-installers (push) Has been cancelled
2025-02-27 14:57:28 +03:00
Oğuzhan Koral bf5409cf90 Feat(dui3): add properties (#402)
Build and deploy / build (push) Has been cancelled
Build and deploy / deploy-installers (push) Has been cancelled
* rename sketchup_attributes with properties for send

* receive properties

* handle send receive properties
2025-02-18 22:32:05 +03:00
Oğuzhan Koral bd4f668526 Make selection is default (#401)
Build and deploy / build (push) Has been cancelled
Build and deploy / deploy-installers (push) Has been cancelled
2025-01-16 19:34:16 +03:00
Oğuzhan Koral d21df0c6fd Update build.yml
Build and deploy / build (push) Has been cancelled
Build and deploy / deploy-installers (push) Has been cancelled
2024-12-20 17:33:55 +03:00
Oğuzhan Koral d808fdaa09 Update build.yml 2024-12-20 17:31:44 +03:00
Oğuzhan Koral b32d23b9d6 Do not check speckle_type from level anymore (#400)
Build and deploy / build (push) Has been cancelled
Build and deploy / deploy-installers (push) Has been cancelled
2024-12-19 20:44:13 +03:00
Oğuzhan Koral d1b8ba95df Fix(arc): CNX-712 civil2skp alignments missing pieces (#399)
* Normalize plane axis always

* measure based fix

* backward compatible arcs without measures
2024-12-13 00:26:44 +03:00
Oğuzhan Koral 5e6825bbdb Feat(dui3): sketchup send batches sequentially (#397)
* feat: send batches in sequence and create commit later

* Remove load tests
2024-12-12 12:26:11 +03:00
Oğuzhan Koral 3e5ba136be Align arcs with new object model (#396) 2024-11-11 14:33:23 +00:00
oguzhankoral 294b49a11c Add debug notes 2024-11-11 12:01:09 +00:00
Oğuzhan Koral 9e0cca447f Rename the menu title as Speckle Beta (#393)
Build and deploy / build (push) Has been cancelled
Build and deploy / deploy-installers (push) Has been cancelled
2024-10-26 23:00:11 +03:00
Oğuzhan Koral bc3f23d8dd Add units to root object on send (#392)
Build and deploy / build (push) Has been cancelled
Build and deploy / deploy-installers (push) Has been cancelled
2024-09-23 19:35:01 +03:00
oguzhankoral 4fcf11eaa8 Fix url 2024-09-19 14:27:13 +03:00
Oğuzhan Koral 1f45902837 Add workspace id to model cards (#391)
Co-authored-by: Oguzhan Koral <oguzhankoral@192.168.1.104>
2024-09-16 16:49:22 +03:00
Oğuzhan Koral bc55543e23 Feat(dui3): add new properties to receiver model card (#390)
Build and deploy / build (push) Has been cancelled
Build and deploy / deploy-installers (push) Has been cancelled
* Add new properties to receiver model card

* Update state correctly from read data at doc init
2024-09-11 15:11:54 +03:00
Oğuzhan Koral c1b8ec7036 Create DUI3Config.db file and objects table if not exists (#389)
Build and deploy / build (push) Has been cancelled
Build and deploy / deploy-installers (push) Has been cancelled
2024-09-06 02:12:12 +03:00
Alan Rynne abe9de1b4a fix: Update gitversion to v6 to align with csharp connectors (#388)
Build and deploy / build (push) Has been cancelled
Build and deploy / deploy-installers (push) Has been cancelled
2024-09-03 12:21:42 +02:00
oguzhankoral 20528f72df Merge remote-tracking branch 'origin/development' 2024-03-19 13:32:03 +03:00
oguzhankoral ad9af9bb3d Merge remote-tracking branch 'origin/development' 2024-02-27 12:38:00 +03:00
oguzhankoral 133308141b Merge branch 'development' 2023-11-28 13:57:11 +03:00
56 changed files with 697 additions and 198 deletions
Vendored
BIN
View File
Binary file not shown.
+17
View File
@@ -0,0 +1,17 @@
version: 2.1
# Define the jobs we want to run for this project
jobs:
build:
docker:
- image: cimg/base:2023.03
steps:
- run: echo "so long and thanks for all the fish"
# Orchestrate our job run sequence
workflows:
build_and_test:
when:
false
jobs:
- build
+3 -1
View File
@@ -32,7 +32,7 @@ jobs:
- name: Install GitVersion
uses: gittools/actions/gitversion/setup@v3.0.0
with:
versionSpec: "5.x"
versionSpec: 6.0.5 # github actions doesnt like 6.1.0 onwards https://github.com/GitTools/actions/blob/main/docs/versions.md
- name: Determine Version
id: gitversion
@@ -50,6 +50,8 @@ jobs:
with:
name: output-${{steps.gitversion.outputs.semVer}}
path: sketchup.zip
retention-days: 1
if-no-files-found: error
compression-level: 0 # no compression
- id: set-version
name: Set version to output
+16 -7
View File
@@ -5,8 +5,8 @@ name: Build and deploy
on:
push:
branches: ["dui3/alpha", "deploy/*"] # Continuous delivery on every long-lived branch
tags: ["v3.*"] # Manual delivery on every 3.x tag
branches: ["main", "installer-test/**"]
tags: ["v3.*.*"] # Manual delivery on every 3.x tag
jobs:
build:
@@ -16,18 +16,27 @@ jobs:
runs-on: ubuntu-latest
needs: build
env:
IS_TAG_BUILD: ${{ github.ref_type == 'tag' }}
IS_PUBLIC_RELEASE: ${{ github.ref_type == 'tag' }}
steps:
- name: 🔫 Trigger Build Installers
uses: ALEEF02/workflow-dispatch@v3.0.0
- name: 🔫 Trigger Build Installer(s)
uses: the-actions-org/workflow-dispatch@v4.0.0
with:
workflow: Build Sketchup
workflow: Build Installers
repo: specklesystems/connector-installers
token: ${{ secrets.CONNECTORS_GH_TOKEN }}
inputs: '{ "run_id": "${{ github.run_id }}", "semver": "${{ needs.build.outputs.semver }}", "file_version": "${{ needs.build.outputs.file_version }}", "public_release": ${{ env.IS_TAG_BUILD }} }'
inputs: '{
"run_id": "${{ github.run_id }}",
"semver": "${{ needs.build.outputs.semver }}",
"file_version": "${{ needs.build.outputs.file_version }}",
"repo": "${{ github.repository }}",
"is_public_release": ${{ env.IS_PUBLIC_RELEASE }}
}'
ref: main
wait-for-completion: true
wait-for-completion-interval: 10s
wait-for-completion-timeout: 10m
display-workflow-run-url: true
display-workflow-run-url-interval: 10s
- uses: geekyeggo/delete-artifact@v5
with:
name: output-*
-38
View File
@@ -1,38 +0,0 @@
# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.
# This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake
# For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby
name: Ruby
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
permissions:
contents: read
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
ruby-version: ['2.7']
steps:
- uses: actions/checkout@v3
- name: Set up Ruby
# To automatically get bug fixes and new Ruby versions for ruby/setup-ruby,
# change this to (see https://github.com/ruby/setup-ruby#versioning):
# uses: ruby/setup-ruby@v1
uses: ruby/setup-ruby@0a29871fe2b0200a17a4497bae54fe5df0d973aa # v1.115.3
with:
ruby-version: ${{ matrix.ruby-version }}
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
- name: Run tests
run: bundle exec rake
+6 -13
View File
@@ -1,18 +1,11 @@
workflow: GitFlow/v1
next-version: 3.0.0
mode: ContinuousDeployment
assembly-informational-format: "{Major}.{Minor}.{Patch}-{PreReleaseTag}"
mode: ManualDeployment
branches:
main:
regex: ^main$
tag: rc
label: rc
develop:
regex: ^development$
tag: dev
pull-request:
tag: pr
beta:
regex: ^dui3/alpha$
tag: beta
source-branches:
- develop
- main
label: beta
unknown:
increment: None
+14
View File
@@ -115,6 +115,20 @@ You can now open up the repo in VS Code or you can use JetBrains' tools RubyMine
If you will use VS Code, make sure you've installed the Ruby extension for VS Code.
#### RubyMine
To debug:
- Add configuration as **'Ruby remote debug'**
- Remote host: localhost
- Remote port: 7000
- Remote root folder: <repo_path>
- Local port: 26162
- Local root folder: <repo_path>
- Run below script
bundle exec skippy sketchup:debug 2024
- When sketchup opened, click Debug button on RubyMine
### Loading the Speckle Connector Plugin
1. Find already prepared `speckle_connector_3_loader.rb` file on the `_tools`
BIN
View File
Binary file not shown.
Binary file not shown.
+27 -5
View File
@@ -3,6 +3,7 @@
require 'JSON'
require_relative '../ext/sqlite3'
require_relative '../constants/path_constants'
require_relative '../preferences/preferences'
module SpeckleConnector3
# Accounts to communicate with models on user's account.
@@ -11,11 +12,11 @@ module SpeckleConnector3
def self.load_accounts
db_path = SPECKLE_ACCOUNTS_DB_PATH
unless File.exist?(db_path)
raise(
IOError,
"No Accounts db found. Please read the guide for different options for adding your account:\n
https://speckle.guide/user/manager.html#adding-accounts"
)
File.new(SPECKLE_ACCOUNTS_DB_PATH, "w")
db = Sqlite3::Database.new(SPECKLE_ACCOUNTS_DB_PATH)
Preferences.create_objects_table(db)
db.close
return []
end
db = Sqlite3::Database.new(db_path)
@@ -24,6 +25,27 @@ module SpeckleConnector3
rows.map { |row| JSON.parse(row[1]) }
end
def self.remove_account(account_id)
db_path = SPECKLE_ACCOUNTS_DB_PATH
unless File.exist?(db_path)
raise(
IOError,
"No Accounts db found. Please read the guide for different options for adding your account:\n
https://speckle.guide/user/manager.html#adding-accounts"
)
end
db = Sqlite3::Database.new(db_path)
begin
db.exec("DELETE FROM objects WHERE hash = '#{account_id}'")
puts "Account with hash #{account_id} has been removed."
rescue StandardError => e
puts "An error occurred: #{e}"
ensure
db.close
end
end
def self.get_account_by_id(id)
accounts = load_accounts
accounts.select { |acc| acc['id'] == id }[0]
@@ -1,8 +1,8 @@
# frozen_string_literal: true
require_relative 'action'
require_relative '../accounts/accounts'
require_relative 'load_saved_streams'
require_relative '../action'
require_relative '../../accounts/accounts'
require_relative '../load_saved_streams'
module SpeckleConnector3
module Actions
@@ -12,7 +12,7 @@ module SpeckleConnector3
# @return [States::State] the new updated state object
def self.update_state(state, resolve_id)
puts 'Initialisation of Speckle accounts requested by plugin'
accounts_data = state.speckle_state.accounts
accounts_data = SpeckleConnector3::Accounts.load_accounts
js_script = "accountsBinding.receiveResponse('#{resolve_id}', #{accounts_data.to_json})"
state.with_add_queue_js_command('getAccounts', js_script)
end
@@ -0,0 +1,20 @@
# frozen_string_literal: true
require_relative '../action'
require_relative '../../accounts/accounts'
require_relative '../load_saved_streams'
module SpeckleConnector3
module Actions
# Action to remove account from database.
class RemoveAccount < 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, resolve_id, account_id)
SpeckleConnector3::Accounts.remove_account(account_id)
js_script = "accountsBinding.receiveResponse('#{resolve_id}')"
state.with_add_queue_js_command('removeAccount', js_script)
end
end
end
end
@@ -17,20 +17,28 @@ module SpeckleConnector3
def self.update_state(state, resolve_id, data)
model_card_id = data['modelCardId']
account_id = data['accountId']
server_url = data['serverUrl']
workspace_id = data['workspaceId']
workspace_slug = data['workspaceSlug']
project_id = data['projectId']
model_id = data['modelId']
project_name = data['projectName']
model_name = data['modelName']
expired = data['expired']
selected_version_id = data['selectedVersionId']
selected_version_source_app = data['selectedVersionSourceApp']
selected_version_user_id = data['selectedVersionUserId']
latest_version_id = data['latestVersionId']
latest_version_source_app = data['latestVersionSourceApp']
latest_version_user_id = data['latestVersionUserId']
has_dismissed_update_warning = data['hasDismissedUpdateWarning']
baked_object_ids = data['bakedObjectIds'].nil? ? nil : data['bakedObjectIds'].values
receive_card = Cards::ReceiveCard.new(model_card_id, account_id,
receive_card = Cards::ReceiveCard.new(model_card_id, account_id, server_url, workspace_id, workspace_slug,
project_id, model_id,
project_name, model_name,
selected_version_id, latest_version_id,
selected_version_id, selected_version_source_app, selected_version_user_id,
latest_version_id, latest_version_source_app, latest_version_user_id,
has_dismissed_update_warning, expired, baked_object_ids)
SketchupModel::Dictionary::ModelCardDictionaryHandler
.save_receive_card_to_model(receive_card, state.sketchup_state.sketchup_model)
@@ -22,6 +22,9 @@ module SpeckleConnector3
send_card = Cards::SendCard.new(
data['modelCardId'],
data['accountId'],
data['serverUrl'],
data['workspaceId'],
data['workspaceSlug'],
data['projectId'],
data['projectName'],
data['modelId'],
@@ -21,6 +21,9 @@ module SpeckleConnector3
send_card = Cards::SendCard.new(
id,
card['account_id'],
card['server_url'],
card['workspace_id'],
card['workspace_slug'],
card['project_id'],
card['project_name'],
card['model_id'],
@@ -35,6 +38,9 @@ module SpeckleConnector3
{
modelCardId: send_card.model_card_id,
accountId: send_card.account_id,
serverUrl: send_card.server_url,
workspaceId: send_card.workspace_id,
workspaceSlug: send_card.workspace_slug,
projectId: send_card.project_id,
modelId: send_card.model_id,
sendFilter: send_card.send_filter,
@@ -49,9 +55,11 @@ module SpeckleConnector3
# TODO: CONVERTER_V2: Extract into new actions
receive_cards = receive_cards_hash.collect do |id, card|
receive_card = Cards::ReceiveCard.new(id, card['account_id'], card['project_id'], card['model_id'],
receive_card = Cards::ReceiveCard.new(id, card['account_id'], card['server_url'], card['workspace_id'], card['workspace_slug'], card['project_id'], card['model_id'],
card['project_name'], card['model_name'], card['selected_version_id'],
card['latest_version_id'], card['has_dismissed_update_warning'],
card['selected_version_source_app'], card['selected_version_user_id'],
card['latest_version_id'], card['latest_version_source_app'],
card['latest_version_user_id'], card['has_dismissed_update_warning'],
card['expired'], card['baked_object_ids'])
new_speckle_state = state.speckle_state.with_receive_card(receive_card)
@@ -59,12 +67,19 @@ module SpeckleConnector3
{
modelCardId: receive_card.model_card_id,
accountId: receive_card.account_id,
serverUrl: receive_card.server_url,
workspaceId: receive_card.workspace_id,
workspaceSlug: receive_card.workspace_slug,
projectId: receive_card.project_id,
modelId: receive_card.model_id,
projectName: receive_card.project_name,
modelName: receive_card.model_name,
selectedVersionId: receive_card.selected_version_id,
selectedVersionSourceApp: receive_card.selected_version_source_app,
selectedVersionUserId: receive_card.selected_version_user_id,
latestVersionId: receive_card.latest_version_id,
latestVersionSourceApp: receive_card.latest_version_source_app,
latestVersionUserId: receive_card.latest_version_user_id,
hasDismissedUpdateWarning: receive_card.has_dismissed_update_warning,
expired: receive_card.expired,
bakedObjectIds: receive_card.baked_object_ids,
@@ -0,0 +1,34 @@
# frozen_string_literal: true
require_relative '../action'
require_relative '../../cards/send_card'
require_relative '../../cards/receive_card'
require_relative '../../filters/send/everything_filter'
require_relative '../../filters/send/selection_filter'
require_relative '../../filters/send_filters'
require_relative '../../sketchup_model/dictionary/model_card_dictionary_handler'
module SpeckleConnector3
module Actions
# Action to remove cards.
class RemoveModels < 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, resolve_id, data)
data.each do |model_card|
SketchupModel::Dictionary::ModelCardDictionaryHandler.remove_card_dict(state.sketchup_state.sketchup_model, model_card)
new_speckle_state = if model_card['typeDiscriminator'] == 'ReceiverModelCard'
state.speckle_state.without_receive_card(model_card['id'])
else
state.speckle_state.without_send_card(model_card['id'])
end
state = state.with_speckle_state(new_speckle_state)
end
# Resolve promise
js_script = "baseBinding.receiveResponse('#{resolve_id}')"
state.with_add_queue_js_command('removeModels', js_script)
end
end
end
end
@@ -0,0 +1,21 @@
# frozen_string_literal: true
require_relative '../action'
require_relative '../../preferences/preferences'
module SpeckleConnector3
module Actions
class GetUserSelectedAccountId < 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, resolve_id)
user_selected_account_id = Preferences.get_user_selected_account_id
accountsConfig = {
userSelectedAccountId: user_selected_account_id
}
js_script = "configBinding.receiveResponse('#{resolve_id}', #{accountsConfig.to_json})"
state.with_add_queue_js_command('getUserSelectedAccountId', js_script)
end
end
end
end
@@ -0,0 +1,18 @@
# frozen_string_literal: true
require_relative '../action'
require_relative '../../preferences/preferences'
module SpeckleConnector3
module Actions
class SetUserSelectedAccountId < 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, resolve_id, account_id)
Preferences.set_user_selected_account_id(account_id)
js_script = "configBinding.receiveResponse('#{resolve_id}')"
state.with_add_queue_js_command('setUserSelectedAccountId', js_script)
end
end
end
end
@@ -0,0 +1,36 @@
# frozen_string_literal: true
require_relative '../action'
require_relative '../../convertors/to_native'
require_relative '../../convertors/to_native_v2'
module SpeckleConnector3
module Actions
# After objects send to server.
class AfterSendObjects < 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, resolve_id, model_card_id, referenced_object_id)
model_card = state.speckle_state.send_cards[model_card_id]
account = Accounts.get_account_by_id(model_card.account_id)
args = {
modelCardId: model_card_id,
projectId: model_card.project_id,
modelId: model_card.model_id,
token: account['token'],
serverUrl: account['serverInfo']['url'],
accountId: model_card.account_id,
message: model_card.message,
referencedObjectId: referenced_object_id,
sendConversionResults: state.speckle_state.conversion_results[model_card_id]
}
after_send_object_js_script = "sendBinding.emit('createVersionViaBrowser', #{args.to_json})"
state = state.with_add_queue_js_command('createVersionViaBrowser', after_send_object_js_script)
resolve_js_script = "sendBinding.receiveResponse('#{resolve_id}')"
state.with_add_queue_js_command('afterSendObject', resolve_js_script)
end
end
end
end
@@ -17,7 +17,9 @@ module SpeckleConnector3
# @return [States::State] the new updated state object
def self.update_state(state, resolve_id, model_card_id)
# Set active path always to model to be safe always. Later we can address it
start_time = Time.now.to_f
state.sketchup_state.sketchup_model.active_path = nil
units = Converters::SKETCHUP_UNITS[state.sketchup_state.length_units]
model_card = state.speckle_state.send_cards[model_card_id]
unless model_card.send_filter.selected_object_ids.any?
resolve_js_script = "sendBinding.receiveResponse('#{resolve_id}')"
@@ -35,7 +37,7 @@ module SpeckleConnector3
end
unpacked_entities = SketchupModel::Definitions::DefinitionManager
.new(Converters::SKETCHUP_UNITS[state.sketchup_state.length_units])
.new(units)
.unpack_entities(entities)
unpacked_materials = SketchupModel::Materials::MaterialManager.new.unpack_materials(entities)
@@ -50,34 +52,75 @@ module SpeckleConnector3
base[:instanceDefinitionProxies] = unpacked_entities.instance_definition_proxies
base[:renderMaterialProxies] = unpacked_materials
base[:colorProxies] = unpacked_colors
base[:units] = units
elapsed_time = (Time.now.to_f - start_time).round(3)
puts "==== Converting objects executed in #{elapsed_time} sec ===="
start_time = Time.now.to_f
sender_progress_args = {
modelCardId: model_card_id,
progress: {
progress: nil,
status: 'Serializing'
}
}
state.instant_message_sender.call("sendBinding.emit('setModelProgress', #{sender_progress_args.to_json})")
id, batches, refs = converter.serialize(base, state.user_state.preferences)
elapsed_time = (Time.now.to_f - start_time).round(3)
puts "==== Serializing objects executed in #{elapsed_time} sec ===="
new_speckle_state = new_speckle_state.with_object_references(model_card.project_id, refs)
new_speckle_state = new_speckle_state.with_empty_changed_entity_persistent_ids
new_speckle_state = new_speckle_state.with_empty_changed_entity_ids
puts "Cached/Total object: #{converter.cached_object_count}/#{converter.object_count}"
puts("converted #{base.count} objects for stream #{model_card.project_id}")
state = state.with_speckle_state(new_speckle_state)
resolve_js_script = "sendBinding.receiveResponse('#{resolve_id}')"
state = state.with_add_queue_js_command('send', resolve_js_script)
args = {
modelCardId: model_card_id,
projectId: model_card.project_id,
modelId: model_card.model_id,
token: account['token'],
serverUrl: account['serverInfo']['url'],
accountId: model_card.account_id,
message: model_card.message,
sendConversionResults: converter.conversion_results,
sendObject: {
id: id,
batches: batches
# args = {
# modelCardId: model_card_id,
# projectId: model_card.project_id,
# modelId: model_card.model_id,
# token: account['token'],
# serverUrl: account['serverInfo']['url'],
# accountId: model_card.account_id,
# message: model_card.message,
# sendConversionResults: converter.conversion_results,
# sendObject: {
# id: id,
# batches: batches
# }
# }
# js_script = "sendBinding.emit('sendViaBrowser', #{args.to_json})"
# state.with_add_queue_js_command('sendViaBrowser', js_script)
# store conversion results in state to pick up later
new_speckle_state = state.speckle_state.with_conversion_results(model_card_id, converter.conversion_results)
state = state.with_speckle_state(new_speckle_state)
total_batch_count = batches.count
batches.each_with_index do |batch, i|
current_batch = i + 1
args = {
modelCardId: model_card_id,
projectId: model_card.project_id,
token: account['token'],
serverUrl: account['serverInfo']['url'],
batch: batch,
currentBatch:current_batch,
totalBatch: total_batch_count,
referencedObjectId: id
}
}
js_script = "sendBinding.emit('sendViaBrowser', #{args.to_json})"
state.with_add_queue_js_command('sendViaBrowser', js_script)
js_script = "sendBinding.emit('sendBatchViaBrowser', #{args.to_json})"
state = state.with_add_queue_js_command("sendBatchViaBrowser_#{current_batch}", js_script)
end
state
end
end
end
+16 -1
View File
@@ -24,25 +24,40 @@ module SpeckleConnector3
# @return [String] model name of the card.
attr_reader :model_name
# @return [String] workspace id of the card.
attr_reader :workspace_id
# @return [String] workspace slug of the card.
attr_reader :workspace_slug
# @return [String] server url of the card.
attr_reader :server_url
# @return [Boolean] card is valid or not.
attr_reader :valid
# rubocop:disable Metrics/ParameterLists
def initialize(model_card_id, account_id, project_id, project_name, model_id, model_name)
def initialize(model_card_id, account_id, server_url, workspace_id, workspace_slug, project_id, project_name, model_id, model_name)
super()
@model_card_id = model_card_id
@account_id = account_id
@workspace_id = workspace_id
@workspace_slug = workspace_slug
@project_id = project_id
@project_name = project_name
@model_id = model_id
@model_name = model_name
@server_url = server_url
@valid = true
self[:model_card_id] = model_card_id
self[:account_id] = account_id
self[:workspace_id] = workspace_id
self[:workspace_slug] = workspace_slug
self[:project_id] = project_id
self[:project_name] = project_name
self[:model_id] = model_id
self[:model_name] = model_name
self[:server_url] = server_url
self[:valid] = @valid
end
# rubocop:enable Metrics/ParameterLists
+35 -8
View File
@@ -14,9 +14,21 @@ module SpeckleConnector3
# @return [String] selected version id to receive
attr_reader :selected_version_id
# @return [String] selected version source app
attr_reader :selected_version_source_app
# @return [String] selected version user id
attr_reader :selected_version_user_id
# @return [String] latest version id to receive
attr_reader :latest_version_id
# @return [String] latest version source app
attr_reader :latest_version_source_app
# @return [String] latest version user id
attr_reader :latest_version_user_id
# @return [Boolean] whether new version notification is dismissed or not
attr_reader :has_dismissed_update_warning
@@ -36,32 +48,47 @@ module SpeckleConnector3
def initialize(
model_card_id,
account_id,
server_url,
workspace_id,
workspace_slug,
project_id,
model_id,
project_name,
model_name,
selected_version_id,
selected_version_source_app,
selected_version_user_id,
latest_version_id,
latest_version_source_app,
latest_version_user_id,
has_dismissed_update_warning,
expired,
baked_object_ids = nil
)
super(model_card_id, account_id, project_id, project_name, model_id, model_name)
super(model_card_id, account_id, server_url, workspace_id, workspace_slug, project_id, project_name, model_id, model_name)
@selected_version_id = selected_version_id
@selected_version_source_app = selected_version_source_app
@selected_version_user_id = selected_version_user_id
@latest_version_id = latest_version_id
@latest_version_source_app = latest_version_source_app
@latest_version_user_id = latest_version_user_id
@has_dismissed_update_warning = has_dismissed_update_warning
@baked_object_ids = baked_object_ids
self[:selected_version_id] = selected_version_id
self[:has_dismissed_update_warning] = has_dismissed_update_warning
self[:latest_version_id] = latest_version_id
self[:model_name] = model_name
self[:project_name] = project_name
self[:expired] = expired
self[:baked_object_ids] = @baked_object_ids
@expired = expired
@model_name = model_name
@project_name = project_name
@type_discriminator = 'ReceiverModelCard'
self[:selected_version_id] = selected_version_id
self[:selected_version_source_app] = selected_version_source_app
self[:selected_version_user_id] = selected_version_user_id
self[:has_dismissed_update_warning] = has_dismissed_update_warning
self[:latest_version_id] = latest_version_id
self[:latest_version_source_app] = latest_version_source_app
self[:latest_version_user_id] = latest_version_user_id
self[:model_name] = model_name
self[:project_name] = project_name
self[:expired] = expired
self[:baked_object_ids] = @baked_object_ids
self[:type_discriminator] = @type_discriminator
end
# rubocop:enable Metrics/ParameterLists
+4 -1
View File
@@ -26,6 +26,9 @@ module SpeckleConnector3
def initialize(
model_card_id,
account_id,
server_url,
workspace_id,
workspace_slug,
project_id,
project_name,
model_id,
@@ -34,7 +37,7 @@ module SpeckleConnector3
send_filter,
send_settings
)
super(model_card_id, account_id, project_id, project_name, model_id, model_name)
super(model_card_id, account_id, server_url, workspace_id, workspace_slug, project_id, project_name, model_id, model_name)
@send_filter = send_filter
@send_settings = send_settings
@latest_created_version_id = latest_created_version_id
@@ -1,19 +1,19 @@
# frozen_string_literal: true
require_relative 'card'
module SpeckleConnector3
module Cards
# Send card for sketchup connector to communicate speckle.
class SendCardMultipleFilters < Card
# @return [Hash{String=>Filter}] filters of the card.
attr_reader :filters
def initialize(card_id, account_id, project_id, model_id, filters)
super(card_id, account_id, project_id, model_id)
@filters = filters
self[:filters] = filters
end
end
end
end
# # frozen_string_literal: true
#
# require_relative 'card'
#
# module SpeckleConnector3
# module Cards
# # Send card for sketchup connector to communicate speckle.
# class SendCardMultipleFilters < Card
# # @return [Hash{String=>Filter}] filters of the card.
# attr_reader :filters
#
# def initialize(card_id, account_id, project_id, model_id, filters)
# super(card_id, account_id, project_id, model_id)
# @filters = filters
# self[:filters] = filters
# end
# end
# end
# end
+1 -1
View File
@@ -26,7 +26,7 @@ module SpeckleConnector3
_run(*parameters)
end
rescue StandardError => e
action = Actions::HandleError.new(e, @binding.name, @action, parameters)
action = Actions::HandleError.new(e, @binding.nil? ? "unknown binding" : @binding.name, @action, parameters)
app.update_state!(action)
end
end
@@ -22,7 +22,7 @@ module SpeckleConnector3
SPECKLE_DUI3 = 'speckle_dui3'
def dialog_title
"Speckle (Beta) for SketchUp"
"Speckle for SketchUp"
end
private
@@ -9,6 +9,8 @@ module SpeckleConnector3
# @return [UI::Command] the command that can be added to Sketchup menu or toolbar
def self.sketchup_command(command, menu_text)
UI::Command.new(menu_text) do
puts '### COMMAND CALLED BY MENU ###'
puts "Name: #{menu_text}"
command.run
end
end
@@ -65,10 +65,10 @@ module SpeckleConnector3
def self.initialize_dui3_speckle_command(app)
cmd = MenuCommandHandler.sketchup_command(
InitializeDUI3Speckle.new(app, nil), 'Initialize Speckle (Beta)'
InitializeDUI3Speckle.new(app, nil), 'Initialize Speckle'
)
cmd.tooltip = 'Speckle (Beta) for SketchUp'
cmd.status_bar_text = 'Opens the Speckle Connector (Beta)'
cmd.tooltip = 'Speckle for SketchUp'
cmd.status_bar_text = 'Opens the Speckle Connector'
cmd.small_icon = '../../img/s2logo_dui3.png'
cmd.large_icon = '../../img/s2logo_dui3.png'
cmd
@@ -54,4 +54,8 @@ module SpeckleConnector3
SPECKLE_CORE_MODELS_INSTANCES_INSTANCE_DEFINITION_PROXY = 'Speckle.Core.Models.Instances.InstanceDefinitionProxy'
SPECKLE_CORE_OTHER_RENDER_MATERIAL_PROXY = 'Objects.Other.RenderMaterialProxy'
SPECKLE_CORE_OTHER_COLOR_PROXY = 'Speckle.Core.Models.Proxies.ColorProxy'
# DATA OBJECTS
SPECKLE_OBJECT_DATA_OBJECT = 'Objects.Data.DataObject'
SPECKLE_OBJECT_DATA_OBJECT_REVIT = 'Objects.Data.DataObject:Objects.Data.RevitObject'
end
@@ -22,6 +22,7 @@ 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 '../speckle_objects/instance_definition_proxy'
require_relative '../speckle_objects/data/revit_data_object'
require_relative '../sketchup_model/dictionary/speckle_entity_dictionary_handler'
require_relative '../ui_data/report/conversion_result'
require_relative '../convertors/conversion_error'
@@ -94,6 +95,8 @@ module SpeckleConnector3
LAYER_COLLECTION = SpeckleObjects::Speckle::Core::Models::LayerCollection
GIS_LAYER_COLLECTION = SpeckleObjects::Speckle::Core::Models::GisLayerCollection
REVIT_DATA_OBJECT = SpeckleObjects::RevitDataObject
BASE_OBJECT_PROPS = %w[applicationId id speckle_type].freeze
CONVERTABLE_SPECKLE_TYPES = %w[
Objects.Geometry.Line
@@ -117,6 +120,7 @@ module SpeckleConnector3
Speckle.Core.Models.Collections.Collection:Speckle.Core.Models.Collections.Layer
Speckle.Core.Models.Collections.Collection:Objects.GIS.RasterLayer
Speckle.Core.Models.Collections.Collection:Objects.GIS.VectorLayer
Objects.Data.DataObject:Objects.Data.RevitObject
].freeze
def from_revit
@@ -153,6 +157,11 @@ module SpeckleConnector3
definition_name = proxy['name']
definition = state.sketchup_state.sketchup_model.definitions.add(definition_name)
properties = proxy['properties'] || proxy['sketchup_attributes']
unless properties.nil?
SketchupModel::Dictionary::BaseDictionaryHandler
.attribute_dictionaries_to_native(definition, properties['dictionaries'])
end
definition.behavior.always_face_camera = proxy['alwaysFaceCamera'] if proxy['alwaysFaceCamera']
@definition_proxies[proxy['applicationId']] = SpeckleObjects::InstanceDefinitionProxy.new(
definition,
@@ -372,6 +381,10 @@ module SpeckleConnector3
# rubocop:enable Metrics/PerceivedComplexity
def speckle_object_to_native(obj)
if SPECKLE_OBJECTS_WITH_NATIVE_CONVERSION[obj['speckle_type']]
return SPECKLE_OBJECTS_WITH_NATIVE_CONVERSION[obj['speckle_type']]
end
return DISPLAY_VALUE.method(:to_native) unless obj['displayValue'].nil? && obj['@displayValue'].nil?
SPECKLE_OBJECT_TO_NATIVE[obj['speckle_type']]
@@ -404,6 +417,10 @@ module SpeckleConnector3
SPECKLE_CORE_MODELS_COLLECTION_VECTOR_LAYER => GIS_LAYER_COLLECTION.method(:to_native)
}.freeze
SPECKLE_OBJECTS_WITH_NATIVE_CONVERSION = {
SPECKLE_OBJECT_DATA_OBJECT_REVIT => REVIT_DATA_OBJECT.method(:to_native)
}
def entities_to_bake(obj, entities)
entities_to_bake = entities
object_id = obj['applicationId'].to_s # TODO: CONVERTER_V2: faces have integer application id..!!?
@@ -447,14 +464,25 @@ module SpeckleConnector3
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)
# Create layers from category of object and place object in it
# create_layers_from_categories(state, obj, converted_entities)
begin
# Create levels as section planes if they exists
create_levels(state, obj)
# Create layers from category of object and place object in it
# create_layers_from_categories(state, obj, converted_entities)
rescue StandardError => e
puts "Level could not be created: #{e.message}"
end
end
# Create speckle entities from sketchup entities to achieve continuous traversal.
converted_entities.each do |converted|
if converted.is_a?(Sketchup::ComponentDefinition)
next # no need to report definitions
end
if !from_sketchup && converted.is_a?(Sketchup::Face)
next # Otherwise we have many noise in report and causing delay post-receive
end
@conversion_results.push(UiData::Report::ConversionResult.new(UiData::Report::ConversionStatus::SUCCESS,
obj['id'],
obj['speckle_type'],
@@ -504,7 +532,7 @@ module SpeckleConnector3
def create_levels(state, speckle_object)
level = speckle_object['level']
return state if level.nil?
return state unless level['speckle_type'].include?('Objects.BuiltElements.Level')
# return state unless level['speckle_type'].include?('Objects.BuiltElements.Level')
level_name = level['name'] || level['id']
is_exist = @entities_to_fill.grep(Sketchup::SectionPlane).any? { |sp| sp.name == level_name }
@@ -37,12 +37,17 @@ module SpeckleConnector3
# @return [SketchupModel::Definitions::UnpackResult]
attr_reader :unpacked_entities
attr_reader :object_count
attr_reader :cached_object_count
# @param model_card [Cards::SendCard] sender card
def initialize(state, unpacked_entities, model_card)
super(state, model_card)
@send_filter = model_card.send_filter
@conversion_results = []
@unpacked_entities = unpacked_entities
@object_count = 0
@cached_object_count = 0
end
def convert_entities_to_base_blocks_poc
@@ -64,11 +69,9 @@ module SpeckleConnector3
# @return [String, Integer, Array<Object>] base id of base and batches
def serialize(base_and_entity, preferences)
serializer = SpeckleConnector3::Converters::BaseObjectSerializer.new(preferences)
t = Time.now.to_f
id = serializer.serialize(base_and_entity)
batches = serializer.batch_json_objects
write_to_speckle_folder(id, batches)
puts "Generating traversed object elapsed #{(Time.now.to_f - t).round(5)} s"
return id, batches, serializer.object_references
end
@@ -122,26 +125,28 @@ module SpeckleConnector3
# @param speckle_state [States::SpeckleState]
# rubocop:disable Metrics/MethodLength
def from_native_to_speckle(entity, preferences, speckle_state, parent, ignore_cache, &convert)
@object_count += 1
persistent_id = entity.is_a?(SpeckleObjects::Geometry::GroupedMesh) ? entity.faces.first.persistent_id.to_s : entity.persistent_id.to_s
# Where we do send caching!
if !ignore_cache && !entity_has_changed?(entity) &&
speckle_state.object_references_by_project[model_card.project_id] &&
speckle_state.object_references_by_project[model_card.project_id].keys.include?(entity.persistent_id.to_s)
reference = speckle_state.object_references_by_project[model_card.project_id][entity.persistent_id.to_s]
speckle_state.object_references_by_project.keys.include?(model_card.project_id) &&
speckle_state.object_references_by_project[model_card.project_id].keys.include?(persistent_id)
reference = speckle_state.object_references_by_project[model_card.project_id][persistent_id]
add_to_report(entity, reference)
@cached_object_count += 1
return speckle_state, reference
end
if entity.is_a?(SpeckleObjects::Geometry::GroupedMesh)
mesh = SpeckleObjects::Geometry::Mesh.from_faces(speckle_state: speckle_state, faces: entity.faces,
units: @units, model_preferences: preferences[:model])
add_to_report(entity, mesh)
return speckle_state, mesh
end
if entity.is_a?(Sketchup::Edge)
line = SpeckleObjects::Geometry::Line.from_edge(speckle_state: speckle_state, edge: entity,
units: @units, model_preferences: preferences[:model]).to_h
add_to_report(entity, line)
add_to_report(entity, line) unless entity.parent.is_a?(Sketchup::ComponentDefinition)
return speckle_state, line
end
@@ -16,6 +16,7 @@ module SpeckleConnector3
super('selection', 'Selection', nil, summary)
@selected_object_ids = selected_object_ids
self[:selectedObjectIds] = selected_object_ids
self[:isDefault] = true # hard coded default value, that's fair
end
def check_expiry(ids)
@@ -18,6 +18,11 @@ module SpeckleConnector3
# @param sketchup_model [Sketchup::Model] active model.
def self.read_preferences(sketchup_model)
unless File.exist?(SPECKLE_CONFIG_DB_PATH)
File.new(SPECKLE_CONFIG_DB_PATH, "w")
db = Sqlite3::Database.new(SPECKLE_CONFIG_DB_PATH)
create_objects_table(db)
end
db = Sqlite3::Database.new(SPECKLE_CONFIG_DB_PATH)
user_preferences = validate_user_preferences(db)
model_preferences = validate_model_preferences(sketchup_model)
@@ -29,6 +34,52 @@ module SpeckleConnector3
)
end
# this is needed to get last selected account
def self.get_user_selected_account_id
db = Sqlite3::Database.new(SPECKLE_CONFIG_DB_PATH)
row_data = db.exec("SELECT content FROM 'objects' WHERE hash = 'accounts'")
is_config_accounts_exist = !row_data.empty?
return nil unless is_config_accounts_exist
# Select data
row_data = db.exec("SELECT content FROM 'objects' WHERE hash = 'accounts'").first.first
# Parse string to hash
data_hash = JSON.parse(row_data).to_h
# Get current theme value
data_hash['userSelectedAccountId']
end
def self.format_user_selected_accounts_insert(account_id)
"('accounts', '{\"userSelectedAccountId\": \"#{account_id}\"}');"
end
def self.format_user_selected_accounts_update(account_id)
"{\"userSelectedAccountId\": \"#{account_id}\"}"
end
def self.set_user_selected_account_id(account_id)
db = Sqlite3::Database.new(SPECKLE_CONFIG_DB_PATH)
row_data = db.exec("SELECT content FROM 'objects' WHERE hash = 'accounts'")
is_config_accounts_exist = !row_data.empty?
if !is_config_accounts_exist
db.exec("INSERT INTO 'objects' VALUES #{format_user_selected_accounts_insert(account_id)}")
else
db.exec("UPDATE 'objects' SET content = '#{format_user_selected_accounts_update(account_id)}' WHERE hash = 'accounts'")
end
end
# Creates the 'objects' table in the database if it doesn't already exist.
# @param db [Sqlite3::Database] the SQLite3 database instance.
def self.create_objects_table(db)
db.exec <<-SQL
CREATE TABLE IF NOT EXISTS objects (
hash TEXT PRIMARY KEY,
content TEXT
);
SQL
end
# Whether row data is complete with preference or not.
# It is useful for backward compatibility, when we add new preferences it should be reset when user initialize it.
def self.data_complete?(row_data)
@@ -46,11 +46,19 @@ module SpeckleConnector3
instance_id = entity.persistent_id.to_s
definition_id = entity.definition.persistent_id.to_s
instance_dictionaries = SketchupModel::Dictionary::BaseDictionaryHandler
.attribute_dictionaries_to_speckle(entity)
instance_att = instance_dictionaries.any? ? { dictionaries: instance_dictionaries } : {}
instance_proxies[instance_id] = SpeckleObjects::InstanceProxy.new(
definition_id,
entity.name,
entity.definition.name,
entity.layer.display_name,
SpeckleObjects::Other::Transform.from_transformation(entity.transformation, @units).value,
depth,
@units,
sketchup_attributes: instance_att,
application_id: instance_id
)
@@ -70,7 +78,17 @@ module SpeckleConnector3
return
end
definition_proxy = SpeckleObjects::InstanceDefinitionProxy.new(entity.definition, [], depth, application_id: definition_id)
definition_dictionaries = SketchupModel::Dictionary::BaseDictionaryHandler
.attribute_dictionaries_to_speckle(entity.definition)
definition_att = definition_dictionaries.any? ? { dictionaries: definition_dictionaries } : {}
definition_proxy = SpeckleObjects::InstanceDefinitionProxy.new(
entity.definition,
[],
depth,
sketchup_attributes: definition_att,
application_id: definition_id
)
definition_proxy[:name] = entity.definition.name
definition_proxy[:description] = entity.definition.description
@@ -16,7 +16,20 @@ module SpeckleConnector3
].freeze
# @param entity [Sketchup::Entity] entity to get attribute dictionaries
def self.attribute_dictionaries_to_speckle(entity, model_preferences)
def self.attribute_dictionaries_to_speckle(entity)
dictionaries = {}
return dictionaries if entity.attribute_dictionaries.nil?
entity.attribute_dictionaries.each do |att_dict|
dict_name = att_dict == '' ? 'empty_dictionary_name' : att_dict.name
dictionaries[dict_name] = att_dict.to_h unless IGNORED_DICTIONARY_NAMES.include?(att_dict.name)
end
dictionaries
end
# @param entity [Sketchup::Entity] entity to get attribute dictionaries
# @note v2 logic
def self.attribute_dictionaries_to_speckle_by_settings(entity, model_preferences)
dictionaries = {}
return dictionaries unless model_preferences[INCLUDE_ENTITY_ATTRIBUTES]
@@ -72,6 +72,22 @@ module SpeckleConnector3
hash
end
# @param obj [Object] object to write
# @param dict [Sketchup::AttributeDictionary] attribute dictionary to write data.
def self.hash_to_dict(dict_name, obj, dict)
dict_to_write = dict.attribute_dictionary(dict_name, true)
obj.each do |key, value|
# value = obj.instance_variable_get(var)
# var_name = var.to_s[1..-1]
if value.is_a?(Hash) # FIXME or not, depends:-> This doesn't cover arrays that has objects in it.
hash_to_dict(key.to_s, value, dict_to_write)
else
dict_to_write[key] = value
end
end
end
# @return [String] the name of the dictionary to read from
def self.dictionary_name
raise NotImplementedError 'Implement this in subclass'
@@ -13,30 +13,14 @@ module SpeckleConnector3
# @param sketchup_model [Sketchup::Model] sketchup model to save cards into it's attribute dictionary
def self.save_send_card_to_model(send_card, sketchup_model)
send_cards_dict = send_cards_dict(sketchup_model)
serialize_obj_to_dict(send_card.model_card_id, send_card, send_cards_dict)
hash_to_dict(send_card.model_card_id, send_card, send_cards_dict)
end
# @param receive_card [Cards::ReceiveCard] card to save model
# @param sketchup_model [Sketchup::Model] sketchup model to save cards into it's attribute dictionary
def self.save_receive_card_to_model(receive_card, sketchup_model)
receive_cards_dict = receive_cards_dict(sketchup_model)
serialize_obj_to_dict(receive_card.model_card_id, receive_card, receive_cards_dict)
end
# @param obj [Object] object to write
# @param dict [Sketchup::AttributeDictionary] attribute dictionary to write data.
def self.serialize_obj_to_dict(dict_name, obj, dict)
dict_to_write = dict.attribute_dictionary(dict_name, true)
obj.each do |key, value|
# value = obj.instance_variable_get(var)
# var_name = var.to_s[1..-1]
if value.is_a?(Hash) # FIXME or not depends: This doesn't cover arrays that has objects in it.
serialize_obj_to_dict(key.to_s, value, dict_to_write)
else
dict_to_write[key] = value
end
end
hash_to_dict(receive_card.model_card_id, receive_card, receive_cards_dict)
end
def self.remove_card_dict(sketchup_model, data)
@@ -101,7 +85,7 @@ module SpeckleConnector3
dict_to_write = dict_to_write.attribute_dictionary(dict_name, true)
dict_to_write = dict_to_write.attribute_dictionary(var_name, true)
value.each do |key, hash_value|
serialize_obj_to_dict(key.to_s, hash_value, dict_to_write)
hash_to_dict(key.to_s, hash_value, dict_to_write)
end
else
dict_to_write.set_attribute(dict_name, var_name, value)
@@ -12,10 +12,13 @@ module SpeckleConnector3
def self.highlight_entities(sketchup_model, entity_ids)
sketchup_model.selection.clear
# below code causing huge performance bottleneck since iterate nestedly, I was initially considering to cover all cases,
# but not worth to have highlighting sub elements since we already highlight the parent. This can be only an issue when user sends
# only the sub elements
# Flat entities to select entities on card
flat_entities = SketchupModel::Query::Entity.flat_entities(sketchup_model.entities)
# flat_entities = SketchupModel::Query::Entity.flat_entities(sketchup_model.entities)
flat_entities.each do |entity|
sketchup_model.entities.each do |entity|
next unless entity_ids.include?(entity.persistent_id.to_s)
sketchup_model.selection.add(entity.instances) if entity.is_a?(Sketchup::ComponentDefinition)
@@ -0,0 +1,17 @@
# frozen_string_literal: true
require_relative '../base'
require_relative '../../constants/type_constants'
module SpeckleConnector3
module SpeckleObjects
class DataObject < Base
SPECKLE_TYPE = SPECKLE_OBJECT_DATA_OBJECT
def self.to_native(state, data_object, layer, _entities, &convert_to_native)
properties = data_object['properties']
return state
end
end
end
end
@@ -0,0 +1,25 @@
# frozen_string_literal: true
require_relative '../base'
require_relative '../../constants/type_constants'
require_relative '../other/display_value'
require_relative '../../sketchup_model/dictionary/base_dictionary_handler'
module SpeckleConnector3
module SpeckleObjects
class RevitDataObject < Base
SPECKLE_TYPE = SPECKLE_OBJECT_DATA_OBJECT_REVIT
def self.to_native(state, revit_data_object, layer, entities, &convert_to_native)
properties = revit_data_object['properties']
new_state, instance_and_definition = SpeckleObjects::Other::DisplayValue.to_native(state, revit_data_object, layer, entities, &convert_to_native)
instance, _definition = instance_and_definition
attr = instance.attribute_dictionary('Speckle', true)
SketchupModel::Dictionary::BaseDictionaryHandler.hash_to_dict('Revit Parameters', properties, attr) if properties
return new_state, instance_and_definition
end
end
end
end
@@ -18,21 +18,24 @@ module SpeckleConnector3
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)
start_point = Point.to_native(arc['startPoint']['x'], arc['startPoint']['y'], arc['startPoint']['z'], units)
end_point = Point.to_native(arc['endPoint']['x'], arc['endPoint']['y'], arc['endPoint']['z'], units)
normal = Vector.to_native(plane['normal']['x'], plane['normal']['y'], plane['normal']['z'], units).normalize
x_axis = Vector.to_native(plane['xdir']['x'], plane['xdir']['y'], plane['xdir']['z'], units).normalize
radius = Geometry.length_to_native(arc['radius'], units)
start_angle = arc['startAngle']
end_angle = arc['endAngle']
# Normalize angles to range 0 to 2π
start_angle %= 2 * Math::PI
end_angle %= 2 * Math::PI
start_vector = (start_point - origin).normalize
end_vector = (end_point - origin).normalize
# Ensure start angle is less than end angle for proper drawing
if start_angle > end_angle
end_angle += 2 * Math::PI
start_angle = Math.atan2(start_vector.cross(normal).dot(x_axis), start_vector.dot(x_axis))
end_angle = Math.atan2(end_vector.cross(normal).dot(x_axis), end_vector.dot(x_axis))
measure = arc['measure'] # this is in radians!
if measure # for backward compatibilty
end_angle = start_angle + measure
else
end_angle += 2 * Math::PI if end_angle < start_angle
end
edges = entities.add_arc(origin, x_axis, normal, radius, start_angle, end_angle)
edges.each { |edge| edge.layer = layer }
return state, edges
@@ -36,7 +36,7 @@ module SpeckleConnector3
self[:units] = units
self[:layer] = layer unless layer.nil?
self['@SpeckleSchema'] = speckle_schema if speckle_schema.any?
self[:sketchup_attributes] = sketchup_attributes if sketchup_attributes.any?
self[:properties] = sketchup_attributes if sketchup_attributes.any?
end
# rubocop:enable Metrics/ParameterLists
@@ -59,7 +59,7 @@ module SpeckleConnector3
# @param edge [Sketchup::Edge] edge to convert line.
def self.from_edge(speckle_state:, edge:, units:, model_preferences:, global_transformation: nil)
dictionaries = SketchupModel::Dictionary::BaseDictionaryHandler
.attribute_dictionaries_to_speckle(edge, model_preferences)
.attribute_dictionaries_to_speckle_by_settings(edge, model_preferences)
att = dictionaries.any? ? { dictionaries: dictionaries } : {}
speckle_schema = Mapper.to_speckle(speckle_state, edge, units, global_transformation: global_transformation)
start_pt = Geometry::Point.from_vertex(edge.start.position, units)
@@ -141,7 +141,10 @@ module SpeckleConnector3
edges.each do |edge|
edge.layer = layer
# edge.layer = line_layer.nil? ? layer : line_layer
unless line['sketchup_attributes'].nil?
if !line['properties'].nil?
SketchupModel::Dictionary::BaseDictionaryHandler
.attribute_dictionaries_to_native(edge, line['properties']['dictionaries'])
elsif !line['sketchup_attributes'].nil? # backward compatibility
SketchupModel::Dictionary::BaseDictionaryHandler
.attribute_dictionaries_to_native(edge, line['sketchup_attributes']['dictionaries'])
end
@@ -49,7 +49,7 @@ module SpeckleConnector3
# self[:renderMaterial] = render_material
self[:'@(31250)vertices'] = vertices
self[:'@(62500)faces'] = faces
self[:sketchup_attributes] = sketchup_attributes if sketchup_attributes.any?
self[:properties] = sketchup_attributes if sketchup_attributes.any?
self['@SpeckleSchema'] = speckle_schema if speckle_schema.any?
end
# rubocop:enable Metrics/ParameterLists
@@ -129,7 +129,10 @@ module SpeckleConnector3
# Smooth edges if they already soft
# FIXME: Below line should be reconsidered. It might be a good to know here mesh comes from NURBS or not.
face.edges.each { |edge| edge.smooth = true if edge.soft? } if has_any_non_planar_quad_mesh
unless mesh['sketchup_attributes'].nil?
if !mesh['properties'].nil?
SketchupModel::Dictionary::BaseDictionaryHandler
.attribute_dictionaries_to_native(face, mesh['properties']['dictionaries'])
elsif !mesh['sketchup_attributes'].nil? # backward compatibility
SketchupModel::Dictionary::BaseDictionaryHandler
.attribute_dictionaries_to_native(face, mesh['sketchup_attributes']['dictionaries'])
end
@@ -151,7 +154,7 @@ module SpeckleConnector3
# rubocop:disable Metrics/ParameterLists
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)
.attribute_dictionaries_to_speckle_by_settings(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 }
@@ -278,7 +281,9 @@ module SpeckleConnector3
# @param mesh [Object] speckle mesh object
# @param entities [Sketchup::Entities] sketchup entities that mesh will be created in it as face.
def self.get_soften_setting(mesh, entities)
unless mesh['sketchup_attributes'].nil?
if !mesh['properties'].nil?
return mesh['properties']['is_soften'].nil? ? true : mesh['properties']['is_soften']
elsif !mesh['sketchup_attributes'].nil? # backward compatibility
return mesh['sketchup_attributes']['is_soften'].nil? ? true : mesh['sketchup_attributes']['is_soften']
end
@@ -55,7 +55,7 @@ module SpeckleConnector3
geometries.each do |geo|
if geo['speckle_type'] && geo['speckle_type'] == OBJECTS_GEOMETRY_MESH
geo['sketchup_attributes'] = { 'is_soften' => false }
geo['properties'] = { 'is_soften' => false }
end
end
@@ -57,7 +57,7 @@ module SpeckleConnector3
geometries.each do |geo|
if geo['speckle_type'] && geo['speckle_type'] == OBJECTS_GEOMETRY_MESH
geo['sketchup_attributes'] = { 'is_soften' => false }
geo['properties'] = { 'is_soften' => false }
end
end
@@ -20,7 +20,7 @@ module SpeckleConnector3
# @param object_ids [Array<String>]
# @param max_depth [Integer]
# @param application_id [String | NilClass]
def initialize(definition, object_ids, max_depth, application_id: nil)
def initialize(definition, object_ids, max_depth, sketchup_attributes: {}, application_id: nil)
super(
speckle_type: SPECKLE_TYPE,
application_id: application_id,
@@ -31,6 +31,7 @@ module SpeckleConnector3
self[:objects] = object_ids
self[:maxDepth] = max_depth
self[:alwaysFaceCamera] = definition.behavior.always_face_camera?
self[:properties] = sketchup_attributes if sketchup_attributes.any?
end
def add_object_id(object_id)
@@ -8,24 +8,37 @@ module SpeckleConnector3
module SpeckleObjects
class InstanceProxy < Base
SPECKLE_TYPE = SPECKLE_CORE_MODELS_INSTANCES_INSTANCE_PROXY
def initialize(definition_id, transform, max_depth, units, application_id: nil)
def initialize(definition_id, name, definitionName, layerName, transform, max_depth, units, sketchup_attributes: {}, application_id: nil)
super(
speckle_type: SPECKLE_TYPE,
application_id: application_id,
id: nil
)
self[:name] = name if name != ""
self[:definition] = definitionName if definitionName != ""
self[:layer] = layerName if layerName != ""
self[:units] = units
self[:definitionId] = definition_id
self[:maxDepth] = max_depth
self[:transform] = transform
self[:properties] = sketchup_attributes if sketchup_attributes.any?
end
def self.to_native(state, instance_proxy, layer, entities, definition_proxies, &_convert_to_native)
definition_id = instance_proxy['definitionId']
proxy_transform = instance_proxy['transform']
name = instance_proxy['name']
transform = Other::Transform.to_native(proxy_transform, instance_proxy['units'])
definition = definition_proxies[definition_id].definition
instance = entities.add_instance(definition, transform)
instance.name = name if name
unless instance_proxy['properties'].nil?
SketchupModel::Dictionary::BaseDictionaryHandler
.attribute_dictionaries_to_native(instance, instance_proxy['properties']['dictionaries'])
end
instance.layer = layer if layer # TODO: CONVERTER_V2 check
# TODO: CONVERTER_V2 handle groups
return state, [instance, definition]
@@ -32,7 +32,7 @@ module SpeckleConnector3
self[:units] = units
self[:name] = name
self[:always_face_camera] = always_face_camera
self[:sketchup_attributes] = sketchup_attributes if sketchup_attributes.any?
self[:properties] = sketchup_attributes if sketchup_attributes.any?
self[:SpeckleSchema] = speckle_schema if speckle_schema.any?
# '@@' means that it is a detached property.
self['@@geometry'] = geometry
@@ -47,7 +47,7 @@ module SpeckleConnector3
# rubocop:disable Metrics/ParameterLists
def self.from_definition(definition, units, preferences, speckle_state, parent, &convert)
dictionaries = SketchupModel::Dictionary::BaseDictionaryHandler
.attribute_dictionaries_to_speckle(definition, preferences[:model])
.attribute_dictionaries_to_speckle_by_settings(definition, preferences[:model])
att = dictionaries.any? ? { dictionaries: dictionaries } : {}
speckle_schema = SketchupModel::Dictionary::SpeckleSchemaDictionaryHandler
.speckle_schema_to_speckle(definition)
@@ -118,7 +118,7 @@ module SpeckleConnector3
geometry = definition_obj['geometry'] || definition_obj['@geometry'] || definition_obj['displayValue']
always_face_camera = definition_obj['always_face_camera'].nil? ? false : definition_obj['always_face_camera']
sketchup_attributes = definition_obj['sketchup_attributes']
properties = definition_obj['properties'] || definition_obj['sketchup_attributes']
definition&.entities&.clear!
definition ||= sketchup_model.definitions.add(definition_name)
@@ -143,9 +143,9 @@ module SpeckleConnector3
# puts("definition finished: #{name} (#{application_id})")
# puts(" entity count: #{definition.entities.count}")
definition.behavior.always_face_camera = always_face_camera
unless sketchup_attributes.nil?
unless properties.nil?
SketchupModel::Dictionary::BaseDictionaryHandler
.attribute_dictionaries_to_native(definition, sketchup_attributes['dictionaries'])
.attribute_dictionaries_to_native(definition, properties['dictionaries'])
end
return state, [definition]
end
@@ -40,7 +40,7 @@ module SpeckleConnector3
self[:is_sketchup_group] = is_sketchup_group
# self[:renderMaterial] = render_material
self[:transform] = transform
self[:sketchup_attributes] = sketchup_attributes if sketchup_attributes.any?
self[:properties] = sketchup_attributes if sketchup_attributes.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
@@ -53,7 +53,7 @@ module SpeckleConnector3
group.persistent_id.to_s)
speckle_state = new_speckle_state
dictionaries = SketchupModel::Dictionary::BaseDictionaryHandler
.attribute_dictionaries_to_speckle(group, preferences[:model])
.attribute_dictionaries_to_speckle_by_settings(group, preferences[:model])
att = dictionaries.any? ? { dictionaries: dictionaries } : {}
speckle_schema = SketchupModel::Dictionary::SpeckleSchemaDictionaryHandler.speckle_schema_to_speckle(group)
block_instance = BlockInstance.new(
@@ -83,7 +83,7 @@ module SpeckleConnector3
speckle_state = new_speckle_state
dictionaries = SketchupModel::Dictionary::BaseDictionaryHandler
.attribute_dictionaries_to_speckle(component_instance, preferences[:model])
.attribute_dictionaries_to_speckle_by_settings(component_instance, preferences[:model])
att = dictionaries.any? ? { dictionaries: dictionaries } : {}
speckle_schema = SketchupModel::Dictionary::SpeckleSchemaDictionaryHandler
.speckle_schema_to_speckle(component_instance)
@@ -245,10 +245,15 @@ module SpeckleConnector3
end
instance.name = block['name'] unless block['name'].nil?
unless block['sketchup_attributes'].nil?
if !block['properties'].nil?
SketchupModel::Dictionary::BaseDictionaryHandler
.attribute_dictionaries_to_native(instance, block['properties']['dictionaries'])
elsif !block['sketchup_attributes'].nil? # backward compatibility
SketchupModel::Dictionary::BaseDictionaryHandler
.attribute_dictionaries_to_native(instance, block['sketchup_attributes']['dictionaries'])
end
return state, [instance, definition]
end
# rubocop:enable Metrics/AbcSize
@@ -32,7 +32,7 @@ module SpeckleConnector3
self[:emissive] = emissive
self[:metalness] = metalness
self[:roughness] = roughness
self[:sketchup_attributes] = sketchup_attributes
self[:properties] = sketchup_attributes
end
# rubocop:enable Metrics/ParameterLists
@@ -12,6 +12,23 @@ module SpeckleConnector3
module Speckle
module Core
module Models
class Debouncer
def initialize(wait_time)
@wait_time = wait_time
@mutex = Mutex.new
@thread = nil
end
def call(&block)
@mutex.synchronize do
@thread&.kill # Cancel the previous execution
@thread = Thread.new do
sleep @wait_time
block.call
end
end
end
end
# ModelCollection object that collect other speckle objects under it's elements.
class ModelCollection < Collection
DIRECT_SHAPE = SpeckleObjects::BuiltElements::Revit::DirectShape
@@ -61,6 +78,8 @@ module SpeckleConnector3
application_id: sketchup_model.guid
)
last_sent_time = Time.now
count = 0
entities.each do |entity|
layer_collection = LayerCollection.get_or_create_layer_collection(entity.layer, model_collection)
@@ -83,13 +102,10 @@ module SpeckleConnector3
status: progress == 1 ? 'Completed' : 'Converting'
}
}
action = Proc.new do
if Time.now - last_sent_time >= 1
state.instant_message_sender.call("sendBinding.emit('setModelProgress', #{sender_progress_args.to_json})")
last_sent_time = Time.now
end
state.worker.add_job(Job.new(entity.persistent_id.to_s, &action))
state.worker.do_work(Time.now.to_f, &action)
end
return speckle_state, model_collection
@@ -17,6 +17,9 @@ module SpeckleConnector3
# @return [Immutable::Hash{String=>Cards::ReceiveCard}] receive cards.
attr_reader :receive_cards
# @return [Immutable::Hash{String=>Array<UiData::Report::ConversionResult>}] receive cards.
attr_reader :conversion_results
# @return [Immutable::Hash{String=>Immutable::Hash{String=>SpeckleObjects::ObjectReference}}] object references that sent before server.
attr_reader :object_references_by_project
@@ -70,6 +73,7 @@ module SpeckleConnector3
@definitions = Immutable::EmptyHash
@send_cards = Immutable::EmptyHash
@receive_cards = Immutable::EmptyHash
@conversion_results = Immutable::EmptyHash
@relation = Relations::ManyToOneRelation.new
@speckle_mapper_state = SpeckleMapperState.new
end
@@ -218,6 +222,16 @@ module SpeckleConnector3
with(:@object_references_by_project => object_references_by_project.put(project_id, new_project_references))
end
def with_conversion_results(model_card_id, results)
new_conversion_results = conversion_results.put(model_card_id, results)
with(:@conversion_results => new_conversion_results)
end
def without_conversion_results(model_card_id)
new_conversion_results = conversion_results.delete(model_card_id)
with(:@conversion_results => new_conversion_results)
end
def invalid_streams
speckle_entities.collect do |_id, speckle_entity|
speckle_entity.invalid_stream_ids
@@ -1,7 +1,8 @@
# frozen_string_literal: true
require_relative 'binding'
require_relative '../../actions/get_accounts'
require_relative '../../actions/account_actions/get_accounts'
require_relative '../../actions/account_actions/remove_account'
module SpeckleConnector3
module Ui
@@ -11,7 +12,8 @@ module SpeckleConnector3
class AccountsBinding < Binding
def commands
@commands ||= {
getAccounts: Commands::ActionCommand.new(@app, self, Actions::GetAccounts)
getAccounts: Commands::ActionCommand.new(@app, self, Actions::GetAccounts),
removeAccount: Commands::ActionCommand.new(@app, self, Actions::RemoveAccount)
}.freeze
end
end
@@ -11,6 +11,7 @@ require_relative '../../actions/base_actions/add_model'
require_relative '../../actions/base_actions/highlight_model'
require_relative '../../actions/base_actions/highlight_objects'
require_relative '../../actions/base_actions/remove_model'
require_relative '../../actions/base_actions/remove_models'
require_relative '../../actions/base_actions/get_send_filters'
require_relative '../../actions/base_actions/update_send_filter'
require_relative '../../actions/base_actions/get_document_state'
@@ -27,6 +28,7 @@ module SpeckleConnector3
highlightModel: Commands::ActionCommand.new(@app, self, Actions::HighlightModel),
highlightObjects: Commands::ActionCommand.new(@app, self, Actions::HighlightObjects),
removeModel: Commands::ActionCommand.new(@app, self, Actions::RemoveModel),
removeModels: Commands::ActionCommand.new(@app, self, Actions::RemoveModels),
# Since we send exact model card with updateModel, I can use directly AddModel action, it will replace
updateModel: Commands::ActionCommand.new(@app, self, Actions::AddModel),
getSourceApplicationName: Commands::ActionCommand.new(@app, self, Actions::GetSourceAppName),
@@ -4,6 +4,8 @@ require_relative 'binding'
require_relative '../../actions/config_actions/get_is_dev_mode'
require_relative '../../actions/config_actions/get_config'
require_relative '../../actions/config_actions/update_config'
require_relative '../../actions/config_actions/get_user_selected_account_id'
require_relative '../../actions/config_actions/set_user_selected_account_id'
module SpeckleConnector3
module Ui
@@ -15,7 +17,9 @@ module SpeckleConnector3
@commands ||= {
getIsDevMode: Commands::ActionCommand.new(@app, self, Actions::GetIsDevMode),
getConfig: Commands::ActionCommand.new(@app, self, Actions::GetConfig),
updateConfig: Commands::ActionCommand.new(@app, self, Actions::UpdateConfig)
updateConfig: Commands::ActionCommand.new(@app, self, Actions::UpdateConfig),
getUserSelectedAccountId: Commands::ActionCommand.new(@app, self, Actions::GetUserSelectedAccountId),
setUserSelectedAccountId: Commands::ActionCommand.new(@app, self, Actions::SetUserSelectedAccountId)
}.freeze
end
end
@@ -2,6 +2,7 @@
require_relative 'binding'
require_relative '../../actions/send_actions/send'
require_relative '../../actions/send_actions/after_send_objects'
require_relative '../../actions/base_actions/get_send_filters'
require_relative '../../actions/base_actions/get_send_settings'
require_relative '../../actions/base_actions/update_send_filter'
@@ -17,7 +18,8 @@ module SpeckleConnector3
send: Commands::ActionCommand.new(@app, self, Actions::Send),
getSendFilters: Commands::ActionCommand.new(@app, self, Actions::GetSendFilters),
getSendSettings: Commands::ActionCommand.new(@app, self, Actions::GetSendSettings),
updateSendFilter: Commands::ActionCommand.new(@app, self, Actions::UpdateSendFilter)
updateSendFilter: Commands::ActionCommand.new(@app, self, Actions::UpdateSendFilter),
afterSendObjects: Commands::ActionCommand.new(@app, self, Actions::AfterSendObjects)
}.freeze
end
end