Compare commits

...

350 Commits

Author SHA1 Message Date
oguzhankoral f85bde5dee WIP 2024-02-22 16:19:13 +03:00
oguzhankoral 05e7472051 WIP 2024-02-22 15:02:23 +03:00
oguzhankoral 006691db7e WIP 2024-02-22 15:02:19 +03:00
oguzhankoral a663881368 WIPWIPWIPWIP 2024-02-22 14:52:01 +03:00
oguzhankoral c8cc8576b0 Instant message sender for App 2024-02-22 14:52:01 +03:00
oguzhankoral 31df7e77ba Merge branch 'development' into oguzhan/dui3
# Conflicts:
#	speckle_connector/src/actions/receive_objects.rb
#	speckle_connector/src/commands/speckle_menu_commands.rb
#	speckle_connector/src/ui/legacy_binding.rb
2024-02-22 14:51:17 +03:00
Oğuzhan Koral 67d4862f6b Fix (Mapper): CNX-9027 mapped edges don't send at all (#324)
* Separate native revit object definitions

* Add types for native revit objects

* Pass speckle_state to line conversion

* Remove mapper functions from model collections

* Use dictionary pattern matching for mapping conversions

* Remove unnecessary argument from Mapper.to_speckle
2024-02-21 16:59:40 +03:00
Oğuzhan Koral 6a16327c30 Fix (Cache): CNX-8976 bug on initialization on clear setup (#323)
* Call sketchup functions before mount

* Change default to app.speckle.systems

* Use account id instead uuid to get selected account before
2024-02-20 23:54:15 +03:00
Oğuzhan Koral 060b1b8f41 Fix (Attributes): Fix typos 2024-02-15 16:43:32 +03:00
Oğuzhan Koral da2e228293 Fix (FE2): CNX-8877 bug access error by fe2 model url (#321)
* Disable reload

* Enrich selected account info and fix same user id issue

* Trigger sketchup only saved stream not exists

* Fix activeAccount

* Increase number of branches limit to 100

* Check regex match
2024-02-13 16:36:35 +03:00
Oğuzhan Koral ab7397bf55 Feat (FE2): CNX-8702 fe2 urls (#320)
* Recreate ApolloProvider whenever account switches

- It is a force-push of reload page whenever user switches account. It doesn't hurt

* Fix FE2 urls and streamWrapper flag argument
2024-02-03 02:36:41 +03:00
Oğuzhan Koral f79547f781 Reset UI location to center of SketchUp (#319) 2024-01-31 23:00:46 +03:00
Oğuzhan Koral 2152f1c90e Feat (Mapper): CNX-8309 Family instances (#318)
* Implement New Revit Family option

* Filter family types for 'Family Instance'

* Adjust available mapping methods according to selection

* Set hard coded categories just once and source families when source set/updated

* Implement family instance mapping

* Pass group selection info if only group selected

* Exclude definitions from conversion escape

- Previously we were using definition mappings only for direct shape conversions but now they can live in instances

* Add direct shape option to components back

* Calculate rotation of family instance

* Fix transformation matrix

* Use insertion point for instances

* Set inputs for mapped definition
2024-01-08 18:40:55 +03:00
Oğuzhan Koral 503fb4d246 Feat (GIS): support line element 2023-12-01 01:46:53 +03:00
oguzhankoral 2befefa752 Extract utils for line and polygon element 2023-11-30 15:07:31 +03:00
oguzhankoral 85e64c5076 Add line element support 2023-11-30 00:36:47 +03:00
Oğuzhan Koral 60523dc994 Fix (Collections): Support gis collections and none unit 2023-11-29 16:06:58 +03:00
oguzhankoral 6d780bf350 Rename GisLayerCollection as generic 2023-11-29 16:06:37 +03:00
oguzhankoral eec02a1f84 Support none unit 2023-11-29 15:58:26 +03:00
oguzhankoral ace2fe6fe3 WIP: Convert from 'meters' to 'm' 2023-11-29 13:26:53 +03:00
oguzhankoral 188794af8d Add support for vector layer 2023-11-29 13:26:53 +03:00
Oğuzhan Koral 92a941a944 Fix (Instancing): correct id of definition for speckle entity 2023-11-29 13:25:51 +03:00
oguzhankoral 0e1ddf2b11 Tweak definition speckle entity checks 2023-11-29 13:15:07 +03:00
Oğuzhan Koral b57fa010d1 Fix (Config): Reset configs if configSketchup somehow corrupted 2023-11-28 22:38:56 +03:00
oguzhankoral f816452b78 Reset configs if configSketchup somehow corrupted 2023-11-28 22:36:03 +03:00
Oğuzhan Koral 120083bb31 Feat (Performance): receive performance improvements 2023-11-28 13:54:36 +03:00
oguzhankoral a5bb5c4686 Remove logging 2023-11-28 13:31:19 +03:00
oguzhankoral e5e2729f0a Wrap receive into sketchup operation for performance improvement 2023-11-28 11:57:17 +03:00
oguzhankoral ba8b902f48 Merge coplanar faces at the end of the operation 2023-11-28 11:23:30 +03:00
oguzhankoral 2d67815ae6 Remove unused lines 2023-11-27 23:36:10 +03:00
oguzhankoral ec0c9066d2 Merge coplanar faces remove scoping and check normals first 2023-11-27 21:44:15 +03:00
oguzhankoral f9473f558a Merge branch 'development' into oguzhan/dui3 2023-11-20 10:51:35 +03:00
Oğuzhan Koral 58ae858077 Update dev with changes in main 2023-11-13 19:45:20 +03:00
Oğuzhan Koral 613e7938b3 Fix (Scene): missing views from Revit 2023-11-13 14:35:09 +03:00
oguzhankoral e07ff1a445 Fix missing views from Revit
- Previously it was assuming views arrive in elements of collection
2023-11-13 14:15:32 +03:00
Oğuzhan Koral de7dd34ea2 Feat (FE2): Support fe2 terminology and urls 2023-11-13 12:03:19 +03:00
oguzhankoral 0552f695f9 Update FE2 terms for Mapper Tool 2023-11-10 16:49:51 +03:00
oguzhankoral b8d4f3d946 Parse FE2 urls to add projects via ADD BY ID OR URL 2023-11-10 15:52:06 +03:00
oguzhankoral fa112a70b1 Switch to FE2 as user preferences 2023-11-10 15:13:58 +03:00
oguzhankoral 88078bad4c Zoom selection for highlight 2023-10-11 10:04:01 +03:00
oguzhankoral 1a3d6ec800 Update sqlite3 submodule hash ref 2023-10-09 13:23:24 +03:00
oguzhankoral 9b5fc2cd74 Highlight model for send cards 2023-10-04 10:17:45 +02:00
oguzhankoral 97309ebb88 Merge remote-tracking branch 'origin/development' 2023-09-19 08:31:29 +03:00
oguzhankoral c26398a13f Remove cards from model 2023-09-18 09:36:16 +03:00
oguzhankoral fdb874b616 Add action name to error message for commands 2023-09-15 18:40:52 +03:00
oguzhankoral dfd06544ec First successful receive 2023-09-15 18:40:52 +03:00
oguzhankoral 69c10ed1e7 Send progressbar with Sketchup.status_text
Thanks to library of thomthom
2023-09-15 18:40:52 +03:00
oguzhankoral 00df9800ed Send model card id via sendViaBrowserArgs 2023-09-15 18:40:51 +03:00
oguzhankoral 6494fd6b41 Get source app version via base bindings 2023-09-15 18:40:51 +03:00
oguzhankoral e9cb673f3a Send message from sender card 2023-09-15 18:40:51 +03:00
oguzhankoral 4e5cb64710 Correct send data 2023-09-15 18:40:50 +03:00
oguzhankoral aaa6ff9938 Real send via DUI3 2023-09-15 18:40:50 +03:00
oguzhankoral 099cb6b13b Trigger sendersExpired when objects modified 2023-09-15 18:40:50 +03:00
oguzhankoral 75c4065d27 Use AddModel action for updateModel command 2023-09-15 18:40:49 +03:00
oguzhankoral f3ce5c8993 Place binding classes into folder 2023-09-15 18:40:49 +03:00
oguzhankoral 9760d3f0d5 Enable error catch for command 2023-09-15 18:40:49 +03:00
oguzhankoral dab851f3d4 Update model card 2023-09-15 18:40:49 +03:00
oguzhankoral 81b3d4d6d7 Add type discriminator 2023-09-15 18:40:48 +03:00
oguzhankoral 5b09566c49 Reorganize send bindings 2023-09-15 18:40:48 +03:00
oguzhankoral 70dcc23b25 Split account binding from base 2023-09-15 18:40:48 +03:00
oguzhankoral 4c90b3fb16 Align with Dim's works 2023-09-15 18:40:47 +03:00
oguzhankoral 87931df9b6 WIP: selection bindings - add cards to model 2023-09-15 18:40:47 +03:00
oguzhankoral 5d03229d35 WIP: filters 2023-09-15 18:40:47 +03:00
oguzhankoral fb31d662cc Convert tag colors to hex 2023-09-15 18:40:46 +03:00
oguzhankoral 489ec8701f Get default filters 2023-09-15 18:40:46 +03:00
oguzhankoral e1afe66c7e Get model state and send filter for sketchup 2023-09-15 18:40:46 +03:00
oguzhankoral b920d822ef WIP: connector configs 2023-09-15 18:40:46 +03:00
oguzhankoral 0908763d33 Implement config_binding 2023-09-15 18:40:45 +03:00
oguzhankoral 847ad87b23 Introduce ruby traverse_and_construct 2023-09-15 18:40:45 +03:00
oguzhankoral 90cf165dcf Send-Receive operations test via ruby 2023-09-15 18:40:45 +03:00
oguzhankoral 8b0307bc72 Remove test bridge.js 2023-09-15 18:40:44 +03:00
oguzhankoral a645e2829a Unit test for send operation 2023-09-15 18:40:44 +03:00
oguzhankoral 33d8644dd6 Enable collect preferences 2023-09-15 18:40:44 +03:00
oguzhankoral de713a848c Emit only documentChanged instead of passing data 2023-09-15 18:40:43 +03:00
oguzhankoral e9aa91fe7f Rename views to bindings 2023-09-15 18:40:43 +03:00
oguzhankoral 9661c79bd6 Report errors to UI 2023-09-15 18:40:43 +03:00
oguzhankoral 91fab4dcd4 Resolve triggerEvent 2023-09-15 18:40:43 +03:00
oguzhankoral 29488a2d87 Implement test bindings 2023-09-15 18:40:42 +03:00
oguzhankoral a3f1dd2459 Create random sketchup binding 2023-09-15 18:40:42 +03:00
oguzhankoral ab12145e4d Implement on_document_changed action 2023-09-15 18:40:42 +03:00
oguzhankoral 442ea7e6ab Add command for get document info 2023-09-15 18:40:41 +03:00
oguzhankoral 04f0024734 Remove get_commands action and command 2023-09-15 18:40:41 +03:00
oguzhankoral 831cc60ab2 Apply same dialog-view relationship to legacy UI 2023-09-15 18:40:41 +03:00
oguzhankoral 7fc4c55362 Control views via dialog 2023-09-15 18:40:41 +03:00
oguzhankoral 78e8202d1c Remove unnecssary init from view 2023-09-15 18:40:40 +03:00
oguzhankoral f35e953531 Collect command names from related view for SketchupBridge 2023-09-15 18:40:40 +03:00
oguzhankoral f5796bdec8 Pass view to commands 2023-09-15 18:40:40 +03:00
oguzhankoral 9f87c22424 Send messages to correct view/binding 2023-09-15 18:40:39 +03:00
oguzhankoral 88ba11a836 Solve missing resolve_id arguments for commands and actions 2023-09-15 18:40:39 +03:00
oguzhankoral 53f370d24e Run legacy and dui3 at the same time 2023-09-15 18:40:39 +03:00
oguzhankoral 9e0998f054 Pass resolve id from arguments 2023-09-15 18:40:38 +03:00
oguzhankoral 0dce0cb88c Replace Bridge with inhouse resolve_id solution 2023-09-15 18:40:38 +03:00
oguzhankoral a61097bdcd Pass serialized accounts data as json object 2023-09-15 18:40:38 +03:00
oguzhankoral ec073bd544 Pass correct request id for getAccounts 2023-09-15 18:40:38 +03:00
oguzhankoral 1c23da6fb2 Request id temp hack 2023-09-15 18:40:37 +03:00
oguzhankoral 7e6b993b06 Add get commands 2023-09-15 18:40:37 +03:00
oguzhankoral 792251dfb9 Add bridge sample 2023-09-15 18:40:37 +03:00
oguzhankoral 1c4ebb5380 Check correct dui3 id ui controller 2023-09-15 18:40:36 +03:00
oguzhankoral 4ac76d23ca Add new dialog for dui3 2023-09-15 18:40:24 +03:00
Oğuzhan Koral 556ddc0b6f Feat (deploy): Mac support 🍎 2023-09-11 10:40:08 +03:00
Oğuzhan Koral a0dde690ea Fix intendation 2023-09-08 18:17:59 +03:00
Oğuzhan Koral a76dab5be6 Remove mac suffix from deploy manager 2023-09-08 18:16:15 +03:00
Oğuzhan Koral 2d10bc5bbf Deploy manager for mac 2023-09-08 18:13:15 +03:00
Oğuzhan Koral 4042632e0b Fix (Revit): Support curtain walls from revit 2023-09-08 13:37:07 +03:00
oguzhankoral 7ccf83e1a4 Consider speckle id for revit definition 2023-09-08 13:17:16 +03:00
oguzhankoral 019cd0756f Convert revit walls to native instead with display value 2023-09-08 13:16:50 +03:00
József L. Kiss 0e5f9f80be CI integration of mac build (#301)
* patcher

* patch-version

* fix 1

* fix 2

* patch_version

* revert

* mac installer

* slname

* checkout

* powershell

* SEMVER

* python

* installername

* git checkout

* cd speckle-sharp-ci-tools

* zip

* zip location

* white space

* remove checktou

---------

Co-authored-by: József L. Kiss <>
2023-09-07 17:05:02 +03:00
József L. Kiss fc6767860a Add release version of sqlit3 bundle 2023-08-17 13:05:13 +02:00
oguzhankoral 5b5b4be7b2 Mac AppData folder 2023-08-16 17:22:25 +03:00
oguzhankoral 45351d082e Add sqlite3_27.bundle for mac 2023-08-16 16:30:43 +03:00
Oğuzhan Koral 22ccd07491 Release 2.15 2023-07-25 14:48:22 +03:00
Oğuzhan Koral 2cf9ee647b Fix (Mapper): Add offset parameter to walls 2023-07-25 14:26:21 +03:00
oguzhankoral efb567824b Add offset parameter to walls 2023-07-12 13:01:16 +03:00
Oğuzhan Koral f0aac39486 Chore (Mixpanel): tracking for mapper actions 2023-07-06 10:03:08 +03:00
oguzhankoral f278055805 Correct mappings set and applied 2023-07-03 12:27:23 +03:00
oguzhankoral 6f2e36fd11 Add mixpanel tracking for mapper 2023-07-03 12:03:37 +03:00
Oğuzhan Koral 119d80ffc8 Fix (Mapper): Definition mapping 2023-06-29 22:42:36 +03:00
oguzhankoral 771c3df864 Fix definition mapping 2023-06-29 22:39:31 +03:00
Oğuzhan Koral 7d1963e458 Feat (Mapper): Revit and default wall support 2023-06-26 12:23:52 +03:00
oguzhankoral dde85972b3 Add default wall 2023-06-26 12:20:32 +03:00
oguzhankoral 5e061da910 Correct tooltips according to source state 2023-06-26 11:49:34 +03:00
oguzhankoral 46bea345de RevitWall from baseline 2023-06-26 11:33:09 +03:00
Oğuzhan Koral bc53462ad6 Chore (Mapper): Rename Floor with RevitFloor 2023-06-26 10:47:50 +03:00
oguzhankoral 884df40a1d Rename Floor with RevitFloor 2023-06-26 10:45:40 +03:00
Oğuzhan Koral b23168c067 Fix (Mapper): evaluate mapping source family data 2023-06-26 10:07:48 +03:00
oguzhankoral 5568212f15 Correct type names from source 2023-06-25 20:48:16 +03:00
oguzhankoral 79db79d799 Remove braces from mapper 2023-06-25 20:47:54 +03:00
oguzhankoral 18a4008efd Set selected level name string instead of object 2023-06-25 20:20:17 +03:00
oguzhankoral 83e4abd1ee Update family types when family updated 2023-06-23 18:37:47 +03:00
oguzhankoral 243bcfba72 Make dropdowns functional 2023-06-23 18:33:39 +03:00
Oğuzhan Koral af2c8c560f Feat (Mapper): mapper method by selection and floor creation 2023-06-22 17:27:49 +03:00
oguzhankoral 6a37f3871c Add new types as constants 2023-06-22 17:18:00 +03:00
oguzhankoral 759a388448 Register levels as speckle entity 2023-06-22 17:17:47 +03:00
oguzhankoral 360e89d7ce Separate default floor with native floor 2023-06-22 17:17:23 +03:00
oguzhankoral 64655a3284 Pass speckle state to speckle conversions to detect levels 2023-06-22 17:16:47 +03:00
oguzhankoral c58356bde8 Rename with_mapper_selection_queue with better one 2023-06-22 17:16:06 +03:00
oguzhankoral f74117632d Pass stream id to level object to create it as speckle entity 2023-06-22 17:15:23 +03:00
oguzhankoral 5f2b8b8e2b Parse family type level info from command to action 2023-06-22 17:15:00 +03:00
oguzhankoral f0ce7481fd Register clear mapper source action to commands 2023-06-22 17:14:38 +03:00
oguzhankoral 6e7a5c6140 Apply and clear mapping source by buttons instead of auto-apply 2023-06-22 17:13:52 +03:00
oguzhankoral 079c18ee19 Apply mappings also for family, type and level 2023-06-22 17:13:25 +03:00
oguzhankoral 26ef6a3815 Add clearing mapper source action 2023-06-22 17:12:18 +03:00
oguzhankoral cf6dcefe6c Separate mapper data collection from Sketchup selection 2023-06-22 17:11:41 +03:00
oguzhankoral 35590eb979 Add revit parameter object 2023-06-22 17:11:07 +03:00
oguzhankoral 583a8b8a76 Separate mapper related read functions 2023-06-20 08:18:08 +03:00
Oğuzhan Koral c6e8a664de Feat (Mapper): Fetch mapper source 2023-06-19 15:10:43 +03:00
oguzhankoral 24a5e0a579 Update levels geometrically when we have new commit 2023-06-19 12:57:48 +03:00
oguzhankoral a242c197fb Store mapper source in ruby state 2023-06-16 23:10:50 +03:00
oguzhankoral 08bdd23149 Add state for mapper 2023-06-16 21:57:13 +03:00
oguzhankoral c5b35b2d98 Notify user when selected source has new update 2023-06-16 16:23:27 +03:00
oguzhankoral 5407fecd1f Fetch source branch last commit and pass to ruby 2023-06-15 16:10:10 +03:00
oguzhankoral 12d2821d26 Add mapping source selection 2023-06-15 12:09:39 +03:00
Oğuzhan Koral 2e6d58e6a3 Feat (Mapper): mapping for default floor 2023-06-14 22:20:21 +03:00
oguzhankoral 0f0c0fd5ae Check material nil 2023-06-14 16:50:04 +03:00
oguzhankoral ef9ec1c223 Send floors with global coordinates as flat list 2023-06-14 01:11:37 +03:00
oguzhankoral f4387bae30 Send @SpeckleSchema as detached property 2023-06-13 11:50:35 +03:00
oguzhankoral 49b238a23a Extract mapped elements on selection 2023-06-13 11:49:24 +03:00
oguzhankoral 4b75c01b28 Convert sketchup faces to built elements' floor 2023-06-12 13:36:09 +03:00
Oğuzhan Koral e7f641046b Fix (Send): Do not send hidden geometries in components 2023-06-09 15:26:16 +03:00
oguzhankoral 9aaabe0fab Do not send hidden geometries in components 2023-06-09 15:24:40 +03:00
Oğuzhan Koral b6e4b711bf Feat (Edge): support rhino curve types 2023-06-09 11:19:57 +03:00
oguzhankoral 58fcfd210b Support arc and circle 2023-06-09 11:12:04 +03:00
oguzhankoral 5868b9c234 Support polycurves as displayValues 2023-06-09 09:55:52 +03:00
Oğuzhan Koral 0dc6d9cf9d Fix (DisplayValue): Use name of display value first 2023-06-08 23:42:05 +03:00
oguzhankoral 67f50cf2fd If displayValue has name use it 2023-06-08 23:39:54 +03:00
Oğuzhan Koral 8b26a4d49a Chore (DisplayValue): Better component names for displayValues 2023-06-08 23:15:07 +03:00
oguzhankoral a1d0bb0aa1 Instance name as speckle_type only 2023-06-08 23:08:25 +03:00
oguzhankoral bfe08560b1 Use speckle type instead def 2023-06-08 22:31:28 +03:00
Oğuzhan Koral ac3ac24272 Fix (Scene): Orthogonal view receiving as zoomed in 2023-06-08 14:39:07 +03:00
oguzhankoral 03e7191d0e Remove unnecessary lines on to_native 2023-06-08 14:36:39 +03:00
oguzhankoral b3a42f8723 Extract camera creation fuction to fix rubocop warnings 2023-06-08 14:34:18 +03:00
oguzhankoral 9c4b740300 Send 35mm focal length if camera is orthogonal 2023-06-08 14:27:05 +03:00
oguzhankoral 2a12bdadf2 Set camera height for isometric views 2023-06-08 14:14:34 +03:00
Oğuzhan Koral c90e8ad4d2 Feat (Face): extrudable brep faces 2023-06-08 12:23:21 +03:00
oguzhankoral 4a52c51c86 Rename returning single faces as ngon 2023-06-08 12:19:09 +03:00
oguzhankoral 0efc817ddc Remove remaining orphan edges after clean up 2023-06-07 13:06:16 +03:00
oguzhankoral fee54fc98c Do not smooth and soft single faces 2023-06-07 13:05:58 +03:00
oguzhankoral 210f751396 Return added entities too from conversion 2023-06-07 13:05:35 +03:00
Oğuzhan Koral 2e2bc3fe29 Feat (Layers): support flat layers 2023-06-06 13:35:05 +03:00
oguzhankoral a6f05f86d1 Document layer strategies 2023-06-06 13:33:37 +03:00
oguzhankoral fc144e4848 Convert layers as flat list from Rhino 2023-06-06 11:43:22 +03:00
oguzhankoral cef9531428 Log function to help write texts to local file 2023-06-06 11:42:54 +03:00
oguzhankoral abd4faefbf Move speckle entity creation from speckle object to SpeckleEntity class 2023-06-06 08:17:31 +03:00
Oğuzhan Koral 966f7aaed5 Fix (Collection): fix blender receive 2023-05-29 18:12:02 +03:00
oguzhankoral 51b59fa995 Fix typo on including string 2023-05-29 18:09:48 +03:00
oguzhankoral 0b713736bd Include also detached @elements props to displayValue 2023-05-29 18:06:05 +03:00
oguzhankoral 9e33581c66 Accept also detached @displayValue props 2023-05-29 18:05:29 +03:00
oguzhankoral b97792b596 Check only collection is model or not 2023-05-29 18:04:56 +03:00
Matteo Cominetti c0746f8eff Merge pull request #270 from specklesystems/oguzhan/hash-only-hostname-of-server-url 2023-05-25 18:17:37 +01:00
oguzhankoral a826a9d692 Hash hostname of the serverUrl 2023-05-25 20:09:32 +03:00
Oğuzhan Koral 6d04203d37 Feat (Collections): Eliminate relations for layer info 2023-05-24 15:57:47 +03:00
oguzhankoral 33b2ed8a94 Fix performance penalty 2023-05-24 14:38:27 +03:00
oguzhankoral 4f16da7ad0 Do not extract relations if from revit 2023-05-24 01:16:51 +03:00
oguzhankoral 36f92c7655 Add network object support 2023-05-24 01:00:06 +03:00
oguzhankoral 1d4f5a759e Eliminate relations for model collections 2023-05-23 23:31:02 +03:00
oguzhankoral 28af9bc811 Enable rescue block for to_native 2023-05-23 12:07:48 +03:00
oguzhankoral cf04cd4094 Check view up and direction parallel or not 2023-05-23 11:50:08 +03:00
oguzhankoral 23e9efb28a Pass layer prop through to_native methods 2023-05-23 11:49:51 +03:00
Oğuzhan Koral 57322df29c Fix (Layer): Do not send line_style if none 2023-05-22 13:57:23 +03:00
oguzhankoral fff82d34c6 Do not send line_style if none 2023-05-22 13:56:10 +03:00
Oğuzhan Koral 7211860c21 Chore (Layer): Support line styles for layers 2023-05-22 11:46:52 +03:00
oguzhankoral 9fc69044f8 Support line styles for layers 2023-05-22 11:42:51 +03:00
Oğuzhan Koral 76467c3e81 Fix (Blocks): Eliminate nil block geometries 2023-05-19 19:36:28 +03:00
oguzhankoral 4cfc04e2f3 Eliminate nil block geometries 2023-05-19 19:13:15 +03:00
Oğuzhan Koral 6bfc7771d0 Fix (Face): Merge coplanar doesn't work some cases 2023-05-19 12:26:24 +03:00
oguzhankoral 7055135257 Return nil if layer path nil 2023-05-19 12:20:55 +03:00
Oğuzhan Koral 85312cf20d Fix (Mapper): inconsistency on mapped elements table state 2023-05-16 13:36:27 +03:00
oguzhankoral 4051cae5b0 Clear cached element and category selection when mapped elements updated 2023-05-16 13:27:02 +03:00
oguzhankoral c64bb6dedf Include instances for button reactions
- Clear, Isolate, Hide, Select
2023-05-16 13:25:41 +03:00
Oğuzhan Koral 7bb17ae0db Fix (Collections): Add layer property to objects as full path 2023-05-16 08:39:06 +03:00
oguzhankoral 3244eb9b15 Add layer property to objects as full path
This is for receiving on Rhino
2023-05-16 08:33:42 +03:00
Oğuzhan Koral 6e173847ba Fix (Performance): Smooth only non-planar quad meshes 2023-05-15 13:53:56 +03:00
oguzhankoral 8cbc1f763d Smooth only non-planar quad meshes 2023-05-15 13:40:31 +03:00
Oğuzhan Koral 2d45abeb28 Release 2.14.0
Merging 2.13 hotfixes into dev branch
2023-05-15 13:17:54 +03:00
oguzhankoral 2fd0ad77bc Fix or disable rubocop issues 2023-05-15 13:14:32 +03:00
oguzhankoral 53c1167831 Remove orthogonality checks 2023-05-15 13:04:22 +03:00
oguzhankoral 48d4a1d7bb Add plane_utils to calculate planarity of 4 points for quad meshes 2023-05-15 13:04:19 +03:00
oguzhankoral 4bbbba6e89 Split all quad meshes 2023-05-15 13:03:22 +03:00
oguzhankoral 0a13575325 Disable rubocop for to_native 2023-05-15 13:02:12 +03:00
Oğuzhan Koral d6075209df Fix (Update): Check if branch instance is deleted 2023-05-12 12:53:19 +03:00
oguzhankoral 9d1b39422b Extract entities_updated method 2023-05-12 12:39:37 +03:00
oguzhankoral 38e297d32b Correct condition for is_update_commit 2023-05-12 11:31:23 +03:00
oguzhankoral 459ef3c9f1 Check if branch instance is deleted 2023-05-12 11:21:34 +03:00
Oğuzhan Koral 3bb12487ba Feat (QGIS): Attribute support for qgis commits 2023-05-12 10:13:44 +03:00
oguzhankoral 8b2428c60d Workaround for QGIS geometry objects or arrays 2023-05-10 17:26:47 +03:00
oguzhankoral f9befd9051 Write qgis attributes to components 2023-05-10 12:43:29 +03:00
oguzhankoral 1020a9bd5d Wrap PolygonElement object into component 2023-05-10 12:07:40 +03:00
Oğuzhan Koral 2844c4ea86 Fix (Instance): Disable aligning axes of displayValue components 2023-05-08 16:54:52 +03:00
oguzhankoral 3344188fee Disable aligning axes of displayValue components 2023-05-08 16:44:10 +03:00
Oğuzhan Koral 67138c2f78 Fix (Update): Update behavior for Revit > Sketchup 2023-05-08 13:21:31 +03:00
oguzhankoral f59d19ef21 Check children changed or not for upcoming blocks 2023-05-08 13:13:53 +03:00
Oğuzhan Koral d0fa7e638f Feat (Collections): Model collections 2023-05-08 09:46:44 +03:00
oguzhankoral 63011e466e Change relation speckle types to collections 2023-05-08 09:34:47 +03:00
oguzhankoral 92d1976300 Split collections into helper classes 2023-05-04 20:08:17 +03:00
oguzhankoral a0cdc9fa07 Check sketchup entities for respomding true to layer set, if so set 2023-05-04 12:22:02 +03:00
oguzhankoral 60f0006597 Remove old layer helper methods 2023-05-04 12:06:56 +03:00
oguzhankoral 67a3c62a08 Align instance axes that created from displayValues without transform 2023-05-03 18:23:58 +03:00
oguzhankoral 21d5dc1e0b Remove layer argument passing for all to_native methods 2023-04-27 17:59:39 +01:00
oguzhankoral 0d810f59f9 Place received objects into correct layers 2023-04-27 17:39:15 +01:00
oguzhankoral dba60b700f Layer relations to native layer tree 2023-04-27 17:21:20 +01:00
oguzhankoral ad9a56bd20 Remove unused methods 2023-04-27 16:16:15 +01:00
oguzhankoral 82585e9104 Convert views to native with traversal method 2023-04-27 16:14:20 +01:00
oguzhankoral dfbb241b0b Model collections on send 2023-04-27 14:56:59 +01:00
oguzhankoral f69ea91f45 Add query for layers 2023-04-26 16:44:11 +01:00
oguzhankoral 768d916092 Convert scenes to view3d on class 2023-04-26 16:44:00 +01:00
oguzhankoral c0acecae10 Query methods for direct shapes 2023-04-26 16:43:31 +01:00
oguzhankoral f741d1c7e4 Clean converter from object specific functions 2023-04-26 16:43:03 +01:00
oguzhankoral d25c70f1d1 Do not load bootstrap again when reload triggered 2023-04-26 16:42:06 +01:00
oguzhankoral 6f954467ef Move collections into related namespace 2023-04-26 16:41:37 +01:00
oguzhankoral 867987a5f5 Group meshes also according to layers 2023-04-26 14:39:52 +01:00
oguzhankoral 61e0a6351c Init collection class 2023-04-14 10:09:44 +03:00
oguzhankoral 558264c23b Add documentation to app methods 2023-04-13 13:57:37 +03:00
oguzhankoral cf7aa371af Move view related methods to related class 2023-04-12 20:04:17 +03:00
oguzhankoral ffedaf6a73 Fix bug on views receive 2023-04-12 14:02:50 +03:00
oguzhankoral d9ae272b36 Proof of concept of layer relations
# Conflicts:
#	speckle_connector/src/convertors/to_speckle.rb
#	speckle_connector/src/speckle_objects/geometry/mesh.rb
#	speckle_connector/src/speckle_objects/other/block_definition.rb
#	speckle_connector/src/speckle_objects/other/block_instance.rb
2023-04-12 12:56:59 +03:00
Oğuzhan Koral 3c5d1f5c9e Fix (References): missing namespaces 2023-04-12 11:09:03 +03:00
oguzhankoral b69b8b7585 Fix missing references after couple of implementation 2023-04-12 10:44:15 +03:00
Oğuzhan Koral 8c7e498fb2 Fix (Security): Bump sqlite3 from 5.0.8 to 5.1.5 in /ui 2023-04-10 14:42:56 +03:00
dependabot[bot] 359413a296 Bump sqlite3 from 5.0.8 to 5.1.5 in /ui
Bumps [sqlite3](https://github.com/TryGhost/node-sqlite3) from 5.0.8 to 5.1.5.
- [Release notes](https://github.com/TryGhost/node-sqlite3/releases)
- [Commits](https://github.com/TryGhost/node-sqlite3/compare/v5.0.8...v5.1.5)

---
updated-dependencies:
- dependency-name: sqlite3
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-04-10 11:19:39 +00:00
Oğuzhan Koral cef7d894c4 Fix (Security): Bump git from 1.12.0 to 1.18.0 2023-04-10 14:15:16 +03:00
dependabot[bot] 7d9cc1aacc Bump git from 1.12.0 to 1.18.0
Bumps [git](https://github.com/ruby-git/ruby-git) from 1.12.0 to 1.18.0.
- [Release notes](https://github.com/ruby-git/ruby-git/releases)
- [Changelog](https://github.com/ruby-git/ruby-git/blob/master/CHANGELOG.md)
- [Commits](https://github.com/ruby-git/ruby-git/compare/v1.12.0...v1.18.0)

---
updated-dependencies:
- dependency-name: git
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-04-10 11:12:22 +00:00
Oğuzhan Koral a6780a756b Feat (Mapper): Mapper tool for direct shapes 2023-04-10 14:05:44 +03:00
Oğuzhan Koral 4e37d17b42 Feat (Mapper): Mapped elements table and it's buttons 2023-04-10 13:48:19 +03:00
oguzhankoral 793923348f Switch button for isolate/show-all accoding to state 2023-04-10 13:37:04 +03:00
oguzhankoral 700db1788d Improve performance dramatically of isolate 2023-04-08 00:02:52 +03:00
oguzhankoral 68a5a44702 Make functional buttons for mapped elements 2023-04-07 20:16:00 +03:00
oguzhankoral 464891f5a1 Manage state of selected elements and existing elements 2023-04-07 11:33:05 +03:00
oguzhankoral d2e5db2680 Custom data table header for child tables 2023-04-06 22:59:46 +03:00
oguzhankoral a9c41d0545 Connect data relationship between parent and childeren data tables 2023-04-05 17:19:21 +03:00
oguzhankoral 0bc458d307 Connect nested data tables with their v-model 2023-04-05 13:54:05 +03:00
oguzhankoral 36c7cc285e Update vuetifyjs to 2.6.10 2023-04-05 13:52:56 +03:00
oguzhankoral f9fbd31a0f Wrap data table with container 2023-04-03 16:43:19 +03:00
oguzhankoral 8789c1f855 Extract mapped elements from mapper component 2023-04-03 15:41:04 +03:00
oguzhankoral f65073480a Apply mixed mapping name 2023-04-03 15:04:20 +03:00
oguzhankoral 157ed831a7 Shrink v-cards for map selection between component-definition 2023-03-31 23:19:19 +03:00
oguzhankoral 0799a59a15 Get info from definition about number of instances 2023-03-31 23:18:23 +03:00
Oğuzhan Koral 60ea3e83e1 Fix (DirectShape): Nested objects material 2023-03-31 19:57:46 +03:00
oguzhankoral 4b874deb50 Don't add mapped entities to layer groups 2023-03-31 19:55:12 +03:00
oguzhankoral 6726b9ad50 Fix nested material issıe 2023-03-31 19:54:29 +03:00
Oğuzhan Koral 75e6fe609e Fix (Mapper): Direct shape objects on viewer 2023-03-31 15:28:05 +03:00
oguzhankoral b40d1ccf7d Send directShapes collection as detached 2023-03-31 15:26:13 +03:00
Oğuzhan Koral 4f7ba23904 Feat (Mapper): Enable multiple mapping apply and clear 2023-03-31 14:33:41 +03:00
oguzhankoral 49084706f2 Enable multiple mapping apply and clear 2023-03-31 14:31:49 +03:00
Oğuzhan Koral 1852e5f6bf Chore (Mapper): Show default values for selected entity 2023-03-30 20:33:59 +03:00
oguzhankoral be0ed5428a Apply default values from selected entity 2023-03-30 20:31:16 +03:00
oguzhankoral f428efde6a Mark mapped cards and make active one 2023-03-30 19:56:49 +03:00
oguzhankoral e79f04f33e Remove unnecessary statement 2023-03-30 15:59:33 +03:00
oguzhankoral 04db8c281f Remove selected rows which was unneccessary 2023-03-30 15:59:03 +03:00
oguzhankoral 2681698186 Disable definition option for groups
- This is uncessary since each group has it's own unique definition on sketchup
2023-03-30 15:49:04 +03:00
Oğuzhan Koral 1682c66da6 Feat (Mapper): Read mapped elements on document load 2023-03-29 23:20:29 +03:00
oguzhankoral 38bc1032d8 Read mapped entities on document load model 2023-03-29 23:18:05 +03:00
Oğuzhan Koral ba37eef9ca Feat (Mapper): Group meshes also for base geometries of direct shapes 2023-03-29 22:49:30 +03:00
oguzhankoral 3db179882a Group direct shape meshes by material 2023-03-29 22:45:45 +03:00
oguzhankoral ba8f25a807 Move mesh related methods from definition 2023-03-29 22:44:06 +03:00
oguzhankoral eac3d3089b Find entities on active path 2023-03-29 22:43:13 +03:00
Oğuzhan Koral 0454a9e147 Fix (Mapper): Group global transformations for direct shapes 2023-03-29 21:03:13 +03:00
oguzhankoral f390cd1c68 Fix/disable rubocop issues 2023-03-29 21:02:49 +03:00
oguzhankoral aaa1ba5aa9 Apply parent's material to direct shape faces 2023-03-29 20:58:57 +03:00
oguzhankoral fb9556abd9 Fix sub elements transform 2023-03-29 20:58:35 +03:00
Oğuzhan Koral 3cfb3b1f84 Feat (Mapper): Show mapped elements on table 2023-03-29 14:54:21 +03:00
oguzhankoral b071bab137 Collect mapped entities when mapper mounted 2023-03-29 14:49:48 +03:00
oguzhankoral 5dbc68ea76 State management for mapped elements 2023-03-29 14:45:09 +03:00
oguzhankoral e76fbc3b77 Notify user after apply or clear mapping 2023-03-29 13:12:59 +03:00
oguzhankoral 09ca0514d1 Remove mapping word from buttons 2023-03-29 12:57:12 +03:00
oguzhankoral faec32a5bb Remove attribute dictionary completely if mappings cleared 2023-03-29 12:35:56 +03:00
oguzhankoral 1f5793ab79 Nil check for reading objects from scratch 2023-03-29 11:50:03 +03:00
oguzhankoral df22bd1cec Fallback to definition schema of instance 2023-03-29 11:47:21 +03:00
oguzhankoral 61dba4e78d Return false if entities are missing for base_and_entities 2023-03-29 11:44:58 +03:00
Oğuzhan Koral bb678117f8 Feat (Mapper): UI communication with Sketchup 2023-03-28 21:36:12 +03:00
oguzhankoral 2dc08e71b7 Collect also instances that definitions' mapped 2023-03-28 21:02:21 +03:00
oguzhankoral df2f844e74 Styles for entity selection to map 2023-03-28 20:11:52 +03:00
oguzhankoral 621c602fc0 Make narrower scrool bar 2023-03-28 20:11:15 +03:00
oguzhankoral f809169757 Fetch definition schema from selection 2023-03-28 20:10:59 +03:00
oguzhankoral 848b135612 Clear mappings 2023-03-28 20:10:26 +03:00
oguzhankoral db6af66705 Fill inputs according to selection 2023-03-28 02:34:55 +03:00
oguzhankoral 728e1f5a86 Send categories as key-value pair objects 2023-03-28 02:34:38 +03:00
oguzhankoral d02d95bc9e Apply mapping command and action 2023-03-28 02:34:13 +03:00
oguzhankoral c1180c5373 Trigger sketchup action to apply mappings 2023-03-28 01:49:17 +03:00
oguzhankoral 4e01fb64e6 Track objects from selection table and prepare mapping 2023-03-28 01:46:21 +03:00
oguzhankoral d0fcb1da34 Add theme colors for mapper active entity cards 2023-03-28 01:45:44 +03:00
oguzhankoral 48352d06b3 Extend selected entity data from sketchup 2023-03-28 01:45:18 +03:00
oguzhankoral d995652569 Get info from last selected entity 2023-03-27 18:57:42 +03:00
oguzhankoral 5a958fa51c Split class names with space 2023-03-27 18:57:13 +03:00
oguzhankoral cfb9e2cacd Print mapped count to selection table 2023-03-27 18:12:08 +03:00
oguzhankoral 7932fc1cab Send entity persistent_id to UI 2023-03-27 18:11:40 +03:00
oguzhankoral e0fc1715b5 Create data table for selection 2023-03-27 14:54:19 +03:00
oguzhankoral 1cfd6caa64 Read object schemas from selection with their type 2023-03-27 14:54:01 +03:00
oguzhankoral 54bf18888d Helper method definition to group objects by property value 2023-03-27 14:53:23 +03:00
Oğuzhan Koral 6b60fc4259 Feat (Observers): Selection observers to collect data 2023-03-24 19:37:20 +03:00
oguzhankoral 216af8697c Create accordion for mapper 2023-03-24 17:33:42 +03:00
oguzhankoral d97e7314d0 Add categories to fake data 2023-03-24 17:33:11 +03:00
oguzhankoral 67d9dda143 Sample interactions 2023-03-24 13:06:55 +03:00
oguzhankoral 5c60e303cb Move mapped_with_schema method to reader 2023-03-24 12:36:45 +03:00
oguzhankoral e36b8f3a56 Create selection observer to trigger UI 2023-03-24 12:36:21 +03:00
Oğuzhan Koral 1e7a19b463 Chore (UI): UI components for mapping tool 2023-03-24 12:30:55 +03:00
oguzhankoral 8004249a29 Init mapper with tab 2023-03-23 16:08:36 +03:00
Oğuzhan Koral 6cd800e4ef Feat (Mapping): Send direct shape PoC 2023-03-23 12:54:42 +03:00
oguzhankoral e182bc7ed2 Clean unused methods 2023-03-22 21:38:23 +03:00
oguzhankoral c338d51c9d Skip faces into definitions if it is mapped 2023-03-22 21:19:11 +03:00
oguzhankoral c1912250df Do definition check in advance and that's why definitions argument removed 2023-03-22 21:18:50 +03:00
oguzhankoral 994c41980e Init definitions and render_materials for later caching 2023-03-22 21:18:03 +03:00
oguzhankoral 385b7a514d Transform mesh if global_transformation defined 2023-03-22 21:17:25 +03:00
oguzhankoral 3aaade9228 Entity queries for parental relationships 2023-03-22 21:16:58 +03:00
oguzhankoral b4dd19b711 Split direct shape conversion from generic conversion 2023-03-22 21:06:53 +03:00
oguzhankoral 9e9b83b4ba Init direct shape definition 2023-03-22 21:06:14 +03:00
oguzhankoral 5ff5114669 Add revit categories dictionary 2023-03-21 19:55:44 +03:00
oguzhankoral f63039f3fb Change module name with revit specific 2023-03-21 19:53:47 +03:00
oguzhankoral b39399463d Add speckle schema to objects for to speckle 2023-03-21 14:17:36 +03:00
oguzhankoral 8217ef7fbb Create speckle schema dictionary handler 2023-03-21 14:17:18 +03:00
oguzhankoral b4851c34e1 Separate base dictionary_handler from root 2023-03-21 14:16:52 +03:00
334 changed files with 24659 additions and 927 deletions
+116 -2
View File
@@ -76,6 +76,99 @@ jobs:
paths:
- speckle-sharp-ci-tools/Installers
build-connector-mac:
macos:
xcode: 12.5.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
@@ -99,6 +192,7 @@ jobs:
root: ./
paths:
- speckle-sharp-ci-tools
deploy-manager2:
docker:
- image: mcr.microsoft.com/dotnet/sdk:6.0
@@ -146,17 +240,37 @@ workflows:
only: /.*/
context: innosetup
- build-connector-mac:
slug: sketchup
requires:
- get-ci-tools
- build-ui
filters:
tags:
only: /.*/
installername: SpeckleSketchUpInstall
- deploy-manager2:
context: do-spaces-speckle-releases
slug: sketchup
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\/.*/
+3 -4
View File
@@ -1,7 +1,7 @@
GEM
remote: https://rubygems.org/
specs:
addressable (2.8.1)
addressable (2.8.4)
public_suffix (>= 2.0.2, < 6.0)
ast (2.4.2)
axiom-types (0.1.1)
@@ -26,7 +26,7 @@ GEM
path_expander (~> 1.0)
ruby_parser (~> 3.1, > 3.1.0)
sexp_processor (~> 4.8)
git (1.12.0)
git (1.18.0)
addressable (~> 2.8)
rchardet (~> 1.8)
ice_nine (0.11.2)
@@ -48,8 +48,7 @@ GEM
pry (0.14.1)
coderay (~> 1.1)
method_source (~> 1.0)
psych (3.3.4)
public_suffix (5.0.0)
public_suffix (5.0.1)
rainbow (3.1.1)
rake (13.0.6)
rchardet (1.8.0)
+1
View File
@@ -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'
+3 -1
View File
@@ -15,7 +15,9 @@ module SpeckleConnector
def self.reload
load(__FILE__)
pattern = File.join(__dir__, '**/*.rb')
Dir.glob(pattern).each { |file| load(file) }
# TODO: Here is a opportunity to improve reloading process.
# We can cache last edited time of the each file later to check which file need to be reloaded.
Dir.glob(pattern).each { |file| load(file) unless file.include?('bootstrap') }
.size
end
# rubocop:enable SketchupSuggestions/FileEncoding
Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

@@ -7,6 +7,7 @@ require_relative '../constants/path_constants'
module SpeckleConnector
# Accounts to communicate with models on user's account.
module Accounts
# Load accounts from user's app data.
def self.load_accounts
db_path = SPECKLE_ACCOUNTS_DB_PATH
unless File.exist?(db_path)
@@ -23,9 +24,21 @@ module SpeckleConnector
rows.map { |row| JSON.parse(row[1]) }
end
def self.get_account_by_id(id)
accounts = load_accounts
accounts.select { |acc| acc['id'] == id }[0]
end
# Default account on the user computer.
def self.default_account
accounts = load_accounts
accounts.select { |acc| acc['isDefault'] }[0] || accounts[0]
end
# Try to get local server account for debug/test purposes.
def self.try_get_local_server_account
accounts = load_accounts
accounts.select { |acc| acc['serverInfo']['url'].include?('localhost') }[0] || nil
end
end
end
@@ -15,7 +15,7 @@ module SpeckleConnector
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
# @return [States::State] the new updated state object
def update_state(state)
state = DeactivateDiffing.update_state(state, {})
state = DeactivateDiffing.update_state(state, nil, {})
puts "Diffing activated for #{@stream_id}"
speckle_entities = state.speckle_state.speckle_entities
invalid_speckle_entities = speckle_entities.select do |_id, entity|
@@ -0,0 +1,73 @@
# frozen_string_literal: true
require_relative 'action'
require_relative 'mapped_entities_updated'
require_relative 'events/selection_event_action'
require_relative '../sketchup_model/dictionary/speckle_schema_dictionary_handler'
module SpeckleConnector
module Actions
# Apply mappings for selected entities.
class ApplyMappings < Action
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
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
# @return [States::State] the new updated state object
# rubocop:disable Metrics/AbcSize
# rubocop:disable Metrics/CyclomaticComplexity
# rubocop:disable Metrics/PerceivedComplexity
# rubocop:disable Metrics/MethodLength
def update_state(state)
sketchup_model = state.sketchup_state.sketchup_model
entities = if sketchup_model.active_path.nil?
sketchup_model.entities
else
sketchup_model.active_path.last.definition.entities
end
# Collect entities from entity ids that comes from UI as list
entities_to_map = entities.select { |e| @entities_to_map.include?(e.persistent_id) }
# Switch to definitions if all entities are component instance and UI flag shows that
if entities_to_map.all? { |e| e.is_a?(Sketchup::ComponentInstance) } && @is_definition
entities_to_map = entities_to_map.collect(&:definition).uniq
end
# Store speckle state to update with mapped entities.
speckle_state = state.speckle_state
entities_to_map.each do |entity|
name = if @name == '<Mixed>'
entity.respond_to?(:name) ? entity.name : ''
else
@name
end
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
new_state = MappedEntitiesUpdated.update_state(state.with_speckle_state(speckle_state))
Events::SelectionEventAction.update_state(new_state, { apply: true })
end
# rubocop:enable Metrics/AbcSize
# rubocop:enable Metrics/CyclomaticComplexity
# rubocop:enable Metrics/PerceivedComplexity
# rubocop:enable Metrics/MethodLength
end
end
end
@@ -0,0 +1,47 @@
# 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 SpeckleConnector
module Actions
# Action to add send card.
class AddModel < 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)
if data['typeDiscriminator'] == 'ReceiverModelCard'
receive_card = Cards::ReceiveCard.new(data['id'], data['accountId'],
data['projectId'], data['projectName'],
data['modelId'], data['modelName'],
data['referencedObject'])
SketchupModel::Dictionary::ModelCardDictionaryHandler
.save_card_to_model(receive_card, state.sketchup_state.sketchup_model)
new_speckle_state = state.speckle_state.with_receive_card(receive_card)
state = state.with_speckle_state(new_speckle_state)
js_script = "baseBinding.receiveResponse('#{resolve_id}')"
return state.with_add_queue_js_command('addSendCard', js_script)
end
send_filter = Filters::SendFilters.get_filter_from_ui_data(data['sendFilter'])
# Init card and add to the state
send_card = Cards::SendCard.new(data['id'], data['accountId'], data['projectId'], data['modelId'],
send_filter, {})
SketchupModel::Dictionary::ModelCardDictionaryHandler
.save_card_to_model(send_card, state.sketchup_state.sketchup_model)
new_speckle_state = state.speckle_state.with_send_card(send_card)
state = state.with_speckle_state(new_speckle_state)
# Resolve promise
js_script = "baseBinding.receiveResponse('#{resolve_id}')"
state.with_add_queue_js_command('addSendCard', js_script)
end
end
end
end
@@ -0,0 +1,30 @@
# frozen_string_literal: true
require_relative '../action'
require_relative '../../cards/send_card'
require_relative '../../filters/send_filters'
require_relative '../../sketchup_model/dictionary/model_card_dictionary_handler'
module SpeckleConnector
module Actions
# Add model to document state.
class AddModelToDocumentState < 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)
puts model.to_json
send_filter = Filters::SendFilters.get_filter_from_ui_data(model['sendFilter'])
send_card = Cards::SendCard.new(model['id'], model['accountId'], model['projectId'], model['modelId'], send_filter, {})
SketchupModel::Dictionary::ModelCardDictionaryHandler
.save_card_to_model(send_card, state.sketchup_state.sketchup_model)
new_speckle_state = state.speckle_state.with_send_card(send_card)
state = state.with_speckle_state(new_speckle_state)
js_script = "baseBinding.receiveResponse('#{resolve_id}')"
state.with_add_queue_js_command('addModelToDocumentState', js_script)
end
end
end
end
@@ -0,0 +1,40 @@
# frozen_string_literal: true
require_relative '../action'
require_relative '../../filters/send_filters'
require_relative '../../sketchup_model/dictionary/model_card_dictionary_handler'
module SpeckleConnector
module Actions
# Gets document state.
class GetDocumentState < 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)
send_cards_hash = SketchupModel::Dictionary::ModelCardDictionaryHandler
.get_cards_from_dict(state.sketchup_state.sketchup_model)
send_cards = send_cards_hash.collect do |id, card|
filter = Filters::SendFilters.get_filter_from_document(card['sendFilter'])
send_card = Cards::SendCard.new(id, card['account_id'], card['project_id'], card['model_id'], filter, {})
new_speckle_state = state.speckle_state.with_send_card(send_card)
state = state.with_speckle_state(new_speckle_state)
{
id: send_card.id,
accountId: send_card.account_id,
projectId: send_card.project_id,
modelId: send_card.model_id,
sendFilter: send_card.send_filter,
typeDiscriminator: send_card.type_discriminator
}
end
model_state = { models: send_cards }
js_script = "baseBinding.receiveResponse('#{resolve_id}', #{model_state.to_json})"
state.with_add_queue_js_command('getDocumentState', js_script)
end
end
end
end
@@ -0,0 +1,38 @@
# frozen_string_literal: true
require_relative '../action'
require_relative '../../filters/send_filters'
require_relative '../../sketchup_model/dictionary/model_card_dictionary_handler'
module SpeckleConnector
module Actions
# Gets model state.
class GetModelState < 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)
send_cards_hash = SketchupModel::Dictionary::ModelCardDictionaryHandler
.get_cards_from_dict(state.sketchup_state.sketchup_model)
send_cards = send_cards_hash.collect do |id, card|
filters = Filters::SendFilters.get_filters_from_model(card['filters'])
send_card = Cards::SendCard.new(id, card['account_id'], card['project_id'], card['model_id'], filters)
new_speckle_state = state.speckle_state.with_send_card(send_card)
state = state.with_speckle_state(new_speckle_state)
{
accountId: send_card.account_id,
projectId: send_card.project_id,
modelId: send_card.model_id,
filters: send_card.filters
}
end
model_state = { sendCards: send_cards }
js_script = "baseBinding.receiveResponse('#{resolve_id}', #{model_state.to_json})"
state.with_add_queue_js_command('getModelState', js_script)
end
end
end
end
@@ -0,0 +1,19 @@
# frozen_string_literal: true
require_relative '../action'
require_relative '../../filters/send_filters'
module SpeckleConnector
module Actions
# Action to get send filter.
class GetSendFilters < 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)
default_filters = Filters::SendFilters.get_default(state.sketchup_state.sketchup_model)
js_script = "sendBinding.receiveResponse('#{resolve_id}', #{default_filters.to_json})"
state.with_add_queue_js_command('getSendFilter', js_script)
end
end
end
end
@@ -0,0 +1,17 @@
# frozen_string_literal: true
require_relative '../action'
module SpeckleConnector
module Actions
# Get source app name.
class GetSourceAppName < 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)
js_command = "baseBinding.receiveResponse('#{resolve_id}', 'Sketchup')"
state.with_add_queue_js_command('getSourceAppName', js_command)
end
end
end
end
@@ -0,0 +1,17 @@
# frozen_string_literal: true
require_relative '../action'
module SpeckleConnector
module Actions
# Get source app version.
class GetSourceAppVersion < 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)
js_command = "baseBinding.receiveResponse('#{resolve_id}', #{SKETCHUP_VERSION})"
state.with_add_queue_js_command('getSourceAppVersion', js_command)
end
end
end
end
@@ -0,0 +1,45 @@
# frozen_string_literal: true
require_relative '../action'
require_relative '../../sketchup_model/query/entity'
module SpeckleConnector
module Actions
# Action to add send card.
class HighlightModel < 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)
# objects_to_highlight = if data['typeDiscriminator'] == 'ReceiverModelCard'
# # model_card = state.speckle_state.receive_cards[model_card_id]
# # TODO: return received objects
# []
# else
# model_card = state.speckle_state.send_cards[model_card_id]
# model_card.send_filter.selected_object_ids
# end
objects_to_highlight = state.speckle_state.send_cards[model_card_id].send_filter.selected_object_ids
state.sketchup_state.sketchup_model.selection.clear
# Flat entities to select entities on card
flat_entities = SketchupModel::Query::Entity.flat_entities(state.sketchup_state.sketchup_model.entities)
flat_entities.each do |entity|
next unless objects_to_highlight.include?(entity.persistent_id)
if entity.is_a?(Sketchup::ComponentDefinition)
state.sketchup_state.sketchup_model.selection.add(entity.instances)
end
state.sketchup_state.sketchup_model.selection.add(entity)
end
state.sketchup_state.sketchup_model.active_view.zoom(state.sketchup_state.sketchup_model.selection)
# Resolve promise
js_script = "baseBinding.receiveResponse('#{resolve_id}')"
state.with_add_queue_js_command('highlightModel', js_script)
end
end
end
end
@@ -0,0 +1,31 @@
# 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 SpeckleConnector
module Actions
# Action to remove send card.
class RemoveModel < 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)
SketchupModel::Dictionary::ModelCardDictionaryHandler.remove_card_dict(state.sketchup_state.sketchup_model, data)
new_speckle_state = if data['typeDiscriminator'] == 'ReceiverModelCard'
state.speckle_state.without_receive_card(data['id'])
else
state.speckle_state.without_send_card(data['id'])
end
state = state.with_speckle_state(new_speckle_state)
# Resolve promise
js_script = "baseBinding.receiveResponse('#{resolve_id}')"
state.with_add_queue_js_command('removeModel', js_script)
end
end
end
end
@@ -0,0 +1,20 @@
# frozen_string_literal: true
require_relative '../action'
require_relative '../../sketchup_model/dictionary/model_card_dictionary_handler'
module SpeckleConnector
module Actions
# Action to update send filter.
class UpdateSendFilter < 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, value)
SketchupModel::Dictionary::ModelCardDictionaryHandler.update_filter(state.sketchup_state.sketchup_model, data, value)
js_script = "sendBinding.receiveResponse('#{resolve_id}')"
state.with_add_queue_js_command('updateSendFilter', js_script)
end
end
end
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, _resolve_id, _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
@@ -0,0 +1,52 @@
# frozen_string_literal: true
require_relative 'action'
require_relative 'mapped_entities_updated'
require_relative 'events/selection_event_action'
require_relative '../sketchup_model/dictionary/speckle_schema_dictionary_handler'
module SpeckleConnector
module Actions
# Clear mappings for selected entities.
class ClearMappings < Action
def initialize(entities_to_map, is_definition)
super()
@entities_to_map = entities_to_map
@is_definition = is_definition
end
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
# @return [States::State] the new updated state object
# rubocop:disable Metrics/CyclomaticComplexity
# rubocop:disable Metrics/PerceivedComplexity
def update_state(state)
sketchup_model = state.sketchup_state.sketchup_model
entities = if sketchup_model.active_path.nil?
sketchup_model.entities
else
sketchup_model.active_path.last.definition.entities
end
# Collect entities from entity ids that comes from UI as list
entities_to_map = entities.select { |e| @entities_to_map.include?(e.persistent_id) }
# Switch to definitions if all entities are component instance and UI flag shows that
if entities_to_map.all? { |e| e.is_a?(Sketchup::ComponentInstance) } && @is_definition
entities_to_map = entities_to_map.collect(&:definition).uniq
end
# Store speckle state to update with mapped entities.
speckle_state = state.speckle_state
entities_to_map.each do |entity|
SketchupModel::Dictionary::SpeckleSchemaDictionaryHandler.remove_dictionary(entity)
speckle_state = speckle_state.with_removed_mapped_entity(entity)
end
new_state = MappedEntitiesUpdated.update_state(state.with_speckle_state(speckle_state))
Events::SelectionEventAction.update_state(new_state, { clear: true })
end
# rubocop:enable Metrics/CyclomaticComplexity
# rubocop:enable Metrics/PerceivedComplexity
end
end
end
@@ -0,0 +1,34 @@
# frozen_string_literal: true
require_relative 'action'
require_relative 'mapped_entities_updated'
require_relative 'events/selection_event_action'
require_relative '../sketchup_model/dictionary/speckle_schema_dictionary_handler'
module SpeckleConnector
module Actions
# Clear mappings for selected entities from mapped elements table.
class ClearMappingsFromTable < 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)
# Flat entities to clear mappings
flat_entities = SketchupModel::Query::Entity.flat_entities(state.sketchup_state.sketchup_model.entities)
# Collect entity ids to clear mappings
entity_ids = data.collect { |_, entities| entities['selectedElements'].collect { |e| e['entityId'] } }.flatten
# Store speckle state to update with mapped entities.
speckle_state = state.speckle_state
flat_entities.each do |entity|
next unless entity_ids.include?(entity.persistent_id)
SketchupModel::Dictionary::SpeckleSchemaDictionaryHandler.remove_dictionary(entity)
speckle_state = speckle_state.with_removed_mapped_entity(entity)
end
new_state = MappedEntitiesUpdated.update_state(state.with_speckle_state(speckle_state))
Events::SelectionEventAction.update_state(new_state, { clear: true })
end
end
end
end
@@ -10,7 +10,7 @@ module SpeckleConnector
class CollectPreferences < 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)
def self.update_state(state, _resolve_id, _data)
state.with_add_queue('collectPreferences', state.user_state.preferences.to_json, [])
end
end
@@ -8,7 +8,7 @@ module SpeckleConnector
class CollectVersions < 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)
def self.update_state(state, _resolve_id, _data)
versions = {
sketchup: Sketchup.version.to_i,
speckle: SpeckleConnector::CONNECTOR_VERSION
@@ -0,0 +1,22 @@
# frozen_string_literal: true
require_relative '../action'
module SpeckleConnector
module Actions
# Action to get config.
class GetConfig < 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)
# Previously it was stored in user state
# config = state.user_state.preferences.to_json
config = {
darkTheme: state.user_state.user_preferences[:dark_theme]
}
js_script = "configBinding.receiveResponse('#{resolve_id}', #{config.to_json})"
state.with_add_queue_js_command('getConfig', js_script)
end
end
end
end
@@ -0,0 +1,26 @@
# frozen_string_literal: true
require_relative '../action'
require_relative '../user_preferences_updated'
module SpeckleConnector
module Actions
# Action to update config.
class UpdateConfig < Action
KEY_VALUES = {
'darkTheme' => 'dark_theme'
}.freeze
# @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, config)
config.each do |key, value|
state = Actions::UserPreferencesUpdated.new('configSketchup', KEY_VALUES[key], value).update_state(state)
end
js_script = "configBinding.receiveResponse('#{resolve_id}')"
state.with_add_queue_js_command('updateConfig', js_script)
end
end
end
end
@@ -8,7 +8,7 @@ module SpeckleConnector
class DeactivateDiffing < 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)
def self.update_state(state, _resolve_id, _data)
puts 'Diffing deactivated!'
speckle_entities = state.speckle_state.speckle_entities
diffing_activated_speckle_entities = speckle_entities.reject do |_id, entity|
@@ -1,6 +1,7 @@
# frozen_string_literal: true
require_relative 'event_action'
require_relative 'on_document_changed'
require_relative '../load_sketchup_model'
require_relative '../collect_preferences'
@@ -25,7 +26,8 @@ module SpeckleConnector
# Action to let UI to render itself with new preferences state
# TODO: Later UI should be updated if any stream is invalid after
# we collected speckle_entities appropriately
CollectPreferences.update_state(new_state, {})
new_state = CollectPreferences.update_state(new_state, nil, {})
OnDocumentChanged.update_state(new_state)
end
end
@@ -1,6 +1,7 @@
# frozen_string_literal: true
require_relative 'event_action'
require_relative '../../actions/send_actions/send_card_expiration_check'
require_relative '../../sketchup_model/utils/face_utils'
require_relative '../../constants/dict_constants'
@@ -26,19 +27,23 @@ module SpeckleConnector
def self.update_state(state, event_data)
speckle_state = state.speckle_state
modified_entity = event_data[0][1]
if modified_entity.is_a?(Sketchup::Face)
path = state.sketchup_state.sketchup_model.active_path
modified_faces = SketchupModel::Utils::FaceUtils.near_faces(modified_entity.edges)
path_objects = path.nil? ? [] : path + path.collect(&:definition)
parent_ids = path_objects.collect(&:persistent_id)
ids_to_invalidate = modified_faces.collect(&:persistent_id) + parent_ids
entities_to_invalidate = speckle_entities_to_invalidate(speckle_state, ids_to_invalidate)
new_speckle_state = invalidate_speckle_entities(speckle_state, entities_to_invalidate)
# This is the place we can send information to UI for diffing check
diffing = state.user_state.preferences[:user][:diffing]
new_speckle_state = new_speckle_state.with_invalid_streams_queue if diffing
return state.with_speckle_state(new_speckle_state)
end
modified_entities = event_data.collect { |data| data[1] }
new_speckle_state = state.speckle_state.with_changed_object_ids(modified_entities.collect(&:persistent_id))
state = state.with_speckle_state(new_speckle_state)
state = Actions::SendCardExpirationCheck.update_state(state)
# if modified_entity.is_a?(Sketchup::Face)
# path = state.sketchup_state.sketchup_model.active_path
# modified_faces = SketchupModel::Utils::FaceUtils.near_faces(modified_entity.edges)
# path_objects = path.nil? ? [] : path + path.collect(&:definition)
# parent_ids = path_objects.collect(&:persistent_id)
# ids_to_invalidate = modified_faces.collect(&:persistent_id) + parent_ids
# entities_to_invalidate = speckle_entities_to_invalidate(speckle_state, ids_to_invalidate)
# new_speckle_state = invalidate_speckle_entities(speckle_state, entities_to_invalidate)
# # This is the place we can send information to UI for diffing check
# diffing = state.user_state.preferences[:user][:diffing]
# new_speckle_state = new_speckle_state.with_invalid_streams_queue if diffing
# return state.with_speckle_state(new_speckle_state)
# end
state
end
@@ -0,0 +1,15 @@
# frozen_string_literal: true
module SpeckleConnector
module Actions
# Triggers whenever document has changed.
class OnDocumentChanged < 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)
js_command = "baseBinding.emit('documentChanged')"
state.with_add_queue_js_command('documentChanged', js_command)
end
end
end
end
@@ -0,0 +1,33 @@
# frozen_string_literal: true
require_relative 'event_action'
require_relative '../mapper_selection_changed'
require_relative '../selection_actions/get_selection'
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 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
Actions::GetSelection.update_state(state)
# 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
end
end
@@ -0,0 +1,21 @@
# frozen_string_literal: true
require_relative 'action'
require_relative '../accounts/accounts'
require_relative 'load_saved_streams'
module SpeckleConnector
module Actions
# Action to initialize local accounts from database.
class GetAccounts < 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)
puts 'Initialisation of Speckle accounts requested by plugin'
accounts_data = state.speckle_state.accounts
js_script = "accountsBinding.receiveResponse('#{resolve_id}', #{accounts_data.to_json})"
state.with_add_queue_js_command('getAccounts', js_script)
end
end
end
end
@@ -0,0 +1,22 @@
# frozen_string_literal: true
require_relative 'action'
module SpeckleConnector
module Actions
# Get document info.
class GetDocumentInfo < 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)
document_info = {
location: state.sketchup_state.sketchup_model.path,
name: state.sketchup_state.sketchup_model.name,
id: state.sketchup_state.sketchup_model.guid
}
js_command = "baseBinding.receiveResponse('#{resolve_id}', #{document_info.to_json})"
state.with_add_queue_js_command('getDocumentInfo', js_command)
end
end
end
end
@@ -0,0 +1,31 @@
# frozen_string_literal: true
module SpeckleConnector
module Actions
# Action to return error message to UI.
class HandleError < Action
# @param error [String] error
# @param view_name [String] name of the view (binding)
# @param action [Action] action that error happened
# @param parameters [Array<String>] arguments
def initialize(error, view_name, action, parameters)
super()
@error = error
@view_name = view_name
@action = action
@args = parameters
end
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
# @return [States::State] the new updated state object
def update_state(state)
error_message = "Error: #{@error}\nBinding: #{@view_name}\nAction:#{@action}\nArgs: #{@args}\n"
error = {
error: error_message
}
js_error_script = "#{@view_name}.receiveResponse('#{@args.first}', #{error.to_json})"
state.with_add_queue_js_command("error_#{@view_name}", js_error_script)
end
end
end
end
@@ -0,0 +1,36 @@
# frozen_string_literal: true
require_relative 'action'
require_relative 'events/selection_event_action'
require_relative '../sketchup_model/dictionary/speckle_schema_dictionary_handler'
module SpeckleConnector
module Actions
# Hide entities that selected from mapped elements table.
class HideMappingsFromTable < 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)
# Flat entities to clear mappings
flat_entities = SketchupModel::Query::Entity.flat_entities(state.sketchup_state.sketchup_model.entities)
# Collect entity ids to clear mappings
entity_ids = data.collect { |_, entities| entities['selectedElements'].collect { |e| e['entityId'] } }.flatten
# Store speckle state to update with mapped entities.
flat_entities.each do |entity|
next unless entity_ids.include?(entity.persistent_id)
if entity.is_a?(Sketchup::ComponentDefinition)
entity.instances.each do |instance|
instance.hidden = true
end
end
entity.hidden = true
end
Events::SelectionEventAction.update_state(state, { clear: true })
end
end
end
end
@@ -10,7 +10,7 @@ module SpeckleConnector
class InitLocalAccounts < 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)
def self.update_state(state, _request_id, _data)
puts 'Initialisation of Speckle accounts requested by plugin'
accounts_data = state.speckle_state.accounts
state.with_add_queue('loadAccounts', accounts_data.to_json, [])
@@ -7,6 +7,7 @@ require_relative '../states/sketchup_state'
require_relative '../accounts/accounts'
require_relative '../preferences/preferences'
require_relative '../constants/observer_constants'
require_relative '../ext/worker'
module SpeckleConnector
module Actions
@@ -14,7 +15,8 @@ module SpeckleConnector
class InitializeSpeckle < 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, observers)
def self.update_state(state, observers, instant_message_sender)
worker = SpeckleConnector::Worker.new()
attach_app_observer!(observers[APP_OBSERVER])
accounts = SpeckleConnector::Accounts.load_accounts
speckle_state = States::SpeckleState.new(accounts, observers, {}, {})
@@ -22,7 +24,9 @@ module SpeckleConnector
sketchup_state = States::SketchupState.new(Sketchup.active_model)
preferences = Preferences.read_preferences(sketchup_state.sketchup_model)
user_state_with_preferences = state.user_state.with_preferences(preferences)
state = States::State.new(user_state_with_preferences, speckle_state, sketchup_state, false)
state = States::State.new(user_state_with_preferences, speckle_state, sketchup_state, false,
worker, &instant_message_sender)
# This is where we attach observers to related model objects like selection, entities..
Actions::LoadSketchupModel.update_state(state, sketchup_state.sketchup_model)
end
@@ -0,0 +1,64 @@
# frozen_string_literal: true
require_relative 'action'
require_relative 'events/selection_event_action'
require_relative '../sketchup_model/dictionary/speckle_schema_dictionary_handler'
module SpeckleConnector
module Actions
# Isolate entities that selected from mapped elements table.
class IsolateMappingsFromTable < Action
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
# @return [States::State] the new updated state object
# rubocop:disable Metrics/AbcSize
# rubocop:disable Metrics/MethodLength
# rubocop:disable Metrics/PerceivedComplexity
# rubocop:disable Metrics/CyclomaticComplexity
def self.update_state(state, _resolve_id, data)
sketchup_model = state.sketchup_state.sketchup_model
# Hide all entities first
sketchup_model.entities.each do |ent|
ent.hidden = true
end
# Flat entities to isolate mappings
flat_entities = SketchupModel::Query::Entity.flat_entities(sketchup_model.entities)
comp_flat_entities = flat_entities.grep(Sketchup::ComponentInstance) + flat_entities.grep(Sketchup::Group) +
flat_entities.grep(Sketchup::ComponentDefinition)
face_edge_flat_entities = flat_entities.grep(Sketchup::Face) + flat_entities.grep(Sketchup::Edge)
# Collect entity ids to clear mappings
selected_elements = data.collect { |_, entities| entities['selectedElements'] }.flatten
comps_or_groups, faces_or_edges = selected_elements.partition do |e|
e['entityType'] == 'Component' || e['entityType'] == 'Definition' || e['entityType'] == 'Group'
end
faces_or_edges_ids = faces_or_edges.collect { |e| e['entityId'] }
face_edge_flat_entities.select { |e| faces_or_edges_ids.include?(e.persistent_id) }.each do |entity|
entity.hidden = false
end
comps_or_groups_ids = comps_or_groups.collect { |e| e['entityId'] }
comp_flat_entities.select { |e| comps_or_groups_ids.include?(e.persistent_id) }.each do |entity|
if entity.is_a?(Sketchup::ComponentDefinition)
entity.instances.each do |instance|
instance.hidden = false
end
end
entity.hidden = false
end
Events::SelectionEventAction.update_state(state, { clear: true })
end
# rubocop:enable Metrics/AbcSize
# rubocop:enable Metrics/MethodLength
# rubocop:enable Metrics/PerceivedComplexity
# rubocop:enable Metrics/CyclomaticComplexity
end
end
end
@@ -8,7 +8,7 @@ module SpeckleConnector
class LoadSavedStreams < 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)
def self.update_state(state, _request_id, _data)
(saved_streams = state.sketchup_state.sketchup_model
.attribute_dictionary('Speckle', true)['saved_streams']) or []
state.with_add_queue('setSavedStreams', saved_streams, [])
@@ -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'
@@ -28,6 +29,9 @@ module SpeckleConnector
# Read speckle entities
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::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)
# Read preferences from database and model.
@@ -42,8 +46,8 @@ module SpeckleConnector
# @param sketchup_model [Sketchup::Model] the model to attach observers to
# @param observers [Hash{Class=>}] the observer objects indexed by their class that will be attached
def self.attach_observers(sketchup_model, observers)
# selection = sketchup_model.selection
# selection.add_observer(observers[SELECTION_OBSERVER_NAME])
selection = sketchup_model.selection
selection.add_observer(observers[SELECTION_OBSERVER])
# layers = sketchup_model.layers
# layers.add_observer(observers[LAYERS_OBSERVER_NAME])
entities = sketchup_model.entities
@@ -0,0 +1,20 @@
# frozen_string_literal: true
require_relative 'action'
require_relative '../sketchup_model/reader/mapper_reader'
module SpeckleConnector
module Actions
# Triggers when mapped entities updated.
class MappedEntitiesUpdated < 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 = nil, _data = nil)
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
end
end
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
@@ -4,6 +4,7 @@ require_relative 'action'
require_relative 'events/app_event_action'
require_relative 'events/entities_event_action'
require_relative 'events/model_event_action'
require_relative 'events/selection_event_action'
require_relative '../constants/observer_constants'
module SpeckleConnector
@@ -13,11 +14,11 @@ module SpeckleConnector
RUN_ORDER = {
APP_OBSERVER => Events::AppEventAction,
ENTITIES_OBSERVER => Events::EntitiesEventAction,
MODEL_OBSERVER => Events::ModelEventAction
MODEL_OBSERVER => Events::ModelEventAction,
# MATERIALS_OBSERVER => Events::MaterialsEventAction,
# LAYERS_OBSERVER => Events::LayerEventAction,
# PAGES_OBSERVER => Events::PagesEventAction,
# SELECTION_OBSERVER => Events::SelectionEventAction
SELECTION_OBSERVER => Events::SelectionEventAction
}.freeze
def self.update_state(state, events)
@@ -0,0 +1,18 @@
# frozen_string_literal: true
require_relative '../action'
module SpeckleConnector
module Actions
# Action to let sketchup know receive from server is finished..
class AfterReceive < 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, stream_id, root_id)
puts "receive finished for: #{root_id}"
js_script = "sketchupReceiveBinding.receiveResponse('#{resolve_id}')"
state.with_add_queue_js_command('afterReceive', js_script)
end
end
end
end
@@ -0,0 +1,18 @@
# frozen_string_literal: true
require_relative '../action'
module SpeckleConnector
module Actions
# Action to let sketchup know receive will be started.
class BeforeReceive < 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, stream_id, root_id)
puts "receive started for: #{root_id}"
js_script = "sketchupReceiveBinding.receiveResponse('#{resolve_id}')"
state.with_add_queue_js_command('beforeReceive', js_script)
end
end
end
end
@@ -0,0 +1,91 @@
# frozen_string_literal: true
require 'json'
require_relative '../action'
require_relative '../../convertors/units'
require_relative '../../convertors/to_native'
module SpeckleConnector
module Actions
# Clear mappings for selected entities.
class ReceiveSingleObject < 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, stream_id, root_id, speckle_objects)
puts "object receive #{speckle_objects.length}"
buffer = speckle_objects.collect { |obj| [obj['id'], obj] }.to_h
t_0 = Time.now.to_f
root_obj = traverse_and_construct(speckle_objects.first, buffer)
puts root_obj
puts "Elapsed traverse and construct #{Time.now.to_f - t_0}"
# File.open("#{ENV['HOME']}/OneDrive/Masaüstü/root.json", 'w') do |f|
# f.write(JSON.pretty_generate(root_obj))
# end
# converter = Converters::ToNative.new(state, stream_id, 'test', 'testt', 'test')
# state = converter.receive_commit_object(root_obj)
js_script = "sketchupReceiveBinding.receiveResponse('#{resolve_id}')"
state.with_add_queue_js_command('receiveObject', js_script)
end
def self.traverse_and_construct(obj, buffer)
return if obj.nil?
return obj if !obj.is_a?(Hash) && !obj.is_a?(Array)
# Handle arrays
if obj.is_a?(Array) && !obj.empty?
arr = handle_array(buffer, obj)
# De-chunk, if array is a set of datachunk, flat them into single data chunk.
arr = try_dechunk(arr)
return arr
end
# Handle object
obj = handle_hash(buffer, obj)
return obj
rescue StandardError => e
puts "#{e} -> #{obj}"
return nil
end
def self.handle_array(buffer, obj)
arr = []
obj.collect do |element|
next if element.nil?
deref = element.is_a?(Hash) && !element['referencedId'].nil? ? buffer[element['referencedId']] : element
arr.append(traverse_and_construct(deref, buffer))
end
arr
end
def self.try_dechunk(arr)
if arr[0].is_a?(Hash) && !arr[0]['speckle_type'].nil? && arr[0]['speckle_type'].downcase.include?('datachunk')
sum_arr = []
arr.each do |chunk|
sum_arr += chunk['data']
end
sum_arr
else
arr
end
end
def self.handle_hash(buffer, obj)
obj.each do |prop, value|
next if value.nil? || (!value.is_a?(Hash) && !value.is_a?(Array))
obj[prop] = buffer[value['referencedId']] if value.is_a?(Hash) && value['referencedId']
obj[prop] = traverse_and_construct(obj[prop], buffer)
end
obj
end
end
end
end
@@ -0,0 +1,26 @@
# frozen_string_literal: true
require_relative '../action'
require_relative '../../convertors/to_native'
require_relative '../../ext/TT_Lib2/progressbar'
module SpeckleConnector
module Actions
# Receive from server.
class AfterGetObjects < 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, source_application, root_obj)
model_card = state.speckle_state.receive_cards[model_card_id]
converter = Converters::ToNative.new(state, model_card.model_id, model_card.project_name,
model_card.model_name, source_application)
# Have side effects on the sketchup model. It effects directly on the entities by adding new objects.
state = converter.receive_commit_object(root_obj)
resolve_js_script = "receiveBinding.receiveResponse('#{resolve_id}')"
state.with_add_queue_js_command('receive', resolve_js_script)
end
end
end
end
@@ -0,0 +1,37 @@
# frozen_string_literal: true
require_relative '../action'
require_relative '../../accounts/accounts'
require_relative '../../convertors/units'
require_relative '../../convertors/to_speckle'
require_relative '../../operations/send'
require_relative '../../ext/TT_Lib2/progressbar'
module SpeckleConnector
module Actions
# Receive from server.
class Receive < 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, source_application)
model_card = state.speckle_state.receive_cards[model_card_id]
account = Accounts.get_account_by_id(model_card.account_id)
resolve_js_script = "receiveBinding.receiveResponse('#{resolve_id}')"
state = state.with_add_queue_js_command('receive', 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,
objectId: model_card.object_id,
sourceApplication: source_application
}
js_script = "receiveBinding.emit('receiveViaBrowser', #{args.to_json})"
state.with_add_queue_js_command('receiveViaBrowser', js_script)
end
end
end
end
@@ -3,13 +3,15 @@
require_relative 'action'
require_relative '../convertors/units'
require_relative '../convertors/to_native'
require_relative '../operations/receive'
require_relative '../convertors/clean_up'
module SpeckleConnector
module Actions
# Action to receive objects from Speckle Server.
class ReceiveObjects < Action
# rubocop:disable Metrics/ParameterLists
def initialize(stream_id, base, stream_name, branch_name, branch_id, source_app)
def initialize(stream_id, base, stream_name, branch_name, branch_id, source_app, object_id)
super()
@stream_id = stream_id
@base = base
@@ -17,16 +19,24 @@ module SpeckleConnector
@branch_name = branch_name
@branch_id = branch_id
@source_app = source_app
@object_id = object_id
end
# rubocop:enable Metrics/ParameterLists
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
# @return [States::State] the new updated state object
def update_state(state)
# content = Operations.receive(@stream_id, @object_id)
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}. ===="
@@ -10,7 +10,7 @@ module SpeckleConnector
class ReloadAccounts < 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)
def self.update_state(state, _resolve_id, _data)
puts 'Reload of Speckle accounts requested by plugin'
new_speckle_state = state.speckle_state.with_accounts(Accounts.load_accounts)
state = state.with_speckle_state(new_speckle_state)
@@ -0,0 +1,37 @@
# frozen_string_literal: true
require_relative 'action'
require_relative 'events/selection_event_action'
require_relative '../sketchup_model/dictionary/speckle_schema_dictionary_handler'
module SpeckleConnector
module Actions
# Select entities that selected from mapped elements table.
class SelectMappingsFromTable < 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)
# Clear first selection
state.sketchup_state.sketchup_model.selection.clear
# Flat entities to select mapped elements
flat_entities = SketchupModel::Query::Entity.flat_entities(state.sketchup_state.sketchup_model.entities)
# Collect entity ids to clear mappings
entity_ids = data.collect { |_, entities| entities['selectedElements'].collect { |e| e['entityId'] } }.flatten
# Store speckle state to update with mapped entities.
flat_entities.each do |entity|
next unless entity_ids.include?(entity.persistent_id)
if entity.is_a?(Sketchup::ComponentDefinition)
state.sketchup_state.sketchup_model.selection.add(entity.instances)
end
state.sketchup_state.sketchup_model.selection.add(entity)
end
Events::SelectionEventAction.update_state(state, { clear: true })
end
end
end
end
@@ -0,0 +1,22 @@
# frozen_string_literal: true
require_relative '../action'
require_relative '../../ui_data/sketchup/selection_info'
module SpeckleConnector
module Actions
# Action to get selection.
class GetSelection < 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)
selected_object_ids = state.sketchup_state.sketchup_model.selection.collect(&:persistent_id)
summary = "Selected #{selected_object_ids.length} objects."
selection_info = UiData::Sketchup::SelectionInfo.new(selected_object_ids, summary)
# js_script = "selectionBinding.receiveResponse('#{resolve_id}', #{selection_info.to_json})"
js_script = "selectionBinding.emit('setSelection', #{selection_info.to_json})"
state.with_add_queue_js_command('setSelection', js_script)
end
end
end
end
@@ -0,0 +1,22 @@
# frozen_string_literal: true
require_relative '../action'
require_relative '../../sketchup_model/dictionary/model_card_dictionary_handler'
module SpeckleConnector
module Actions
# Action to activate send filter.
class ActivateSendFilter < 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, value)
SketchupModel::Dictionary::ModelCardDictionaryHandler.update_filter(state.sketchup_state.sketchup_model, data, value)
card_id = "#{data['accountId']}-#{data['projectId']}-#{data['modelId']}"
send_card = state.speckle_state.send_cards[card_id]
puts "Send card filter updated -> #{card_id} -> #{send_card}"
js_script = "sendBindingOld.receiveResponse('#{resolve_id}')"
state.with_add_queue_js_command('activateSendFilter', js_script)
end
end
end
end
@@ -0,0 +1,22 @@
# frozen_string_literal: true
require_relative '../action'
require_relative '../../sketchup_model/dictionary/model_card_dictionary_handler'
module SpeckleConnector
module Actions
# Action to activate send filter tag.
class ActivateSendFilterTag < 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, value)
SketchupModel::Dictionary::ModelCardDictionaryHandler.update_tag_filter(state.sketchup_state.sketchup_model, data, value)
card_id = "#{data['accountId']}-#{data['projectId']}-#{data['modelId']}"
send_card = state.speckle_state.send_cards[card_id]
puts "Send card filter updated -> #{card_id} -> #{send_card}"
js_script = "sendBindingOld.receiveResponse('#{resolve_id}')"
state.with_add_queue_js_command('activateSendFilterTag', js_script)
end
end
end
end
@@ -0,0 +1,86 @@
# frozen_string_literal: true
require_relative '../action'
require_relative '../../accounts/accounts'
require_relative '../../convertors/units'
require_relative '../../convertors/to_speckle'
require_relative '../../operations/send'
require_relative '../../ext/TT_Lib2/progressbar'
require_relative '../../ext/worker'
module SpeckleConnector
module Actions
# Send to server.
class Send < 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)
model_card = state.speckle_state.send_cards[model_card_id]
account = Accounts.get_account_by_id(model_card.account_id)
converter = Converters::ToSpeckle.new(state, model_card_id, model_card.send_filter)
new_speckle_state, base = converter.convert_selection_to_base(state.user_state.preferences)
id, total_children_count, batches, new_speckle_state = converter.serialize(base, new_speckle_state,
state.user_state.preferences)
# update_test(state)
puts("converted #{base.count} objects for stream #{@stream_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,
sendObject: {
id: id,
totalChildrenCount: total_children_count,
batches: batches
}
}
js_script = "sendBinding.emit('sendViaBrowser', #{args.to_json})"
state.with_add_queue_js_command('sendViaBrowser', js_script)
end
def self.update_test(state)
dialog = UI::HtmlDialog.new(
{
:dialog_title => 'Dialog Example',
:preferences_key => 'com.sample.plugin',
:scrollable => true,
:resizable => true,
:width => 600,
:height => 400,
:left => 10,
:top => 10,
:min_width => 50,
:min_height => 50,
:max_width =>1000,
:max_height => 1000,
:style => UI::HtmlDialog::STYLE_DIALOG
})
html = '<div id="hi"><b>Hello world!</b></div>'
dialog.set_html(html)
dialog.show
action = Proc.new do |status|
js_command = "document.getElementById('hi').innerHTML = '<b>#{status}</b>'"
log_js_command = "console.log('test')"
dialog.execute_script(js_command)
dialog.execute_script(log_js_command)
end
selected_object_ids = state.sketchup_state.sketchup_model.selection.collect(&:persistent_id)
state.worker.add_jobs(1000.times.to_a.map { |i| Job.new(i, &action) })
state.worker.do_work(Time.now.to_f, &action)
end
end
end
end
@@ -0,0 +1,23 @@
# frozen_string_literal: true
require_relative '../action'
require_relative '../../sketchup_model/dictionary/model_card_dictionary_handler'
module SpeckleConnector
module Actions
# Action to check send card expirations.
class SendCardExpirationCheck < 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)
return state unless state.speckle_state.changed_entity_ids.any?
expired_send_cards_ids = state.speckle_state.send_cards.select do |_id, send_card|
send_card.send_filter.check_expiry(state.speckle_state.changed_entity_ids)
end.keys.to_a
js_script = "sendBinding.emit('sendersExpired', #{expired_send_cards_ids.to_json})"
state.with_add_queue_js_command('sendersExpired', js_script)
end
end
end
end
@@ -4,6 +4,7 @@ require_relative 'action'
require_relative 'deactivate_diffing'
require_relative '../convertors/units'
require_relative '../convertors/to_speckle'
require_relative '../operations/send'
module SpeckleConnector
module Actions
@@ -17,11 +18,14 @@ module SpeckleConnector
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
# @return [States::State] the new updated state object
def update_state(state)
state = DeactivateDiffing.update_state(state, {})
converter = Converters::ToSpeckle.new(state, @stream_id)
state = DeactivateDiffing.update_state(state, nil, {})
converter = Converters::ToSpeckle.new(state, @stream_id, {})
new_speckle_state, base = converter.convert_selection_to_base(state.user_state.preferences)
id, total_children_count, batches, new_speckle_state = converter.serialize(base, new_speckle_state,
state.user_state.preferences)
# TODO: Later active send operation.
# Operations.send(@stream_id, batches)
puts("converted #{base.count} objects for stream #{@stream_id}")
# This is the place we can send information to UI for diffing check
@@ -0,0 +1,20 @@
# frozen_string_literal: true
require_relative 'action'
module SpeckleConnector
module Actions
# Show all entities on the model.
class ShowAllEntities < 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)
# Show all entities first
state.sketchup_state.sketchup_model.entities.each do |ent|
ent.hidden = false
end
state
end
end
end
end
@@ -0,0 +1,46 @@
# frozen_string_literal: true
require_relative '../action'
module SpeckleConnector
module Actions
# Action to get user config.
class GetUserConfig < 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)
# Previously it was stored in user state
# config = state.user_state.preferences.to_json
config = [
{
key: 'darkTheme',
title: 'Theme',
type: 'toggle',
config: {
value: state.user_state.user_preferences[:dark_theme]
}
},
{
key: 'diffing',
title: 'Diffing',
type: 'toggle',
config: {
value: state.user_state.user_preferences[:diffing]
}
},
{
key: 'referencePoint',
title: 'Reference Point',
type: 'dropdown',
config: {
value: 'test',
items: ['test', 'test1', 'test2']
}
}
]
js_script = "connectorConfigBinding.receiveResponse('#{resolve_id}', #{config.to_json})"
state.with_add_queue_js_command('getUserConfig', js_script)
end
end
end
end
@@ -0,0 +1,18 @@
# frozen_string_literal: true
require_relative '../action'
module SpeckleConnector
module Actions
# Action to get user config.
class UpdateUserConfig < 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, new_config)
puts new_config.values
js_script = "connectorConfigBinding.receiveResponse('#{resolve_id}')"
state.with_add_queue_js_command('updateUserConfig', js_script)
end
end
end
end
@@ -0,0 +1,21 @@
# frozen_string_literal: true
require_relative '../action'
module SpeckleConnector
module Actions
# Test purpose action.
class GetComplexType < 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)
complex_type = {
id: 'complex_type_id',
count: 3
}
js_script = "testBinding.receiveResponse('#{resolve_id}', #{complex_type.to_json})"
state.with_add_queue_js_command('getComplexType', js_script)
end
end
end
end
@@ -0,0 +1,18 @@
# frozen_string_literal: true
require_relative '../action'
module SpeckleConnector
module Actions
# Test purpose action.
class GoAway < 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)
puts 'SketchUp went away :('
js_script = "testBinding.receiveResponse('#{resolve_id}')"
state.with_add_queue_js_command('goAway', js_script)
end
end
end
end
@@ -0,0 +1,21 @@
# frozen_string_literal: true
require_relative '../action'
module SpeckleConnector
module Actions
# Test purpose action.
class SayHi < 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, name, count, say_hello_not_hi)
said_hi = []
count.times do
said_hi.append("#{say_hello_not_hi ? 'Hello' : 'Hi'} #{name}!")
end
js_script = "testBinding.receiveResponse('#{resolve_id}', #{said_hi})"
state.with_add_queue_js_command('sayHi', js_script)
end
end
end
end
@@ -0,0 +1,28 @@
# frozen_string_literal: true
require_relative '../action'
module SpeckleConnector
module Actions
# Test purpose action.
class TriggerEvent < 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, event_name)
if event_name == 'emptyTestEvent'
js_script = "testBinding.emit('#{event_name}')"
else
args = {
name: 'Oguzhan',
isOk: true,
count: 3
}
js_script = "testBinding.emit('#{event_name}', #{args.to_json})"
end
resolve_js_script = "testBinding.receiveResponse('#{resolve_id}')"
state = state.with_add_queue_js_command('triggerEventResolve', resolve_js_script)
state.with_add_queue_js_command('triggerEvent', js_script)
end
end
end
end
@@ -28,25 +28,32 @@ module SpeckleConnector
state.speckle_state?
end
def update_ui!
ui_controller.update_ui(state)
end
def send_messages!
queue = @state.speckle_state.message_queue
queue.each_value { |value| ui_controller.user_interfaces[Ui::SPECKLE_UI_ID].dialog.execute_script(value) }
update_state!(Actions::ClearQueue)
end
# Attach observers to application when speckle initialized via menu commands.
def add_observer_handler!(observer_handler)
@observer_handler = observer_handler
end
# Send messages to HtmlDialog if any.
def send_messages!
queue = @state.speckle_state.message_queue
queue.each_value do |value|
instant_message_sender(value)
end
update_state!(Actions::ClearQueue)
end
def instant_message_sender(message)
ui_controller.user_interfaces.each_value do |dialog|
dialog.execute_script(message)
end
end
# This is the only function application state will be switched by calling upcoming action with it's parameters
# if any.
def update_state!(action, *parameters)
old_state = @state
@state = action.update_state(old_state, *parameters)
send_messages! if @state.speckle_state.message_queue.any?
update_ui! unless @state.equal?(old_state)
end
end
end
+39
View File
@@ -0,0 +1,39 @@
# frozen_string_literal: true
require_relative '../speckle_objects/other/color'
module SpeckleConnector
module Cards
# Card for sketchup connector to communicate speckle.
class Card < Hash
# @return [String] id of the card.
attr_reader :id
# @return [String] account id of the card.
attr_reader :account_id
# @return [String] project id of the card.
attr_reader :project_id
# @return [String] model id of the card.
attr_reader :model_id
# @return [Boolean] card is valid or not.
attr_reader :valid
def initialize(card_id, account_id, project_id, model_id)
super()
@id = card_id
@account_id = account_id
@project_id = project_id
@model_id = model_id
@valid = true
self[:id] = card_id
self[:account_id] = account_id
self[:project_id] = project_id
self[:model_id] = model_id
self[:valid] = @valid
end
end
end
end
@@ -0,0 +1,36 @@
# frozen_string_literal: true
require_relative 'card'
module SpeckleConnector
module Cards
# Receive card for sketchup connector to communicate speckle.
class ReceiveCard < Card
attr_reader :type_discriminator
# @return [String, NilClass] message to send
attr_reader :message
# @return [String] object id to receive
attr_reader :object_id
# @return [String] name of the project
attr_reader :project_name
# @return [String] name of the model
attr_reader :model_name
def initialize(card_id, account_id, project_id, project_name, model_id, model_name, object_id)
super(card_id, account_id, project_id, model_id)
@object_id = object_id
self[:object_id] = object_id
self[:model_name] = model_name
self[:project_name] = project_name
@model_name = model_name
@project_name = project_name
@type_discriminator = 'ReceiverModelCard'
self[:type_discriminator] = @type_discriminator
end
end
end
end
+31
View File
@@ -0,0 +1,31 @@
# frozen_string_literal: true
require_relative 'card'
module SpeckleConnector
module Cards
# Send card for sketchup connector to communicate speckle.
class SendCard < Card
# @return [Filters::Send::EverythingFilter | Filters::Send::SelectionFilter | Filters::Send::LayerFilter] filter of the card.
attr_reader :send_filter
# @return [Object] send settings of the card.
attr_reader :send_settings
attr_reader :type_discriminator
# @return [String, NilClass] message to send
attr_reader :message
def initialize(card_id, account_id, project_id, model_id, send_filter, send_settings)
super(card_id, account_id, project_id, model_id)
@send_filter = send_filter
@send_settings = send_settings
@type_discriminator = 'SenderModelCard'
self[:sendFilter] = send_filter
self[:sendSettings] = send_settings
self[:type_discriminator] = @type_discriminator
end
end
end
end
@@ -0,0 +1,19 @@
# frozen_string_literal: true
require_relative 'card'
module SpeckleConnector
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
@@ -7,10 +7,10 @@ module SpeckleConnector
# Command to update state of the application.
class ActionCommand < Command
# @param app [App::SpeckleConnectorApp] the app object to run command on
# @param binding [Ui::Binding] binding object holds commands to call
# @param action [#update_state] the action that knows how to change the state of the speckle app
def initialize(app, action)
super(app)
@app = app
def initialize(app, binding, action)
super(app, binding)
@action = action
end
@@ -7,7 +7,7 @@ module SpeckleConnector
module Commands
# Command to activate diffing for stream.
class ActivateDiffing < Command
def _run(data)
def _run(_resolve_id, data)
stream_id = data['stream_id']
action = Actions::ActivateDiffing.new(stream_id)
app.update_state!(action)
@@ -0,0 +1,25 @@
# frozen_string_literal: true
require_relative 'command'
require_relative '../actions/apply_mappings'
module SpeckleConnector
module Commands
# Command to apply mapping for selected entities.
class ApplyMappings < Command
def _run(_resolve_id, data)
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, family,
family_type, level, name, is_definition)
app.update_state!(action)
end
end
end
end
@@ -0,0 +1,18 @@
# frozen_string_literal: true
require_relative 'command'
require_relative '../actions/clear_mappings'
module SpeckleConnector
module Commands
# Command to clear mapping for selected entities.
class ClearMappings < Command
def _run(_resolve_id, data)
entities_to_map = data['entitiesToClearMap']
is_definition = data['isDefinition']
action = Actions::ClearMappings.new(entities_to_map, is_definition)
app.update_state!(action)
end
end
end
end
+16 -8
View File
@@ -1,5 +1,7 @@
# frozen_string_literal: true
require_relative '../actions/handle_error'
module SpeckleConnector
module Commands
# Base command schema to wrap common operations for all commands.
@@ -7,19 +9,25 @@ module SpeckleConnector
# @return [App::SpeckleConnectorApp] the main app object
attr_reader :app
# @return [Ui::View] view object holds dialog and it's state
attr_reader :view
# @return [Ui::Binding] binding object holds dialog and it's state
attr_reader :binding
# @@param app [App::SpeckleConnectorApp] the main app object
def initialize(app)
# @param app [App::SpeckleConnectorApp] the main app object
# @param binding [Ui::Binding] binding object holds commands to call
def initialize(app, binding)
@app = app
@view = app.ui_controller.user_interfaces[Ui::SPECKLE_UI_ID]
@binding = binding
end
def run(*parameters)
# Run here common operations that same for each command.
with_observers_disabled do
_run(*parameters)
begin
# Run here common operations that same for each command.
with_observers_disabled do
_run(*parameters)
end
rescue StandardError => e
action = Actions::HandleError.new(e, @binding.name, @action, parameters)
app.update_state!(action)
end
end
@@ -1,15 +0,0 @@
# frozen_string_literal: true
require_relative 'command'
module SpeckleConnector
module Commands
# Run this command when the UI is ready to get data
class DialogReady < Command
# Update the selected user interface
def _run(_data)
view.update_view(app.state)
end
end
end
end
@@ -0,0 +1,85 @@
# frozen_string_literal: true
require_relative 'command'
require_relative '../ui/dui3_dialog'
require_relative '../states/initial_state'
require_relative '../ui/legacy_binding'
require_relative '../ui/bindings/accounts_binding'
require_relative '../ui/bindings/base_binding'
require_relative '../ui/bindings/send_binding'
require_relative '../ui/bindings/receive_binding'
require_relative '../ui/bindings/selection_binding'
require_relative '../ui/test_binding'
require_relative '../ui/bindings/config_binding'
require_relative '../ui/sketchup_config_binding'
require_relative '../actions/initialize_speckle'
require_relative '../observers/factory'
module SpeckleConnector
module Commands
# Command to initialize Speckle UI and register it to ui_controller.
# This is the command where we show UI to user.
class InitializeDUI3Speckle < Command
SPECKLE_DUI3 = 'speckle_dui3'
def dialog_title
"Speckle #{CONNECTOR_VERSION}"
end
private
def _run
app = self.app
if !app.state.instance_of?(States::InitialState) && app.ui_controller.user_interfaces[SPECKLE_DUI3]
dialog = app.ui_controller.user_interfaces[SPECKLE_DUI3]
dialog.show
return
end
initialize_speckle_dui3(app)
end
# Do the actual Speckle initialization.
# rubocop:disable Naming/VariableNumber
def initialize_speckle_dui3(app)
# TODO: Initialize here speckle states and observers.
observer_handler = Observers::Factory.create_handler(app)
app.add_observer_handler!(observer_handler)
observers = Observers::Factory.create_observers(observer_handler)
app.update_state!(Actions::InitializeSpeckle, observers, app.method(:instant_message_sender))
dialog_specs = {
dialog_id: SPECKLE_DUI3,
dialog_title: dialog_title,
height: 950,
width: 300
}
# Init bindings
base_binding = Ui::BaseBinding.new(app, Ui::BASE_BINDING_NAME)
accounts_binding = Ui::AccountsBinding.new(app, Ui::ACCOUNTS_BINDING_NAME)
send_binding = Ui::SendBinding.new(app, Ui::SEND_BINDING_NAME)
receive_binding = Ui::ReceiveBinding.new(app, Ui::RECEIVE_BINDING_NAME)
selection_binding = Ui::SelectionBinding.new(app, Ui::SELECTION_BINDING_NAME)
test_bindings = Ui::TestBinding.new(app, Ui::TEST_BINDINGS_NAME)
config_bindings = Ui::ConfigBinding.new(app, Ui::CONFIG_BINDING_NAME)
connector_config_bindings = Ui::SketchupConfigBinding.new(app, Ui::CONNECTOR_CONFIG_BINDING_NAME)
# Init dialog
dui3_dialog = SpeckleConnector::Ui::DUI3Dialog.new(**dialog_specs)
# Register bindings to dialog
dui3_dialog.bindings[Ui::BASE_BINDING_NAME] = base_binding
dui3_dialog.bindings[Ui::ACCOUNTS_BINDING_NAME] = accounts_binding
dui3_dialog.bindings[Ui::SEND_BINDING_NAME] = send_binding
dui3_dialog.bindings[Ui::RECEIVE_BINDING_NAME] = receive_binding
dui3_dialog.bindings[Ui::TEST_BINDINGS_NAME] = test_bindings
dui3_dialog.bindings[Ui::CONFIG_BINDING_NAME] = config_bindings
dui3_dialog.bindings[Ui::CONNECTOR_CONFIG_BINDING_NAME] = connector_config_bindings
dui3_dialog.bindings[Ui::SELECTION_BINDING_NAME] = selection_binding
app.ui_controller.register_ui(SPECKLE_DUI3, dui3_dialog)
dui3_dialog.show
end
# rubocop:enable Naming/VariableNumber
end
end
end
@@ -2,15 +2,17 @@
require_relative 'command'
require_relative '../states/initial_state'
require_relative '../ui/vue_view'
require_relative '../ui/legacy_binding'
require_relative '../actions/initialize_speckle'
require_relative '../observers/factory'
module SpeckleConnector
module Commands
# Command to initialize Speckle UI and register it to ui_controller.
# Command to initialize old Speckle UI and register it to ui_controller.
# This is the command where we show UI to user.
class InitializeSpeckle < Command
SPECKLE_LEGACY_UI = 'speckle_legacy_ui'
def dialog_title
"Speckle #{CONNECTOR_VERSION}"
end
@@ -19,32 +21,34 @@ module SpeckleConnector
def _run
app = self.app
unless app.state.instance_of?(States::InitialState)
vue_view = app.ui_controller.user_interfaces[Ui::SPECKLE_UI_ID]
if !app.state.instance_of?(States::InitialState) && app.ui_controller.user_interfaces[SPECKLE_LEGACY_UI]
vue_view = app.ui_controller.user_interfaces[SPECKLE_LEGACY_UI]
vue_view.show
return
end
initialize_speckle(app)
initialize_speckle_legacy_view(app)
end
# Do the actual Speckle initialization.
def initialize_speckle(app)
def initialize_speckle_legacy_view(app)
# TODO: Initialize here speckle states and observers.
observer_handler = Observers::Factory.create_handler(app)
app.add_observer_handler!(observer_handler)
observers = Observers::Factory.create_observers(observer_handler)
app.update_state!(Actions::InitializeSpeckle, observers)
dialog_specs = {
dialog_id: Ui::SPECKLE_UI_ID,
dialog_id: SPECKLE_LEGACY_UI,
htm_file: Ui::VUE_UI_HTML,
dialog_title: dialog_title,
height: 950,
width: 300
}
vue_view = Ui::VueView.new(dialog_specs, app)
app.ui_controller.register_ui(Ui::SPECKLE_UI_ID, vue_view)
vue_view.show
legacy_ui_dialog = SpeckleConnector::Ui::Dialog.new(**dialog_specs)
legacy_binding = Ui::LegacyBinding.new(app, 'legacy_ui')
legacy_ui_dialog.bindings[Ui::SPECKLE_LEGACY_BINDING_NAME] = legacy_binding
app.ui_controller.register_ui(SPECKLE_LEGACY_UI, legacy_ui_dialog)
legacy_ui_dialog.show
end
end
end
@@ -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(_resolve_id, 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
@@ -8,7 +8,7 @@ module SpeckleConnector
module Commands
# Command to update theme.
class ModelPreferencesUpdated < Command
def _run(data)
def _run(_resolve_id, data)
preference = data['preference']
new_value = data['value']
app.update_state!(Actions::ModelPreferencesUpdated.new(preference, new_value))
@@ -8,7 +8,7 @@ module SpeckleConnector
module Commands
# Command to notify connected.
class NotifyConnected < Command
def _run(data)
def _run(_resolve_id, data)
stream_id = data['stream_id']
app.update_state!(Actions::Connected)
app.update_state!(Actions::SendFromQueue.new(stream_id))
@@ -7,14 +7,15 @@ module SpeckleConnector
module Commands
# Command to receive objects from Speckle Server.
class ReceiveObjects < Command
def _run(data)
def _run(_resolve_id, data)
stream_id = data['stream_id']
base = data['base']
branch_name = data['branch_name']
branch_id = data['branch_id']
stream_name = data['stream_name']
source_app = data['source_app']
action = Actions::ReceiveObjects.new(stream_id, base, stream_name, branch_name, branch_id, source_app)
object_id = data['object_id']
action = Actions::ReceiveObjects.new(stream_id, base, stream_name, branch_name, branch_id, source_app, object_id)
app.update_state!(action)
end
end
@@ -8,7 +8,7 @@ module SpeckleConnector
module Commands
# Command to remove stream.
class RemoveStream < Command
def _run(data)
def _run(_resolve_id, data)
stream_id = data['stream_id']
action = Actions::RemoveStream.new(stream_id)
app.update_state!(action)
@@ -0,0 +1,26 @@
# frozen_string_literal: true
require_relative 'command'
require_relative '../states/initial_state'
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_LEGACY_UI]
if vue_view
vue_view.dialog.reset_dialog_location
else
puts "Speckle UI didn't initialized!"
end
end
end
end
end
@@ -9,7 +9,7 @@ module SpeckleConnector
module Commands
# Command to saved stream.
class SaveStream < Command
def _run(data)
def _run(_resolve_id, data)
stream_id = data['stream_id']
app.update_state!(Actions::SaveStream.new(stream_id))
end
@@ -7,7 +7,7 @@ module SpeckleConnector
module Commands
# Command to send selection to Speckle Server.
class SendSelection < Command
def _run(data)
def _run(_resolve_id, data)
stream_id = data['stream_id']
action = Actions::SendSelection.new(stream_id)
app.update_state!(action)
@@ -3,6 +3,8 @@
require_relative 'menu_command_handler'
require_relative 'action_command'
require_relative 'initialize_speckle'
require_relative 'initialize_dui3_speckle'
require_relative 'reset_window_location'
require_relative '../actions/one_click_send'
module SpeckleConnector
@@ -10,6 +12,8 @@ module SpeckleConnector
# Speckle menu commands that adds them to Sketchup menu and toolbar.
class SpeckleMenuCommands
CMD_INITIALIZE_SPECKLE = :initialize_speckle
CMD_INITIALIZE_DUI3_SPECKLE = :initialize_dui3_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,6 +30,13 @@ module SpeckleConnector
commands.add_to_menu!(CMD_INITIALIZE_SPECKLE, speckle_menu)
commands.add_to_toolbar!(CMD_INITIALIZE_SPECKLE, speckle_toolbar)
commands[CMD_INITIALIZE_DUI3_SPECKLE] = initialize_dui3_speckle_command(app)
commands.add_to_menu!(CMD_INITIALIZE_DUI3_SPECKLE, speckle_menu)
commands.add_to_toolbar!(CMD_INITIALIZE_DUI3_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)
# 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)
@@ -33,7 +44,7 @@ module SpeckleConnector
def self.initialize_speckle_command(app)
cmd = MenuCommandHandler.sketchup_command(
InitializeSpeckle.new(app), 'Initialize Speckle'
InitializeSpeckle.new(app, nil), 'Initialize Speckle'
)
cmd.tooltip = 'Launch Connector'
cmd.status_bar_text = 'Opens the Speckle Connector window'
@@ -42,9 +53,31 @@ module SpeckleConnector
cmd
end
def self.initialize_dui3_speckle_command(app)
cmd = MenuCommandHandler.sketchup_command(
InitializeDUI3Speckle.new(app, nil), 'Initialize DUI3 Speckle'
)
cmd.tooltip = 'Launch Connector with DUI3'
cmd.status_bar_text = 'Opens the Speckle Connector DUI3 Window'
cmd.small_icon = '../../img/s2logo_dui3.png'
cmd.large_icon = '../../img/s2logo_dui3.png'
cmd
end
def self.reset_window_location_command(app)
cmd = MenuCommandHandler.sketchup_command(
ResetWindowLocation.new(app, nil), 'Reset Window Location'
)
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
def self.send_command(app)
cmd = MenuCommandHandler.sketchup_command(
ActionCommand.new(app, Actions::OneClickSend), 'Send to Speckle'
ActionCommand.new(app, nil, Actions::OneClickSend), 'Send to Speckle'
)
cmd.tooltip = 'Send to Speckle'
cmd.status_bar_text = 'Send to Speckle'
@@ -8,7 +8,7 @@ module SpeckleConnector
module Commands
# Command to update preferences.
class UserPreferencesUpdated < Command
def _run(data)
def _run(_resolve_id, data)
preference_hash = data['preference_hash']
preference = data['preference']
new_value = data['value']
@@ -2,6 +2,12 @@
module SpeckleConnector
SPECKLE_BASE_OBJECT = 'Speckle_Base_Object'
SPECKLE_MAPPING_TOOL_SCHEMA = 'Speckle_Mapping_Tool_Schema'
SPECKLE_SCHEMA = 'Speckle_Schema'
SPECKLE_SEND_CARDS = 'Speckle_Send_Cards'
SPECKLE_RECEIVE_CARDS = 'Speckle_Receive_Cards'
SPECKLE_ID = 'speckle_id'
SPECKLE_TYPE = 'speckle_type'
APPLICATION_ID = 'application_id'
@@ -0,0 +1,5 @@
# frozen_string_literal: true
module SpeckleConnector
VECTOR_Z = Geom::Vector3d.new(0, 0, 1)
end
@@ -4,4 +4,5 @@ module SpeckleConnector
APP_OBSERVER = 'SpeckleConnector::Observers::AppObserver'
ENTITIES_OBSERVER = 'SpeckleConnector::Observers::EntitiesObserver'
MODEL_OBSERVER = 'SpeckleConnector::Observers::ModelObserver'
SELECTION_OBSERVER = 'SpeckleConnector::Observers::SelectionObserver'
end
@@ -14,7 +14,7 @@ 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')
File.join(Dir.home, '.config/Speckle')
else
raise 'Speckle could not determine your Appdata path'
end
@@ -11,6 +11,13 @@ module SpeckleConnector
INCLUDE_COMPONENT_ENTITY_ATTRIBUTES = :include_component_entity_attributes
MERGE_COPLANAR_FACES = :merge_coplanar_faces
ENTITY_KEYS_FOR_INCLUDING_ATTRIBUTES = {
Sketchup::ComponentInstance => INCLUDE_COMPONENT_ENTITY_ATTRIBUTES,
Sketchup::Group => INCLUDE_GROUP_ENTITY_ATTRIBUTES,
Sketchup::Face => INCLUDE_FACE_ENTITY_ATTRIBUTES,
Sketchup::Edge => INCLUDE_EDGE_ENTITY_ATTRIBUTES
}.freeze
LEVEL_SHIFT_VALUE = SpeckleObjects::Geometry.length_to_native(1.5, 'm')
DEFAULT_MODEL_PREFERENCES = {
@@ -3,10 +3,35 @@
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_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'
@@ -16,4 +41,9 @@ module SpeckleConnector
OBJECTS_OTHER_REVIT_REVITINSTANCE = 'Objects.Other.Revit.RevitInstance'
OBJECTS_OTHER_BLOCKDEFINITION = 'Objects.Other.BlockDefinition'
OBJECTS_OTHER_RENDERMATERIAL = 'Objects.Other.RenderMaterial'
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
@@ -228,6 +228,8 @@ module SpeckleConnector
return false unless is_array && value.length == 2
return false if value[1].nil?
value[1].all? { |v| v.is_a?(Sketchup::Entity) }
end
@@ -308,8 +310,12 @@ module SpeckleConnector
Digest::MD5.hexdigest(traversed_base.to_json)
end
def batch_objects
@objects
end
# rubocop:disable Metrics/MethodLength
def batch_objects(max_batch_size_mb = 1)
def batch_json_objects(max_batch_size_mb = 1)
max_size = 1000 * 1000 * max_batch_size_mb
batches = []
batch = '['
+35 -25
View File
@@ -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)
@@ -21,6 +21,8 @@ module SpeckleConnector
attr_accessor :definitions
# @param state [States::State] the current state of the {SpeckleConnector::App}
def initialize(state, stream_id)
@state = state
+137 -150
View File
@@ -2,16 +2,26 @@
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'
require_relative '../speckle_objects/other/block_instance'
require_relative '../speckle_objects/other/display_value'
require_relative '../speckle_objects/other/revit/revit_instance'
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
module Converters
@@ -24,31 +34,49 @@ 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
GEOMETRY = SpeckleObjects::Geometry
OTHER = SpeckleObjects::Other
REVIT = SpeckleObjects::Revit
BUILTELEMENTS = SpeckleObjects::BuiltElements
GIS = SpeckleObjects::GIS
# 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 = OTHER::Revit::RevitInstance
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
@@ -56,44 +84,92 @@ module SpeckleConnector
Objects.Other.BlockDefinition
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
def from_qgis
@from_qgis ||= source_app.include?('qgis')
end
# ReceiveObjects action call this method by giving everything that comes from server.
# Upcoming object is a referencedObject of selected commit to receive.
# 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.
filtered_layer_containers = obj.keys.filter_map { |key| key if key.start_with?('@') && key != '@Named Views' }
create_layers(filtered_layer_containers, sketchup_model.layers) unless from_revit
# Convert views to sketchup scenes
SpeckleObjects::BuiltElements::View3d.to_native(obj, sketchup_model)
# Get default commit layer from sketchup model which will be used as fallback
unless from_revit
# Create layers and it's folders from layers relation on the model collection.
SpeckleObjects::Relations::Layers.to_native(obj, source_app, sketchup_model)
end
# By default entities to fill is sketchup model's entities.
@entities_to_fill = sketchup_model.entities
# Navigate to branch entities if commit doesn't come from sketchup
unless from_sketchup
@branch_definition = branch_definition
@entities_to_fill = @branch_definition.entities
end
default_commit_layer = sketchup_model.layers.layers.find { |layer| layer.display_name == '@Untagged' }
@entities_to_fill = entities_to_fill(obj)
traverse_commit_object(obj, sketchup_model.layers, default_commit_layer, @entities_to_fill)
traverse_commit_object(obj, default_commit_layer, @entities_to_fill)
create_levels_from_section_planes
check_hiding_layers_needed
try_create_instance
@state
end
# Creating instance from @branch_definition only available for non-sketchup commits since we wrap commits
# under instance.
# There is also another use case that maybe definition is exist in file but user might be deleted it before.
# If this is the case we can add instance by checking number of instances.
# rubocop:disable Style/GuardClause
def try_create_instance
if !from_sketchup && (!@is_update_commit || @branch_definition.instances.empty?)
instance = sketchup_model.entities.add_instance(@branch_definition, Geom::Transformation.new)
BLOCK_INSTANCE.align_instance_axes(instance) if from_qgis
end
end
# rubocop:enable Style/GuardClause
def levels_layer
@levels_layer ||= sketchup_model.layers.add('Levels')
end
def clear_levels
instances = @entities_to_fill.grep(Sketchup::ComponentInstance)
instances.each do |instance|
speckle_type = instance.get_attribute(SPECKLE_BASE_OBJECT, 'speckle_type')
next if speckle_type.nil?
sketchup_model.definitions.remove(instance.definition) if speckle_type == OBJECTS_BUILTELEMENTS_REVIT_LEVEL
end
end
# Create levels from section planes that already created for this commit object.
# rubocop:disable Metrics/AbcSize
# rubocop:disable Metrics/MethodLength
def create_levels_from_section_planes
clear_levels if @is_update_commit
return unless from_revit
section_planes = @entities_to_fill.grep(Sketchup::SectionPlane)
@@ -105,7 +181,9 @@ module SpeckleConnector
section_planes.each do |section_plane|
level_name = "#{@definition_name}-#{section_plane.name}"
definition = sketchup_model.definitions.add(level_name)
@entities_to_fill.add_instance(definition, Geom::Transformation.new)
instance = @entities_to_fill.add_instance(definition, Geom::Transformation.new)
att = section_plane.attribute_dictionary(SPECKLE_BASE_OBJECT).to_h
SketchupModel::Dictionary::SpeckleEntityDictionaryHandler.set_hash(instance, att)
elevation = section_plane.bounds.center.z
c1_e = Geom::Point3d.new(c_1.x, c_1.y, elevation - LEVEL_SHIFT_VALUE)
c2_e = Geom::Point3d.new(c_2.x, c_2.y, elevation - LEVEL_SHIFT_VALUE)
@@ -122,8 +200,17 @@ module SpeckleConnector
# rubocop:enable Metrics/AbcSize
# rubocop:enable Metrics/MethodLength
# @return [Sketchup::ComponentDefinition] branch definition to fill objects in it.
def branch_definition
@definition_name = "#{@branch_name}-#{@stream_name}"
definition = sketchup_model.definitions.find { |d| d.name == @definition_name }
@is_update_commit = !definition.nil?
definition = sketchup_model.definitions.add(@definition_name) if definition.nil?
definition
end
def entities_to_fill(_obj)
return sketchup_model.entities if from_sketchup
return sketchup_model.entities unless from_revit
@definition_name = "#{@branch_name}-#{@stream_name}"
definition = sketchup_model.definitions.find { |d| d.name == @definition_name }
@@ -131,7 +218,7 @@ module SpeckleConnector
definition = sketchup_model.definitions.add(@definition_name)
sketchup_model.entities.add_instance(definition, Geom::Transformation.new)
end
definition.entities
definition
end
LAYERS_WILL_BE_HIDDEN = [
@@ -169,82 +256,14 @@ module SpeckleConnector
['Objects.BuiltElements.Revit.Parameter'].include?(obj['speckle_type'])
end
# Create actual Sketchup layers from layer_paths that taken from Speckle base object.
# @param layer_paths [Array<String>] layer paths to decompose it to folders and it's layers.
# @param folder [Sketchup::Layers, Sketchup::LayerFolder] folder to create folders and layers under it.
def create_layers(layer_paths, folder)
# Strip leading '@'
layers_with_folders = layer_paths.map { |layer| layer[1..-1] }
# Split layer_paths according to having parent folder or not.
layers_with_head_folder, headless_layers = layers_with_folders.partition { |layer| layer.include?('::') }
# Create array of array that split with '::'
folder_layer_arrays = layers_with_head_folder.collect { |folder_layer| folder_layer.split('::') }
# Add headless layers into `Sketchup.active_model.layers`
create_headless_layers(headless_layers, folder)
# Create layers that have parent folder(s)- this method is recursive until all tree is created.
create_folder_layers(folder_layer_arrays, folder)
end
# @param page [Sketchup::Page] scene to update -update properties-
def set_page_update_properties(page, update_properties)
update_properties.each do |prop, value|
page.instance_variable_set(:"@#{prop}", value)
end
end
# @param rendering_options [Sketchup::RenderingOptions] rendering options of scene (page)
def set_rendering_options(rendering_options, speckle_rendering_options)
speckle_rendering_options.each do |prop, value|
next if rendering_options[prop].nil?
rendering_options[prop] = if value.is_a?(Hash)
SpeckleObjects::Others::Color.to_native(value)
else
value
end
end
end
# @param headless_layers [Array<String>] headless layer names.
# @param folder [Sketchup::Layers, Sketchup::LayerFolder] layer folder to create commit layers under it.
def create_headless_layers(headless_layers, folder)
headless_layers.each do |layer_name|
# Add layer first to the layers object of sketchup model.
layer = sketchup_model.layers.add(layer_name)
folder.add_layer(layer) unless folder.layers.any? { |l| l.display_name == layer_name }
end
end
# Create layers with it's parent folders.
# @param folder [Sketchup::LayerFolder] layer folder to create commit layers under it.
def create_folder_layers(folder_layer_arrays, folder)
folder_layer_arrays.each do |folder_layer_array|
create_folder_layer(folder_layer_array, folder)
end
end
# Create layers that have parent folder(s)- this method is recursive (self-caller) until all tree is created.
def create_folder_layer(folder_array, folder)
if folder_array.length > 1
# add folder if it is not exist.
folder.add_folder(folder_array[0]) unless folder.folders.any? { |f| f.display_name == folder_array[0] }
new_folder = folder.folders.find { |f| f.display_name == folder_array[0] }
create_folder_layer(folder_array[1..-1], new_folder)
else
# Add layer first to the layers object of sketchup model.
layer = sketchup_model.layers.add(folder_array[0])
folder.add_layer(layer) unless folder.layers.any? { |l| l.display_name == layer }
end
end
# Traversal method to create Sketchup objects from upcoming base object.
# @param obj [Hash, Array] object might be source base object or it's sub objects, because this method is a
# self-caller method means that call itself according to conditions inside of it.
# rubocop:disable Metrics/CyclomaticComplexity
# rubocop:disable Metrics/PerceivedComplexity
def traverse_commit_object(obj, commit_folder, layer, entities)
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)
@@ -252,57 +271,23 @@ module SpeckleConnector
# puts(">>> Found #{obj['speckle_type']}: #{obj['id']}. Continuing traversal.")
props = obj.keys.filter_map { |key| key unless key.start_with?('_') }
props.each do |prop|
layer_path = prop if prop.start_with?('@') && obj[prop].is_a?(Array)
layer = find_layer(layer_path, commit_folder, layer)
traverse_commit_object(obj[prop], commit_folder, layer, entities)
traverse_commit_object(obj[prop], layer, entities)
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, commit_folder, layer, entities) }
obj.each_value { |value| traverse_commit_object(value, layer, entities) }
elsif obj.is_a?(Array)
obj.each { |value| traverse_commit_object(value, commit_folder, layer, entities) }
obj.each { |value| traverse_commit_object(value, layer, entities) }
end
end
# rubocop:enable Metrics/CyclomaticComplexity
# rubocop:enable Metrics/PerceivedComplexity
# Find layer of the Speckle object by checking iteratively into folder.
# @param layer_path [String] complete layer_path to retrieve
# @param folder [Sketchup::LayerFolder, Sketchup::Layers] entry folder to search layer
# @param fallback_layer [Sketchup::Layer] fallback layer to assign object later if any error occur.
# @return [Sketchup::Layer] layer according to path
# @example
# "@folder_1::folder_2::layer_1"
# # it will return the layer object which has display name as `layer_1`.
def find_layer(layer_path, folder, fallback_layer)
begin
# Split folders and it's tail layer (last one is layer, others are folders.)
layer_path_array = layer_path[1..-1].split('::')
# Get sub folders as array, might be empty if `layer_path_array` has only 1 entry
sub_folders = layer_path_array.length > 1 ? layer_path_array[0..-2] : []
# Get exact layer name from last entry
layer_name = layer_path_array.last
# Iterate sub folders to find new sub folder to switch it.
# It help to search in the tree by switching the target search folder.
# Finally we can reach the layer name.
sub_folders.each do |sub_folder|
# Try to find sub folder into source folder passes by argument
s_f = folder.folders.find { |f| f.display_name == sub_folder }
# Switch source folder if any exist
folder = s_f unless s_f.nil?
end
# Find finally the layer into related folder
folder.layers.find { |l| l.display_name == layer_name }
rescue StandardError
return fallback_layer
end
end
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
@@ -310,13 +295,25 @@ 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),
OBJECTS_OTHER_BLOCKINSTANCE => BLOCK_INSTANCE.method(:to_native),
OBJECTS_OTHER_BLOCKINSTANCE_FULL => BLOCK_INSTANCE.method(:to_native),
OBJECTS_OTHER_REVIT_REVITINSTANCE => REVIT_INSTANCE.method(:to_native),
OBJECTS_OTHER_RENDERMATERIAL => RENDER_MATERIAL.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),
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
@@ -328,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)
@@ -335,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
@@ -349,13 +348,13 @@ module SpeckleConnector
layer = sketchup_model.layers.find { |l| l.display_name == speckle_object['category'] }
unless layer.nil?
entities.each { |entity| entity.layer = layer } if layer
entities.each { |entity| entity.layer = layer if entity.respond_to?(:layer) } if layer
return state
end
layer = sketchup_model.layers.add(speckle_object['category'])
unless layer.nil?
entities.each { |entity| entity.layer = layer } if layer
entities.each { |entity| entity.layer = layer if entity.respond_to?(:layer) } if layer
state
end
state
@@ -365,39 +364,27 @@ module SpeckleConnector
# @param state [States::State] state of the speckle application
def create_levels(state, speckle_object)
return state if speckle_object['level'].nil?
return state unless speckle_object['level']['speckle_type'].include?('Objects.BuiltElements.Level')
level = speckle_object['level']
return state if level.nil?
return state unless level['speckle_type'].include?('Objects.BuiltElements.Level')
level_name = speckle_object['level']['name'] || speckle_object['level']['id']
level_name = level['name'] || level['id']
is_exist = @entities_to_fill.grep(Sketchup::SectionPlane).any? { |sp| sp.name == level_name }
return state if is_exist
elevation = SpeckleObjects::Geometry.length_to_native(speckle_object['level']['elevation'],
speckle_object['level']['units'])
elevation = SpeckleObjects::Geometry.length_to_native(level['elevation'], level['units'])
section_plane = @entities_to_fill.add_section_plane([0, 0, elevation + LEVEL_SHIFT_VALUE], [0, 0, -1])
section_plane.name = level_name
SketchupModel::Dictionary::SpeckleEntityDictionaryHandler.write_initial_base_data(
section_plane, level['applicationId'], level['id'], level['speckle_type'], [], @stream_id
)
state
end
# @param state [States::State] state of the application
def convert_to_speckle_entities(state, speckle_object, entities)
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)
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
end
# rubocop:enable Metrics/ClassLength
+63 -142
View File
@@ -10,63 +10,59 @@ require_relative '../speckle_objects/other/block_instance'
require_relative '../speckle_objects/other/block_definition'
require_relative '../speckle_objects/other/rendering_options'
require_relative '../speckle_objects/built_elements/view3d'
require_relative '../speckle_objects/built_elements/revit/direct_shape'
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'
require_relative '../ext/TT_Lib2/progressbar'
require_relative '../ext/TT_Lib2/model'
require_relative '../ext/TT_Lib2/entities'
module SpeckleConnector
module Converters
# Converts sketchup entities to speckle objects.
class ToSpeckle < Converter
MODEL_COLLECTION = SpeckleObjects::Speckle::Core::Models::ModelCollection
DIRECT_SHAPE = SpeckleObjects::BuiltElements::Revit::DirectShape
SPECKLE_ENTITIES_READER = SketchupModel::Reader::SpeckleEntitiesReader
VIEW3D = SpeckleObjects::BuiltElements::View3d
# @return [TT::ProgressBar]
attr_reader :progress_bar
attr_reader :entity_count
attr_reader :send_filter
attr_reader :worker
attr_writer :count
def initialize(state, stream_id, send_filter)
super(state, stream_id)
@count = 0
@send_filter = send_filter
model = state.sketchup_state.sketchup_model
@entity_count = if send_filter.name == 'Selection'
TT::Model.count_unique_entity(model)
else
TT::Entities.count_unique_entity(model.selection)
end
@progress_bar = TT::Progressbar.new(@entity_count, 'Converting to Speckle')
end
# Convert selected objects by putting them into related array that grouped by layer.
# @return [Hash{Symbol=>Array}] layers -which only have objects- to hold it's objects under the base object.
def convert_selection_to_base(preferences)
layers = add_all_layers
state = speckle_state
sketchup_model.selection.each do |entity|
new_speckle_state, converted_object_with_entity = convert(entity, preferences, state)
state = new_speckle_state
layer_name = entity_layer_path(entity)
layers[layer_name].push(converted_object_with_entity)
end
# send only+ layers that have any object
base_object_properties = layers.reject { |_layer_name, objects| objects.empty? }
add_views(base_object_properties) if sketchup_model.pages.any?
return state, SpeckleObjects::Base.with_detached_layers(base_object_properties)
end
convert = method(:convert)
# Add views from pages.
# @param base_object_properties [Hash] dynamically attached base object properties.
def add_views(base_object_properties)
views = []
sketchup_model.pages.each do |page|
cam = page.camera
origin = get_camera_origin(cam)
target = get_camera_target(cam)
direction = get_camera_direction(cam)
update_properties = get_scene_update_properties(page)
rendering_options = SpeckleObjects::Others::RenderingOptions.to_speckle(page.rendering_options)
view = SpeckleObjects::BuiltElements::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
)
views.append(view)
end
base_object_properties['@Named Views'] = views
end
new_speckle_state, model_collection = MODEL_COLLECTION.from_sketchup_model(sketchup_model, speckle_state,
@units, preferences, state, @stream_id, &convert)
# Get scene properties
# @param page [Sketchup::Page] page on sketchup.
def get_scene_update_properties(page)
{
use_axes: page.use_axes?,
use_camera: page.use_camera?,
use_hidden_geometry: page.use_hidden_geometry?,
use_hidden_layers: page.use_hidden_layers?,
use_hidden_objects: page.use_hidden_objects?,
use_rendering_options: page.use_rendering_options?,
use_section_planes: page.use_section_planes?,
use_shadow_info: page.use_shadow_info?,
use_style: page.use_style?
}
return new_speckle_state, model_collection
end
# Serialized and traversed information to send batches.
@@ -76,7 +72,7 @@ module SpeckleConnector
serializer = SpeckleConnector::Converters::BaseObjectSerializer.new(speckle_state, stream_id, preferences)
t = Time.now.to_f
id = serializer.serialize(base_and_entity)
batches = serializer.batch_objects
batches = serializer.batch_json_objects
# write_to_speckle_folder(id, batches)
puts "Generating traversed object elapsed #{Time.now.to_f - t} s"
base_total_children_count = serializer.total_children_count(id)
@@ -93,17 +89,29 @@ module SpeckleConnector
# @param entity [Sketchup::Entity] sketchup entity to convert Speckle.
# @param speckle_state [States::SpeckleState] the current speckle state of the {States::State}
# @param parent [Symbol, String] parent of the Sketchup Entity to be converted.
# rubocop:disable Metrics/MethodLength
def convert(entity, preferences, speckle_state, parent = :base)
progress_bar.next
convert = method(:convert)
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
# 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(entity, @units, preferences[:model])
mesh = SpeckleObjects::Geometry::Mesh.from_face(speckle_state: speckle_state, face: entity, units: @units,
model_preferences: preferences[:model])
return speckle_state, [mesh, [entity]]
end
@@ -124,9 +132,13 @@ module SpeckleConnector
end
if entity.is_a?(Sketchup::ComponentDefinition)
# Local caching
return speckle_state, [definitions[entity.guid], [entity]] if definitions.key?(entity.guid)
new_speckle_state, block_definition = SpeckleObjects::Other::BlockDefinition.from_definition(
entity, @units, @definitions, preferences, speckle_state, parent, &convert
entity, @units, preferences, speckle_state, parent, &convert
)
definitions[entity.guid] = block_definition
speckle_state = new_speckle_state
return speckle_state, [block_definition, [entity]]
end
@@ -134,97 +146,6 @@ module SpeckleConnector
return speckle_state, nil
end
# rubocop:enable Metrics/MethodLength
# Create layers -> {Hash{Symbol=>Array}} from sketchup model with empty array as hash entry values.
# This method add first headless layers (not belong to any folder),
# then goes through each folder, their sub-folders and their layers.
# @return [Hash{Symbol=>Array}] layers from sketchup model with empty array as hash entry values.
def add_all_layers
# add headless layers
layer_objects = add_layers(sketchup_model.layers.layers)
# add layers from folders
add_layers_from_folders(sketchup_model.layers.folders, layer_objects)
layer_objects
end
# @param layers [Array<Sketchup::Layer>] layers in sketchup model
# @return [Hash{Symbol=>Array}] layers with empty array value.
def add_layers(layers, layer_objects = {}, parent_name = '')
layers.each do |layer|
layer_name = parent_name.empty? ? "@#{layer.display_name}" : "#{parent_name}::#{layer.display_name}"
layer_objects[layer_name] = []
end
layer_objects
end
# @param folders [Array<Sketchup::LayerFolder>] layer folders in sketchup model.
# @param layer_objects [Hash{Symbol=>Array}] layer objects to fill in.
# @param parent_name [String] parent folder name to structure layer path before send to Speckle.
# ex: "@#{parent_name}::#{layer_name}"
def add_layers_from_folders(folders, layer_objects, parent_name = '')
folders.each do |folder|
folder_name = parent_name.empty? ? "@#{folder.display_name}" : "#{parent_name}::#{folder.display_name}"
add_layers(folder.layers, layer_objects, folder_name)
add_layers_from_folders(folder.folders, layer_objects, folder_name) unless folder.folders.empty?
end
end
# Find layer path of given Sketchup entity.
# @param entity [Sketchup::Entity] entity to find root layer.
# @return [String] layer path of Sketchup entity.
def entity_layer_path(entity)
layer_name = entity.layer.display_name
if entity.layer.folder.nil?
"@#{layer_name}"
else
folders = folder_name(entity.layer.folder)
path = ''
folders.reverse.each do |folder|
path += "#{folder}::"
end
"@#{path}#{layer_name}"
end
end
# Nested method to retrieve sub-folders until nothing found.
# @return [Array<String>] folder names as list from bottom to top. Might need to be reversed if you want to see
# from top to bottom.
def folder_name(folder, folders = [])
if folder.folder.nil?
folders.push(folder.display_name)
else
folder_name(folder.folder, folders.push(folder.display_name))
end
end
private
def get_camera_direction(cam)
SpeckleObjects::Geometry::Vector.new(
SpeckleObjects::Geometry.length_to_speckle(cam.direction[0], @units),
SpeckleObjects::Geometry.length_to_speckle(cam.direction[1], @units),
SpeckleObjects::Geometry.length_to_speckle(cam.direction[2], @units),
@units
)
end
def get_camera_target(cam)
SpeckleObjects::Geometry::Point.new(
SpeckleObjects::Geometry.length_to_speckle(cam.target[0], @units),
SpeckleObjects::Geometry.length_to_speckle(cam.target[1], @units),
SpeckleObjects::Geometry.length_to_speckle(cam.target[2], @units),
@units
)
end
def get_camera_origin(camera)
SpeckleObjects::Geometry::Point.new(
SpeckleObjects::Geometry.length_to_speckle(camera.eye[0], @units),
SpeckleObjects::Geometry.length_to_speckle(camera.eye[1], @units),
SpeckleObjects::Geometry.length_to_speckle(camera.eye[2], @units),
@units
)
end
end
end
end

Some files were not shown because too many files have changed in this diff Show More