Compare commits

...

51 Commits

Author SHA1 Message Date
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
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 97309ebb88 Merge remote-tracking branch 'origin/development' 2023-09-19 08:31:29 +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 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
32 changed files with 770 additions and 169 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\/.*/
@@ -111,7 +111,7 @@ module SpeckleConnector
categories: Mapper::Category::RevitCategory.to_a,
types: types,
levels: levels,
selectedLevel: selected_level_name
selectedLevelName: selected_level_name
}.freeze
end
@@ -140,10 +140,10 @@ module SpeckleConnector
source_exist = !state.speckle_state.speckle_mapper_state.mapper_source.nil?
if source_exist
methods = ['Column', 'Beam', 'Brace', 'Pipe', 'Duct']
methods = ['Column', 'Beam', 'Pipe', 'Duct']
direct_shape_selection_info_with_source(state, edges, methods)
else
default_methods = ['Default Column', 'Default Beam', 'Default Brace', 'Default Pipe', 'Default Duct']
default_methods = ['Default Column', 'Default Beam', 'Default Pipe', 'Default Duct']
direct_shape_selection_info_with_default(edges, default_methods)
end
end
@@ -38,6 +38,7 @@ module SpeckleConnector
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
@@ -3,6 +3,7 @@
require_relative 'action'
require_relative '../convertors/units'
require_relative '../convertors/to_native'
require_relative '../convertors/clean_up'
module SpeckleConnector
module Actions
@@ -26,7 +27,12 @@ module SpeckleConnector
converter = Converters::ToNative.new(state, @stream_id, @stream_name, @branch_name, @source_app)
# Have side effects on the sketchup model. It effects directly on the entities by adding new objects.
start_time = Time.now.to_f
state.sketchup_state.sketchup_model.start_operation('Receive Speckle Objects', true)
state = converter.receive_commit_object(@base)
if state.user_state.model_preferences[:merge_coplanar_faces]
Converters::CleanUp.merge_coplanar_faces(converter.converted_faces)
end
state.sketchup_state.sketchup_model.commit_operation
elapsed_time = (Time.now.to_f - start_time).round(3)
puts "==== Converting to Native executed in #{elapsed_time} sec ===="
puts "==== Source application is #{@source_app}. ===="
@@ -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
@@ -7,12 +7,14 @@ module SpeckleConnector
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_FLOOR = 'Objects.BuiltElements.Floor:Objects.BuiltElements.Revit.RevitFloor'
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_REVIT_DIRECTSHAPE = 'Objects.BuiltElements.Revit.DirectShape'
OBJECTS_BUILTELEMENTS_REVIT_PARAMETER = 'Objects.BuiltElements.Revit.Parameter'
OBJECTS_BUILTELEMENTS_REVIT_REVITELEMENTTYPE = 'Objects.BuiltElements.Revit.RevitElementType'
OBJECTS_BUILTELEMENTS_REVIT_LEVEL = 'Objects.BuiltElements.Level:Objects.BuiltElements.Revit.RevitLevel'
OBJECTS_GEOMETRY_LINE = 'Objects.Geometry.Line'
OBJECTS_GEOMETRY_POLYLINE = 'Objects.Geometry.Polyline'
+22 -19
View File
@@ -11,9 +11,10 @@ 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) }
@@ -22,6 +23,22 @@ module SpeckleConnector
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
def self.merged_faces(faces)
faces.reject(&:deleted?)
end
@@ -35,43 +52,29 @@ 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 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)
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)
edge.erase!
true
end
# rubocop:enable Metrics/AbcSize
# Determines if two faces are overlapped.
def self.face_duplicate?(face_1, face_2, overlapping: false)
@@ -32,11 +32,14 @@ module SpeckleConnector
# @return [String] source application of received object that will be converted to native
attr_reader :source_app
attr_reader :converted_faces
def initialize(state, stream_id, stream_name, branch_name, source_app)
super(state, stream_id)
@stream_name = stream_name
@branch_name = branch_name
@source_app = source_app.downcase
@converted_faces = []
end
# Module aliases
@@ -56,6 +59,7 @@ module SpeckleConnector
BLOCK_DEFINITION = OTHER::BlockDefinition
BLOCK_INSTANCE = OTHER::BlockInstance
REVIT_INSTANCE = REVIT::Other::RevitInstance
REVIT_WALL = BUILTELEMENTS::RevitWall
RENDER_MATERIAL = OTHER::RenderMaterial
DISPLAY_VALUE = OTHER::DisplayValue
VIEW3D = BUILTELEMENTS::View3d
@@ -77,6 +81,7 @@ module SpeckleConnector
Objects.Other.RenderMaterial
Objects.Other.Instance:Objects.Other.BlockInstance
Objects.BuiltElements.View:Objects.BuiltElements.View3D
Objects.BuiltElements.Wall:Objects.BuiltElements.Revit.RevitWall
Objects.BuiltElements.Network
Objects.GIS.PolygonElement
Speckle.Core.Models.Collection
@@ -294,6 +299,7 @@ module SpeckleConnector
OBJECTS_OTHER_REVIT_REVITINSTANCE => REVIT_INSTANCE.method(:to_native),
OBJECTS_OTHER_RENDERMATERIAL => RENDER_MATERIAL.method(:to_native),
OBJECTS_BUILTELEMENTS_VIEW3D => VIEW3D.method(:to_native),
OBJECTS_BUILTELEMENTS_REVIT_WALL => REVIT_WALL.method(:to_native),
OBJECTS_BUILTELEMENTS_REVIT_DIRECTSHAPE => BUILTELEMENTS::Revit::DirectShape.method(:to_native),
OBJECTS_BUILTELEMENTS_NETWORK => BUILTELEMENTS::Network.method(:to_native),
OBJECTS_GIS_POLYGONELEMENT => POLYGON_ELEMENT.method(:to_native),
@@ -309,6 +315,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)
Binary file not shown.
+14 -2
View File
@@ -1,7 +1,9 @@
# frozen_string_literal: true
require_relative '../speckle_objects/built_elements/floor'
require_relative '../speckle_objects/built_elements/revit/revit_floor'
require_relative '../speckle_objects/built_elements/revit/revit_wall'
require_relative '../speckle_objects/built_elements/default_floor'
require_relative '../speckle_objects/built_elements/default_wall'
require_relative '../sketchup_model/query/entity'
require_relative '../sketchup_model/reader/mapper_reader'
require_relative '../sketchup_model/dictionary/speckle_schema_dictionary_handler'
@@ -39,7 +41,17 @@ module SpeckleConnector
end
if speckle_schema['method'] == 'Floor'
return SpeckleObjects::BuiltElements::Floor
return SpeckleObjects::BuiltElements::RevitFloor
.to_speckle_schema(speckle_state, entity, units, global_transformation: global_transformation)
end
if speckle_schema['method'] == 'Default Wall'
return SpeckleObjects::BuiltElements::DefaultWall
.to_speckle_schema(entity, units, global_transformation: global_transformation)
end
if speckle_schema['method'] == 'Wall'
return SpeckleObjects::BuiltElements::RevitWall
.to_speckle_schema(speckle_state, entity, units, global_transformation: global_transformation)
end
@@ -12,9 +12,9 @@ module SpeckleConnector
include Immutable::ImmutableUtils
DICT_HANDLER = SketchupModel::Dictionary::SpeckleModelDictionaryHandler
# rubocop:disable Layout/LineLength
DEFAULT_CONFIG = "('configSketchup', '{\"dark_theme\":false, \"diffing\":false, \"register_speckle_entity\":false}');"
DEFAULT_CONFIG = "('configSketchup', '{\"dark_theme\":false, \"diffing\":false, \"register_speckle_entity\":false, \"fe2\":false}');"
# rubocop:enable Layout/LineLength
DEFAULT_PREFERENCES = '{"dark_theme":false, "diffing":false, "register_speckle_entity": false}'
DEFAULT_PREFERENCES = '{"dark_theme":false, "diffing":false, "register_speckle_entity": false, "fe2": false}'
# @param sketchup_model [Sketchup::Model] active model.
def self.read_preferences(sketchup_model)
@@ -34,10 +34,16 @@ module SpeckleConnector
def self.data_complete?(row_data)
return false if row_data.empty?
data = JSON.parse(row_data.first.first)
return false if data['dark_theme'].nil? || data['diffing'].nil? || data['register_speckle_entity'].nil?
begin
data = JSON.parse(row_data.first.first)
if data['dark_theme'].nil? || data['fe2'].nil? || data['diffing'].nil? || data['register_speckle_entity'].nil?
return false
end
true
true
rescue StandardError
false
end
end
# Validates current preferences. If there are incomplete data then this method resets it with default preferences.
@@ -65,11 +71,13 @@ module SpeckleConnector
data_hash = JSON.parse(row_data).to_h
# Get current theme value
dark_theme = data_hash['dark_theme']
fe2 = data_hash['fe2']
diffing = data_hash['diffing']
register_speckle_entity = data_hash['register_speckle_entity']
{
dark_theme: dark_theme,
fe2: fe2,
diffing: diffing,
register_speckle_entity: register_speckle_entity
}.freeze
@@ -27,14 +27,11 @@ module SpeckleConnector
adj_faces.uniq
end
# @param face [Sketchup::Face] face to check whether is vertical or not.
def self.vertical?(face)
face.normal.perpendicular?(VECTOR_Z)
end
# @param face [Sketchup::Face] face to check whether is horizontal or not.
def self.horizontal?(face)
face.normal.parallel?(VECTOR_Z)
# @param face [Sketchup::Face] face to get max z distance for all vertices.
def self.max_z(face)
points = face.vertices.collect(&:position)
points_z_values = points.collect(&:z)
points_z_values.max - points_z_values.min
end
end
end
@@ -136,6 +136,15 @@ module SpeckleConnector
next if (entity.is_a?(Sketchup::Face) || entity.is_a?(Sketchup::Edge)) &&
!state.user_state.user_preferences[:register_speckle_entity]
if entity.is_a?(Sketchup::ComponentDefinition)
definition = speckle_object['definition'] || speckle_object['@block_definition'] ||
speckle_object['block_definition']
if definition
speckle_id = definition['id']
speckle_type = definition['speckle_type']
end
end
ent = SpeckleEntity.new(entity, speckle_id, application_id, speckle_type, children, [stream_id])
ent.write_initial_base_data
speckle_state = speckle_state.with_speckle_entity(ent)
@@ -0,0 +1,52 @@
# frozen_string_literal: true
require_relative '../base'
require_relative '../built_elements/revit/parameter'
require_relative '../other/render_material'
require_relative '../geometry/length'
require_relative '../geometry/line'
require_relative '../geometry/polyline'
require_relative '../../constants/type_constants'
require_relative '../../sketchup_model/dictionary/speckle_schema_dictionary_handler'
require_relative '../../sketchup_model/utils/face_utils'
module SpeckleConnector
module SpeckleObjects
module BuiltElements
# Default Wall object.
class DefaultWall < Base
SPECKLE_TYPE = OBJECTS_BUILTELEMENTS_DEFAULT_WALL
def initialize(base_line:, height:, flipped:, units:, material:, application_id: nil)
super(
speckle_type: SPECKLE_TYPE,
total_children_count: 0,
application_id: application_id,
id: nil
)
self[:baseLine] = base_line
self[:height] = height
self[:flipped] = flipped
self[:units] = units
self[:renderMaterial] = material
end
# @param face [Sketchup::Face] face to get speckle schema for floor.
def self.to_speckle_schema(face, units, global_transformation: nil)
base_line = Geometry::Line.base_line_from_face(face, units, global_transformation: global_transformation)
material = face.material || face.back_material
DefaultWall.new(
base_line: base_line,
height: Geometry.length_to_speckle(SketchupModel::Utils::FaceUtils.max_z(face), units),
flipped: false,
units: units,
material: material.nil? ? nil : Other::RenderMaterial.from_material(face.material || face.back_material),
application_id: face.persistent_id
)
end
end
end
end
end
@@ -1,20 +1,21 @@
# frozen_string_literal: true
require_relative '../base'
require_relative '../built_elements/revit/parameter'
require_relative '../other/render_material'
require_relative '../geometry/line'
require_relative '../geometry/polyline'
require_relative '../../constants/type_constants'
require_relative '../../sketchup_model/dictionary/speckle_schema_dictionary_handler'
require_relative '../../base'
require_relative '../../built_elements/revit/parameter'
require_relative '../../other/render_material'
require_relative '../../geometry/line'
require_relative '../../geometry/polyline'
require_relative '../../../constants/type_constants'
require_relative '../../../sketchup_model/dictionary/speckle_schema_dictionary_handler'
module SpeckleConnector
module SpeckleObjects
module BuiltElements
# Floor object.
class Floor < Base
SPECKLE_TYPE = OBJECTS_BUILTELEMENTS_FLOOR
# Revit floor object.
class RevitFloor < Base
SPECKLE_TYPE = OBJECTS_BUILTELEMENTS_REVIT_FLOOR
# rubocop:disable Metrics/ParameterLists
def initialize(family:, type:, outline:, voids:, level:, units:, material:, parameters:nil, application_id: nil)
super(
speckle_type: SPECKLE_TYPE,
@@ -31,6 +32,7 @@ module SpeckleConnector
self[:parameters] = parameters
self[:renderMaterial] = material
end
# rubocop:enable Metrics/ParameterLists
# @param face [Sketchup::Face] face to get speckle schema for floor.
def self.to_speckle_schema(speckle_state, face, units, global_transformation: nil)
@@ -57,7 +59,7 @@ module SpeckleConnector
parameters['Height Offset From Level'] = offset_parameter
end
Floor.new(
RevitFloor.new(
family: schema['family'],
type: schema['family_type'],
outline: outline,
@@ -0,0 +1,102 @@
# frozen_string_literal: true
require_relative '../../base'
require_relative '../../built_elements/revit/parameter'
require_relative '../../other/render_material'
require_relative '../../geometry/line'
require_relative '../../geometry/length'
require_relative '../../../constants/type_constants'
require_relative '../../../sketchup_model/dictionary/speckle_schema_dictionary_handler'
require_relative '../../../sketchup_model/utils/face_utils'
module SpeckleConnector
module SpeckleObjects
module BuiltElements
# Revit wall object.
class RevitWall < Base
SPECKLE_TYPE = OBJECTS_BUILTELEMENTS_REVIT_WALL
# rubocop:disable Metrics/ParameterLists
def initialize(family:, type:, base_line:, height:, flipped:, level:, units:, material:, parameters: nil, application_id: nil)
super(
speckle_type: SPECKLE_TYPE,
total_children_count: 0,
application_id: application_id,
id: nil
)
self[:family] = family
self[:type] = type
self[:height] = height
self[:flipped] = flipped
self[:level] = level
self[:baseLine] = base_line
self[:units] = units
self[:parameters] = parameters
self[:renderMaterial] = material
end
# rubocop:enable Metrics/ParameterLists
def self.to_native(state, wall, layer, entities, &convert_to_native)
obj = Other::DisplayValue.collect_definition_geometries(wall)
obj['name'] = Other::DisplayValue.get_definition_name(obj)
state, _definitions = Other::BlockDefinition.to_native(
state, obj, layer, entities, &convert_to_native
)
definition = state.sketchup_state.sketchup_model.definitions[Other::BlockDefinition.get_definition_name(obj)]
Other::BlockInstance.find_and_erase_existing_instance(definition, obj['id'], obj['applicationId'])
t_arr = obj['transform']
transform = t_arr.nil? ? Geom::Transformation.new : Other::Transform.to_native(t_arr, obj['units'])
instance = entities.add_instance(definition, transform)
instance.name = Other::DisplayValue.get_instance_name(obj['name']) unless obj['name'].nil?
instance.layer = layer unless layer.nil?
# Align instance axes that created from display value. (without any transform)
# BlockInstance.align_instance_axes(instance)
return state, [instance, definition]
end
# @param face [Sketchup::Face] face to get speckle schema for wall.
def self.to_speckle_schema(speckle_state, face, units, global_transformation: nil)
base_line = Geometry::Line.base_line_from_face(face, units, global_transformation: global_transformation)
material = face.material || face.back_material
schema = SketchupModel::Dictionary::SpeckleSchemaDictionaryHandler.speckle_schema_to_speckle(face).to_h
source_exist = !speckle_state.speckle_mapper_state.mapper_source.nil?
level = nil
parameters = nil
if source_exist
level = speckle_state.speckle_mapper_state.mapper_source.levels.find { |l| l[:name] == schema['level'] }
parameters = Base.new
offset_parameter = BuiltElements::Revit::Parameter.new(name: 'Height Offset From Level')
level_z = Geometry.length_to_native(level[:elevation], level[:units])
min_z = face.vertices.collect(&:position).map(&:z).min
offset_parameter['value'] = Geometry.length_to_speckle(min_z - level_z, units)
offset_parameter['units'] = units
parameters['Height Offset From Level'] = offset_parameter
end
RevitWall.new(
family: schema['family'],
type: schema['family_type'],
base_line: base_line,
height: Geometry.length_to_speckle(SketchupModel::Utils::FaceUtils.max_z(face), units),
flipped: false,
level: level,
units: units,
parameters: parameters,
material: material.nil? ? nil : Other::RenderMaterial.from_material(face.material || face.back_material),
application_id: face.persistent_id
)
end
def self.get_wall_height(face, units)
points = face.vertices.collect(&:position)
points_z_values = points.collect(&:z)
Geometry.length_to_speckle(points_z_values.max - points_z_values.min, units)
end
end
end
end
end
@@ -40,7 +40,7 @@ module SpeckleConnector
# rubocop:enable Metrics/ParameterLists
# @param edge [Sketchup::Edge] edge to convert line.
def self.from_edge(edge, units, model_preferences)
def self.from_edge(edge, units, model_preferences, global_transformation: nil)
dictionaries = SketchupModel::Dictionary::BaseDictionaryHandler
.attribute_dictionaries_to_speckle(edge, model_preferences)
att = dictionaries.any? ? { dictionaries: dictionaries } : {}
@@ -60,6 +60,41 @@ module SpeckleConnector
)
end
# @param edge [Sketchup::Face] face to get base line from face.
def self.base_line_from_face(face, units, global_transformation: nil)
points = face.vertices.collect(&:position)
points_z_values = points.collect(&:z)
height = Geometry.length_to_speckle(points_z_values.max - points_z_values.min, units)
min_z = points_z_values.min
projected_points = points.map { |p| Geom::Point3d.new(p.x, p.y, min_z) }
distance_with_points = Struct.new(:distance, :point_1, :point_2)
lines_with_distances = []
projected_points.each do |p|
projected_points.each do |p_other|
next if p_other == p
lines_with_distances.append(distance_with_points.new(p.distance(p_other), p, p_other))
end
end
lines_with_distances.sort_by!(&:distance).reverse!
p_1 = lines_with_distances.first.point_1
p_2 = lines_with_distances.first.point_2
unless global_transformation.nil?
p_1 = p_1.transform!(global_transformation)
p_2 = p_2.transform!(global_transformation)
end
Line.new(
start_pt: Geometry::Point.from_vertex(p_1, units),
end_pt: Geometry::Point.from_vertex(p_2, units),
domain: Primitive::Interval.from_numeric(0, Geometry.length_to_speckle(p_1.distance(p_2), units), units),
units: units,
layer: SketchupModel::Query::Layer.entity_path(face),
sketchup_attributes: {},
speckle_schema: {},
application_id: face.persistent_id.to_s
)
end
# @param state [States::State] state of the application.
# @param line [Object] object represents Speckle line.
# @param layer [Sketchup::Layer] layer to add {Sketchup::Edge} into it.
@@ -121,9 +121,9 @@ module SpeckleConnector
mesh_layer_name = SketchupModel::Query::Layer.entity_layer_from_path(mesh['layer'])
mesh_layer = state.sketchup_state.sketchup_model.layers.to_a.find { |l| l.display_name == mesh_layer_name }
# Merge only added faces in this scope
if model_preferences[:merge_coplanar_faces]
added_faces = Converters::CleanUp.merge_coplanar_faces(added_faces)
end
# if model_preferences[:merge_coplanar_faces]
# added_faces = Converters::CleanUp.merge_coplanar_faces(added_faces)
# end
added_faces.each do |face|
face.layer = mesh_layer unless mesh_layer.nil?
# Smooth edges if they already soft
@@ -159,6 +159,7 @@ module SpeckleConnector
# rubocop:disable Metrics/CyclomaticComplexity
# rubocop:disable Metrics/PerceivedComplexity
def self.group_entities_to_speckle(entities, preferences, speckle_state, parent, &convert)
entities = entities.reject(&:hidden?)
orphan_edges = entities.grep(Sketchup::Edge).filter { |edge| edge.faces.none? }
lines = orphan_edges.collect do |orphan_edge|
new_speckle_state, converted = convert.call(orphan_edge, preferences, speckle_state, parent)
@@ -83,13 +83,19 @@ module SpeckleConnector
elements = obj['elements'] || obj['@elements']
if !elements.nil? && elements.is_a?(Array)
elements.each do |element|
# Mullions is a special case here, they are extracted as base object with @displayValue from revit..
if element['@displayValue'].nil?
obj['geometry'].append(element)
else
obj['geometry'] += element['@displayValue']
# if only elements are there then assign only elements, there are some cases that RevitWalls can only
# have elements instead of display value
if obj['geometry'].nil? && !elements.nil?
obj['geometry'] = elements
else
if !elements.nil? && elements.is_a?(Array)
elements.each do |element|
# Mullions is a special case here, they are extracted as base object with @displayValue from revit..
if element['@displayValue'].nil?
obj['geometry'].append(element)
else
obj['geometry'] += element['@displayValue']
end
end
end
end
@@ -15,8 +15,10 @@ module SpeckleConnector
family = def_obj['family']
type = def_obj['type']
category = def_obj['category']
element_id = def_obj['elementId']
id = def_obj['id']
return "#{family}-#{type}-#{category}-#{def_obj['elementId']}"
return "#{family}-#{type}-#{category}-#{element_id}-#{id}"
end
def self.to_native(state, definition, layer, entities, &convert_to_native)
@@ -66,6 +66,13 @@ module SpeckleConnector
def self.to_native(state, model_collection, layer, entities, &convert_to_native)
elements = model_collection['elements']
views = model_collection['@Views']
if views
views.each do |view|
new_state, _converted_entities = convert_to_native.call(state, view, layer, entities)
state = new_state
end
end
elements.each do |element|
new_state, _converted_entities = convert_to_native.call(state, element, layer, entities)
@@ -84,7 +91,7 @@ module SpeckleConnector
method = SPECKLE_SCHEMA_DICTIONARY_HANDLER.get_attribute(entity, 'method')
if method.include?('Floor') && entity.is_a?(Sketchup::Face)
if !method.nil? && (method.include?('Floor') || method.include?('Wall')) && entity.is_a?(Sketchup::Face)
global_transformation = QUERY::Entity.global_transformation(entity, path)
floor = SpeckleObjects::Geometry::Mesh.from_face(speckle_state: speckle_state, face: entity,
units: units, model_preferences: preferences,
+15 -7
View File
@@ -15,7 +15,7 @@
>
<v-tabs-slider class="mx-sm-1"></v-tabs-slider>
<v-tab href="#streams">
{{"Streams"}}
{{ streamsText }}
</v-tab>
<v-tab href="#mapper">
{{"Mapper"}}
@@ -88,7 +88,7 @@
<v-text-field
v-model="streamSearchQuery"
prepend-inner-icon="mdi-magnify"
label="Search streams"
:label="searchText"
background-color="background"
hide-details
clearable
@@ -101,6 +101,7 @@
</v-container>
<create-stream-dialog
v-if="accounts().length !== 0"
:is-f-e2="preferences && preferences.user && preferences.user.fe2"
:account-id="activeAccount().userInfo.id"
:server-url="activeAccount().serverInfo.url"
/>
@@ -115,7 +116,7 @@
</v-tab-item>
<v-tab-item :key="2" value="mapper">
<v-card flat>
<mapper></mapper>
<mapper :stream-text="streamText" :branch-text="branchText"></mapper>
</v-card>
</v-tab-item>
</v-tabs-items>
@@ -174,7 +175,7 @@ export default {
size: {
type: Number,
default: 42
},
}
},
data() {
return {
@@ -183,7 +184,11 @@ export default {
createStreamByIdDialog: false,
createStreamByIdText: "",
preferences: {},
tab: "streams"
tab: "streams",
searchText: '',
streamsText: 'Streams',
streamText: 'Stream',
branchText: 'Branch'
}
},
computed: {
@@ -209,8 +214,11 @@ export default {
})
bus.$on('update-preferences', async (preferences) => {
let prefs = JSON.parse(preferences)
this.preferences = prefs
this.preferences = JSON.parse(preferences)
this.searchText = this.preferences.user.fe2 ? 'Search projects' : 'Search streams'
this.streamsText = this.preferences.user.fe2 ? 'Projects' : 'Streams'
this.streamText = this.preferences.user.fe2 ? 'Project' : 'Stream'
this.branchText = this.preferences.user.fe2 ? 'Model' : 'Branch'
this.$vuetify.theme.dark = this.preferences.user.dark_theme
})
+8 -3
View File
@@ -232,22 +232,27 @@ export default {
// }
},
clearMappingsFromTableSelection(){
sketchup.exec({ name: "clear_mappings_from_table", data: this.elementSelection })
sketchup.exec({ name: "clear_mappings_from_table", data: this.elementSelection })
this.$mixpanel.track('MappingsAction', { name: 'Mappings Clear' })
},
isolateMappedElementsOnSketchup(){
if (this.isIsolated){
this.isIsolated = false
sketchup.exec({ name: "show_all_entities", data: {} })
this.$mixpanel.track('MappingsAction', { name: 'Mappings Un-Isolate' })
} else {
this.isIsolated = true
sketchup.exec({ name: "isolate_mappings_from_table", data: this.elementSelection })
this.$mixpanel.track('MappingsAction', { name: 'Mappings Isolate' })
}
},
hideMappedElementsOnSketchup(){
sketchup.exec({ name: "hide_mappings_from_table", data: this.elementSelection })
sketchup.exec({ name: "hide_mappings_from_table", data: this.elementSelection })
this.$mixpanel.track('MappingsAction', { name: 'Mappings Hide' })
},
selectMappedElementsOnSketchup(){
sketchup.exec({ name: "select_mappings_from_table", data: this.elementSelection })
sketchup.exec({ name: "select_mappings_from_table", data: this.elementSelection })
this.$mixpanel.track('MappingsAction', { name: 'Mappings Select Elements' })
},
// Update mapped elements table whenever mapped elements has changed.
getMappedElementsTableData(){
+194 -62
View File
@@ -65,24 +65,31 @@
mdi-source-branch
</v-icon>
{{ `Source` }}
<v-btn
v-if="!sourceUpToDate"
v-tooltip="'Source branch is not up-to-date!'"
class="ma-0"
height="20px"
icon
small
color="red"
@click="refreshSourceBranch"
>
<v-icon>
mdi-update
</v-icon>
</v-btn>
<v-tooltip right>
<template #activator="{ on, attrs }">
<v-btn
class="ma-0 ml-1"
height="20px"
width="20px"
icon
x-small
:color="getSourceStateIconColor()"
v-bind="attrs"
v-on="on"
@click="refreshSourceBranch"
>
<v-icon>
{{ getSourceStateIcon() }}
</v-icon>
</v-btn>
</template>
<span>{{ getSourceStateToolTip() }}</span>
</v-tooltip>
</v-container>
</v-expansion-panel-header>
<v-expansion-panel-content>
<mapper-source :source-up-to-date="this.sourceUpToDate"/>
<mapper-source :stream-text="streamText" :branch-text="branchText" :source-state="this.sourceState"/>
</v-expansion-panel-content>
</v-expansion-panel>
@@ -152,7 +159,7 @@
class="pt-0"
label="Mapper Method"
:disabled="!entitySelected"
:items="enabledMethods"
:items="availableMethods"
density="compact"
clearable
@change="onSelectedMethodChange"
@@ -167,6 +174,7 @@
:items="families"
density="compact"
clearable
@change="onSelectedFamilyChange"
></v-autocomplete>
<v-autocomplete
@@ -272,6 +280,7 @@
import {bus} from "@/main";
import {groupBy} from "@/utils/groupBy";
import MappingSource from "@/components/MapperSource.vue";
import {sourceMap} from "@vue/cli-service/lib/config/terserOptions";
global.mapperSourceUpdated = function (streamId, levels, types) {
console.log(`Mapper source updated for ${streamId}.`)
@@ -291,6 +300,16 @@ global.mappedEntitiesUpdated = function (mappedEntities) {
export default {
name: "Mapper",
props: {
streamText: {
type: String,
default: ''
},
branchText: {
type: String,
default: ''
}
},
components: {
MapperSource: () => import('@/components/MapperSource.vue'),
GlobalToast: () => import('@/components/GlobalToast'),
@@ -309,7 +328,7 @@ export default {
categorySelectionActive: false,
nameSelectionActive: false,
sourceUpToDate: true,
sourceState: 'Not Set',
// Expanded indexes for selection table (Types)
selectionExpandedIndexes: [],
// Expanded indexes for mapped element table (Categories)
@@ -324,6 +343,7 @@ export default {
entitySelected: false,
selectedEntityCount: 0,
selectedEntities: [],
allFamilyTypes: {},
familyTypes: [],
lastSelectedEntity: null,
@@ -334,7 +354,7 @@ export default {
selectedLevel: null,
name: "",
enabledMethods: [],
availableMethods: [],
availableCategories: [],
families: [],
allTypes: {},
@@ -449,10 +469,51 @@ export default {
}
},
methods:{
getSourceStateIcon(){
switch (this.sourceState){
case "Not Set":
return `mdi-cloud-off-outline`;
case "Set":
return `mdi-checkbox-marked-circle-outline`;
case "Outdated":
return `mdi-update`;
default:
break;
}
},
getSourceStateToolTip(){
switch (this.sourceState){
case "Not Set":
return 'Source disconnected.';
case "Set":
return 'Source connected.';
case "Outdated":
return 'Source branch is not up-to-date!';
default:
break;
}
},
getSourceStateIconColor(){
switch (this.sourceState){
case "Not Set":
return `grey`;
case "Set":
return `green`;
case "Outdated":
return `red`;
default:
break;
}
},
onSelectedMethodChange(){
this.hideOptionalMappingInputs()
this.updateMappingInputs()
this.getTypesFromSelectedMethod()
this.getFamiliesFromSelectedMethod()
this.getTypesFromSelectedFamily()
this.$mixpanel.track('MappingsAction', { name: 'Mappings Set', schema: this.selectedMethod })
},
onSelectedFamilyChange(){
this.getTypesFromSelectedFamily();
},
updateMappingInputs(){
if (this.selectedMethod === null){
@@ -483,39 +544,54 @@ export default {
this.levelSelectionActive = true
}
},
getTypesFromSelectedMethod(){
getTypesFromSelectedFamily(){
this.familyTypes = this.allFamilyTypes[this.selectedFamily]
this.selectedFamilyType = this.familyTypes[0].type
if (this.selectedFamily === null || this.selectedFamily === undefined){
this.selectedFamily = this.families[0]
}
if (this.familyTypes === null ||this.familyTypes === undefined){
this.familyTypes = this.allFamilyTypes[this.selectedFamily]
}
if (this.selectedFamilyType === null || this.selectedFamilyType === undefined){
this.selectedFamilyType = this.familyTypes[0].type
}
},
getFamiliesFromSelectedMethod(){
switch (this.selectedMethod) {
case 'Floor':
this.familyTypes = this.allTypes['Floors'];
this.families = ['Floor'];
this.families = Object.keys(this.allTypes['Floors']);
this.allFamilyTypes = this.allTypes['Floors']
break;
case 'Wall':
this.familyTypes = this.allTypes['Walls'];
this.families = ['Wall'];
this.families = Object.keys(this.allTypes['Walls']);
this.allFamilyTypes = this.allTypes['Walls']
break;
case 'Column':
this.familyTypes = this.allTypes['Columns'];
this.families = ['Column'];
this.families = Object.keys(this.allTypes['Columns']);
this.allFamilyTypes = this.allTypes['Columns']
break;
case 'Beam':
this.familyTypes = this.allTypes['Beams'];
this.families = ['Beam'];
break;
case 'Brace':
this.familyTypes = this.allTypes['Braces'];
this.families = ['Brace'];
this.families = Object.keys(this.allTypes['Beams']);
this.allFamilyTypes = this.allTypes['Beams']
break;
case 'Pipe':
this.familyTypes = this.allTypes['Pipes'];
this.families = ['Pipe'];
this.families = Object.keys(this.allTypes['Piping System']);
this.allFamilyTypes = this.allTypes['Piping System']
break;
case 'Duct':
this.familyTypes = this.allTypes['Ducts'];
this.families = ['Duct'];
this.families = Object.keys(this.allTypes['Duct System']);
this.allFamilyTypes = this.allTypes['Duct System']
break;
default:
break;
}
if (this.selectedFamily === null || this.selectedFamily === undefined){
this.selectedFamily = this.families[0]
}
if (this.selectedLevel === null || this.selectedLevel === undefined){
this.selectedLevel = this.levels[0].name
}
},
hideOptionalMappingInputs(){
this.categorySelectionActive = false
@@ -525,10 +601,13 @@ export default {
this.levelSelectionActive = false
},
refreshSourceBranch(){
bus.$emit('refresh-source-branch')
if (this.sourceState === 'Outdated'){
bus.$emit('refresh-source-branch')
this.$mixpanel.track('MappingsAction', { name: 'Mappings Source Update' })
}
},
clearInputs(){
this.enabledMethods = []
this.availableMethods = []
this.availableCategories = []
this.selectedEntities = []
this.selectionTableData = []
@@ -581,12 +660,12 @@ export default {
return summary
},
setInputValuesFromSelection(){
// Clear all inputs if entity is not selected.
if (!this.entitySelected){
this.name = ""
this.selectedMethod = null
this.selectedCategory = null
this.clearMappingInputs()
return
}
// Check if definition card is selected and set definition mappings.
if (this.definitionSelected) {
if (!this.definitionMapped){
if (this.selectedEntityCount > 1){
@@ -605,15 +684,20 @@ export default {
this.selectedMethod = this.lastSelectedEntity['definition']['schema']['method']
this.selectedCategory = this.lastSelectedEntity['definition']['schema']['category']
}
} else {
}
// Otherwise set entity mappings.
else
{
if (!this.entityMapped){
if (this.selectedEntityCount > 1){
this.name = '<Mixed>'
}else{
this.name = this.lastSelectedEntity['entityName']
}
console.log("entity not mapped")
this.updateMappingInputs()
// this.selectedMethod = 'Direct Shape'
this.getFamiliesFromSelectedMethod()
this.getTypesFromSelectedFamily()
this.selectedCategory = 49
} else {
if (this.selectedEntityCount > 1){
@@ -622,10 +706,12 @@ export default {
this.name = this.lastSelectedEntity['schema']['name']
}
this.selectedMethod = this.lastSelectedEntity['schema']['method']
console.log("entity is mapped")
this.updateMappingInputs()
this.getTypesFromSelectedMethod()
this.selectedCategory = this.lastSelectedEntity['schema']['category']
this.selectedFamily = this.lastSelectedEntity['schema']['family']
this.selectedCategory = this.lastSelectedEntity['schema']['category']
this.getFamiliesFromSelectedMethod()
this.getTypesFromSelectedFamily()
this.selectedFamilyType = this.lastSelectedEntity['schema']['family_type']
this.selectedLevel = this.lastSelectedEntity['schema']['level']
}
@@ -666,10 +752,29 @@ export default {
this.mappedElementsExpandedIndexes.push(slotData.item);
}
},
inputsReadyToApply(){
if (this.selectedMethod === null || this.selectedMethod === undefined){
return false;
}
const nativeMethods = this.nativeEdgeMethods.concat(this.nativeFaceMethods)
if (this.selectedMethod === 'Direct Shape'){
return this.selectedCategory !== null
}
else if (nativeMethods.includes(this.selectedMethod)){
return this.selectedFamily !== null &&
this.selectedFamilyType !== null &&
this.selectedLevel !== null
}
else {
return true;
}
},
applyMapping(){
if (this.selectedMethod === null || this.selectedCategory === null){
if (!this.inputsReadyToApply()){
this.$eventHub.$emit('error', {
text: 'Method and category are not set.\n'
text: 'Some inputs are not set to apply mapping.\n'
})
return
}
@@ -687,6 +792,8 @@ export default {
this.$eventHub.$emit('success', {
text: 'Mapping Applied.\n'
})
this.$mixpanel.track('MappingsAction', { name: 'Mappings Applied' })
},
clearMapping(){
const mapping = {
@@ -698,28 +805,53 @@ export default {
this.$eventHub.$emit('error', {
text: 'Mapping Cleared.\n'
})
}
},
mounted() {
sketchup.exec({name: "collect_mapped_entities", data: {}})
bus.$on('entities-selected', async (selectionParameters) => {
this.$mixpanel.track('MappingsAction', { name: 'Mappings Clear' })
},
clearMappingInputs(){
this.selectedMethod = null
const selectionPars = JSON.parse(selectionParameters)
this.enabledMethods = selectionPars.mappingMethods
this.availableCategories = selectionPars.categories
this.selectedEntities = selectionPars.selection
this.allTypes = selectionPars.types
this.levels = selectionPars.levels
this.selectedLevel = selectionPars.selectedLevel
console.log(selectionPars)
this.selectedCategory = null
this.name = ""
this.selectedFamily = null
this.selectedFamilyType = null
this.selectedLevel = null
this.familyTypes = null
this.levels = null
this.availableMethods = null
this.availableCategories = null
this.allTypes = null
},
getDataFromSelection(selectionParameters){
this.availableMethods = selectionParameters.mappingMethods
this.availableCategories = selectionParameters.categories
this.selectedEntities = selectionParameters.selection
this.allTypes = selectionParameters.types
this.levels = selectionParameters.levels
this.selectedLevel = selectionParameters.selectedLevelName
},
updateStatesFromSelectionData(){
this.lastSelectedEntity = this.selectedEntities[this.selectedEntities.length - 1]
this.entityMapped = this.isEntitiesMapped(this.selectedEntities)
this.definitionMapped = this.isEntityDefinitionsMapped(this.selectedEntities)
this.definitionSelected = !this.entityMapped && this.definitionMapped
this.selectedEntityCount = this.selectedEntities.length
this.entitySelected = this.selectedEntityCount !== 0
}
},
mounted() {
sketchup.exec({name: "collect_mapped_entities", data: {}})
bus.$on('entities-selected', async (selectionParameters) => {
// Parse data to json object
const selectionPars = JSON.parse(selectionParameters)
// Reset mapping inputs with nulls and empties.
this.clearMappingInputs()
// Get data from selection into objects and arrays. These data basically constructs the dropdowns.
this.getDataFromSelection(selectionPars)
// Update inner state of the mapper component according to selection data.
this.updateStatesFromSelectionData()
// Get selection table data.
this.getSelectionTableData()
// Set mapping input values from selection data.
this.setInputValuesFromSelection()
})
bus.$on('entities-deselected', async () => {
@@ -731,7 +863,7 @@ export default {
this.mappedEntityCount = mappedEntities.length
})
bus.$on('set-source-up-to-date', (isUpToDate) => {
this.sourceUpToDate = isUpToDate
this.sourceState = isUpToDate
})
}
}
+33 -10
View File
@@ -2,7 +2,7 @@
<v-container class="pa-0">
<v-autocomplete
v-model="sourceStreamId"
label="Stream"
:label="streamText"
:items="allStreamsList"
item-text="name"
item-value="id"
@@ -12,7 +12,7 @@
<v-autocomplete
v-model="sourceBranchId"
class="pt-0 mb-n5"
label="Branch"
:label="branchText"
:items="allBranchesList"
:disabled="sourceStreamId === null"
item-text="name"
@@ -62,7 +62,15 @@ export default {
name: "MappingSource",
props: {
streamSearchQuery: { type: String, default: null },
sourceUpToDate: { type: Boolean },
sourceState: { type: String, default: 'Not Set' },
streamText: {
type: String,
default: ''
},
branchText: {
type: String,
default: ''
}
},
data() {
return {
@@ -117,11 +125,13 @@ export default {
},
result(data) {
if (data.data.commitCreated.sourceApplication.includes('Revit')){
this.afterCommitCreated()
this.$eventHub.$emit('notification', {
text: `A new commit was created on Revit!`,
})
this.$apollo.queries.stream.refetch()
if (data.data.commitCreated.branchName === this.selectedBranch.name){
this.afterCommitCreated()
this.$eventHub.$emit('notification', {
text: `A new commit was created on Revit!`,
})
this.$apollo.queries.stream.refetch()
}
}
},
skip() {
@@ -161,19 +171,32 @@ export default {
mounted() {
bus.$on('refresh-source-branch', () => {
this.onSourceBranchChanged()
bus.$emit('set-source-up-to-date', true)
bus.$emit('set-source-up-to-date', 'Set')
})
},
methods: {
applySource(){
bus.$emit('set-source-up-to-date', 'Set')
this.onSourceBranchChanged()
this.$eventHub.$emit('success', {
text: 'Mapper source applied.\n'
})
this.$mixpanel.track('MappingsAction', { name: 'Mappings Source Apply' })
},
clearSource(){
sketchup.exec({name:"clear_mapper_source" , data: {}})
bus.$emit('set-source-up-to-date', 'Not Set')
this.sourceApplied = false
this.sourceBranchName = null
this.sourceStreamName = null
this.sourceBranchId = null
this.sourceStreamId = null
this.$eventHub.$emit('error', {
text: 'Mapper source cleared.\n'
})
},
afterCommitCreated(){
bus.$emit('set-source-up-to-date', false)
bus.$emit('set-source-up-to-date', 'Outdated')
},
async onSourceBranchChanged() {
const commitRefId = this.selectedBranch.commits.items[0]?.referencedObject
+22 -4
View File
@@ -13,7 +13,7 @@
<v-toolbar-title class="ml-0" style="position: relative; left: -10px">
<!-- Uncomment when pinning is in place and add style="position: relative; left: -10px" to the element above :) -->
<v-btn
v-tooltip="'Pin this stream - it will be saved to this file.'"
v-tooltip="`Pin this ${streamText.toLowerCase()} - it will be saved to this file.`"
icon
x-small
@click="toggleSavedStream"
@@ -66,7 +66,11 @@
<template #activator="{ on, attrs }">
<v-slide-x-transition>
<div v-show="hover">
<create-branch-dialog :stream-name="stream.name" :stream-id="streamId"/>
<create-branch-dialog
:is-f-e2="preferences && preferences.user && preferences.user.fe2"
:stream-name="stream.name"
:stream-id="streamId"
/>
</div>
</v-slide-x-transition>
<v-chip v-if="stream.branches" small v-bind="attrs" class="mr-1" v-on="on">
@@ -133,7 +137,7 @@
hide-details
dense
flat
placeholder="Write your commit message here"
:placeholder="`Write your ${commitText.toLowerCase()} message here`"
/>
</div>
</v-slide-y-transition>
@@ -204,7 +208,11 @@ export default {
commitId: 'latest',
commitMessage: null,
invalid: false,
diffing: false
diffing: false,
streamText: '',
branchText: '',
commitText: '',
preferences: {}
}
},
apollo: {
@@ -286,6 +294,16 @@ export default {
}
},
mounted() {
bus.$on('update-preferences', async (preferences) => {
const pref = JSON.parse(preferences)
this.preferences = pref
this.streamText = pref.user.fe2 ? 'Project' : 'Stream'
this.branchText = pref.user.fe2 ? 'Model' : 'Branch'
this.commitText = pref.user.fe2 ? 'Version' : 'Commit'
})
// Collect preferences to render UI according to it
sketchup.exec({name: "collect_preferences", data: {}})
bus.$on(`deactivate-diffing-${this.streamId}`, () => {
this.diffing = false
})
@@ -3,7 +3,7 @@
<v-dialog v-model="showCreateBranch">
<template #activator="{ on: dialog, attrs }">
<v-btn
v-tooltip="'Create Branch'"
v-tooltip="`Create ${isFE2 ? 'Model' : 'Branch'}`"
icon x-small class="ml-0 mr-1"
v-bind="attrs"
v-on="{...dialog}"
@@ -15,10 +15,10 @@
</template>
<v-card>
<v-card-title class="text-h5 mb-1">
Create a New Branch
{{ `Create a New ${isFE2 ? 'Model' : 'Branch'}` }}
</v-card-title>
<v-card-subtitle class="py-0 my-0 font-italic">
under {{ streamName }} stream
{{ `under ${streamName} ${isFE2 ? 'project' : 'stream'}` }}
</v-card-subtitle>
<v-container class="px-6" pb-0>
<v-text-field
@@ -27,7 +27,7 @@
hide-details
dense
flat
placeholder="Branch Name"
:placeholder="`${isFE2 ? 'Model' : 'Branch'} Name`"
/>
<v-text-field
v-model="description"
@@ -75,6 +75,14 @@ export default {
streamName: {
type: String,
default: null
},
isFE2: {
type: Boolean,
default: false
},
branchTooltipName: {
type: String,
default: ''
}
},
data() {
@@ -16,13 +16,14 @@
left
>
mdi-plus-circle
</v-icon>Create New Stream
</v-icon>
{{ `Create New ${isFE2 ? 'Project': 'Stream'}` }}
</v-btn>
</template>
<v-card>
<v-card-title class="text-h5">
Create a New Stream
{{ `Create a New ${isFE2 ? 'Project' : 'Stream'}` }}
</v-card-title>
<v-container class="px-6" pb-0>
<!--
@@ -55,7 +56,7 @@
hide-details
dense
flat
placeholder="Stream Name (Optional)"
:placeholder="`${isFE2 ? 'Project' : 'Stream'} Name (Optional)`"
/>
<v-text-field
v-model="description"
@@ -67,7 +68,7 @@
/>
<v-switch
v-model="privateStream"
:label="'Private Stream'"
:label="`Private ${isFE2 ? 'Project' : 'Stream'}`"
></v-switch>
</v-container>
@@ -169,6 +170,10 @@ export default {
serverUrl: {
type: String,
default: null
},
isFE2: {
type: Boolean,
default: false
}
},
data() {
@@ -200,7 +205,7 @@ export default {
},
async getStream(){
try {
const streamWrapper = new StreamWrapper(this.createStreamByIdText, this.accountId, this.serverUrl)
const streamWrapper = new StreamWrapper(this.createStreamByIdText, this.accountId, this.serverUrl, this.isFE2)
let res = await this.$apollo.query({
query: gql`
query Stream($id: String!){
+23 -1
View File
@@ -16,14 +16,25 @@
Settings
</v-card-title>
<v-container class="px-6" pb-0>
<!-- Switch Theme -->
<!-- User preferences -->
<div class="sm1 mt-3">User Preferences</div>
<v-divider class="mb-2"/>
<!-- Switch Theme -->
<v-btn icon small class="mx-1" @click="switchTheme">
<v-icon>mdi-theme-light-dark</v-icon>
</v-btn>
<span>Color Mode</span>
<!-- FE2 -->
<v-switch
:input-value="fe2"
class="pt-3 mt-n2 mb-n7"
:label="'FE2'"
@change="fe2Handler"
/>
<!-- Register objects as Speckle Entity on send/receive -->
<v-switch
:input-value="registerSpeckleEntity"
@@ -133,6 +144,7 @@ export default {
includeComponentAttributes: this.preferences.model.include_component_entity_attributes,
mergeCoplanarFaces: this.preferences.model.merge_coplanar_faces,
diffing: this.preferences.user.diffing,
fe2: this.preferences.user.fe2,
registerSpeckleEntity: this.preferences.user.register_speckle_entity
}
},
@@ -147,6 +159,7 @@ export default {
this.includeComponentAttributes = newValue.model.include_component_entity_attributes
this.mergeCoplanarFaces = newValue.model.merge_coplanar_faces
this.diffing = newValue.user.diffing
this.fe2 = newValue.user.fe2
this.registerSpeckleEntity = newValue.user.register_speckle_entity
},
deep: true,
@@ -161,6 +174,15 @@ export default {
}
},
methods: {
fe2Handler(newValue){
this.fe2 = !!newValue
sketchup.exec({
name: "user_preferences_updated",
data: {preference_hash: "configSketchup", preference: "fe2", value: this.fe2}
})
this.$mixpanel.track('Connector Action', { name: 'Toggle FE2' })
sketchup.exec({name: "collect_preferences", data: {}})
},
diffingHandler(newValue){
this.diffing = !!newValue
sketchup.exec({
+9 -5
View File
@@ -1,7 +1,11 @@
require('url')
export class StreamWrapper {
constructor(streamIdOrUrl, accountId, serverUrl) {
constructor(streamIdOrUrl, accountId, serverUrl, isFE2) {
this.isFE2 = isFE2
this.streamsKey = this.isFE2 ? 'projects/': 'streams/'
this.branchesKey = this.isFE2 ? 'models/': 'branches/'
this.commitsKey = this.isFE2 ? 'versions/': 'commits/'
this.originalOutput = streamIdOrUrl
try {
this.streamWrapperFromUrl(streamIdOrUrl)
@@ -18,7 +22,7 @@ export class StreamWrapper {
this.segments = this.url.pathname.split('/').map((segment) => segment + '/')
this.serverUrl = this.url.origin
if (this.segments.length >= 4 && this.segments[3]?.toLowerCase() === "branches/"){
if (this.segments.length >= 4 && this.segments[3]?.toLowerCase() === this.branchesKey){
this.streamId = this.segments[2].replace("/", "")
if (this.segments.length > 5)
{
@@ -32,7 +36,7 @@ export class StreamWrapper {
} else {
switch (this.segments.length){
case 3: // ie http://speckle.server/streams/8fecc9aa6d
if (this.segments[1].toLowerCase() === "streams/")
if (this.segments[1].toLowerCase() === this.streamsKey)
this.streamId = this.segments[2].replace("/", "");
else
throw new Error(`Cannot parse ${this.originalOutput} into a stream wrapper class`);
@@ -48,7 +52,7 @@ export class StreamWrapper {
break;
case 5: // ie http://speckle.server/streams/8fecc9aa6d/commits/76a23d7179
switch (this.segments[3].toLowerCase()){
case "commits/":
case this.commitsKey:
this.streamId = this.segments[2].replace("/", "");
this.commitId = this.segments[4].replace("/", "");
break;
@@ -57,7 +61,7 @@ export class StreamWrapper {
this.branchName = this.segments[3].replace("/", "");
this.commitId = this.segments[4].replace("/", "");
break;
case "branches/":
case this.branchesKey:
this.streamId = this.segments[2].replace("/", "");
this.branchName = this.segments[4].replace("/", "");
break;
+11 -2
View File
@@ -27,7 +27,7 @@
elevation="0"
@click="showMore"
>
More Streams
{{ `More ${streamsText}` }}
</v-btn>
</div>
</div>
@@ -64,7 +64,8 @@ export default {
data() {
return {
showMoreEnabled: true,
savedStreams: []
savedStreams: [],
streamsText: ''
}
},
computed: {
@@ -80,6 +81,14 @@ export default {
}
},
mounted() {
bus.$on('update-preferences', async (preferences) => {
const pref = JSON.parse(preferences)
this.streamsText = pref.user.fe2 ? 'Projects' : 'Streams'
})
// Collect preferences to render UI according to it
sketchup.exec({name: "collect_preferences", data: {}})
bus.$on("deactivate-diffing-except", (exceptedStreamId) => {
this.savedStreams.forEach((streamId) => {
if (streamId !== exceptedStreamId){