Compare commits

...

34 Commits

Author SHA1 Message Date
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
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
26 changed files with 604 additions and 76 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,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
@@ -33,4 +33,6 @@ module SpeckleConnector
OBJECTS_OTHER_DISPLAYSTYLE = 'Objects.Other.DisplayStyle'
SPECKLE_CORE_MODELS_COLLECTION = 'Speckle.Core.Models.Collection'
SPECKLE_CORE_MODELS_COLLECTION_RASTER_LAYER = 'Speckle.Core.Models.Collection:Objects.GIS.RasterLayer'
SPECKLE_CORE_MODELS_COLLECTION_VECTOR_LAYER = 'Speckle.Core.Models.Collection:Objects.GIS.VectorLayer'
end
+33 -25
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,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)
+15 -1
View File
@@ -19,6 +19,7 @@ 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
@@ -32,11 +33,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,11 +60,13 @@ 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
POLYGON_ELEMENT = GIS::PolygonElement
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[
@@ -77,9 +83,12 @@ 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
Speckle.Core.Models.Collection:Objects.GIS.RasterLayer
Speckle.Core.Models.Collection:Objects.GIS.VectorLayer
].freeze
def from_revit
@@ -294,10 +303,13 @@ module SpeckleConnector
OBJECTS_OTHER_REVIT_REVITINSTANCE => REVIT_INSTANCE.method(:to_native),
OBJECTS_OTHER_RENDERMATERIAL => RENDER_MATERIAL.method(:to_native),
OBJECTS_BUILTELEMENTS_VIEW3D => VIEW3D.method(:to_native),
OBJECTS_BUILTELEMENTS_REVIT_WALL => REVIT_WALL.method(:to_native),
OBJECTS_BUILTELEMENTS_REVIT_DIRECTSHAPE => BUILTELEMENTS::Revit::DirectShape.method(:to_native),
OBJECTS_BUILTELEMENTS_NETWORK => BUILTELEMENTS::Network.method(:to_native),
OBJECTS_GIS_POLYGONELEMENT => POLYGON_ELEMENT.method(:to_native),
SPECKLE_CORE_MODELS_COLLECTION => COLLECTION.method(:to_native)
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
@@ -309,6 +321,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.
@@ -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
@@ -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)
@@ -36,6 +36,27 @@ module SpeckleConnector
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)
@@ -11,6 +11,10 @@ module SpeckleConnector
end
def self.length_to_native(length, units)
if units == 'none'
units = SpeckleConnector::Converters::
SKETCHUP_UNITS[Sketchup.active_model.options['UnitsOptions']['LengthUnit']]
end
length.__send__(SpeckleConnector::Converters::SKETCHUP_UNIT_STRINGS[units])
end
end
@@ -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
@@ -0,0 +1,207 @@
# frozen_string_literal: true
module SpeckleConnector
module SpeckleObjects
module Geometry
module Units
MILLIMETERS = 'mm'
CENTIMETERS = 'cm'
METERS = 'm'
KILOMETERS = 'km'
INCHES = 'in'
FEET = 'ft'
YARDS = 'yd'
MILES = 'mi'
NONE = 'none'
# USInches = "us_in" the smelliest ones, can add later if people scream "USA #1"
USFEET = 'us_ft' # it happened, absolutely gross
SUPPORTED_UNITS = [MILLIMETERS, CENTIMETERS, METERS, KILOMETERS,
INCHES, FEET, USFEET, YARDS, MILES, NONE].freeze
CONVERSION_TABLE = {
MILLIMETERS => {
CENTIMETERS => 0.1,
METERS => 0.001,
KILOMETERS => 1e-6,
INCHES => 0.0393701,
FEET => 0.00328084,
USFEET => 0.0032808333,
YARDS => 0.00109361,
MILES => 6.21371e-7
},
CENTIMETERS => {
MILLIMETERS => 10,
METERS => 0.01,
KILOMETERS => 1e-5,
INCHES => 0.393701,
FEET => 0.0328084,
USFEET => 0.0328083333,
YARDS => 0.0109361,
MILES => 6.21371e-6
},
METERS => {
MILLIMETERS => 1000,
CENTIMETERS => 100,
KILOMETERS => 0.001,
INCHES => 39.3701,
FEET => 3.28084,
USFEET => 3.28083333,
YARDS => 1.09361,
MILES => 0.000621371
},
KILOMETERS => {
MILLIMETERS => 1e6,
CENTIMETERS => 100000,
METERS => 1000,
INCHES => 39370.1,
FEET => 3280.84,
USFEET => 3280.83333,
YARDS => 1093.61,
MILES => 0.621371
},
INCHES => {
MILLIMETERS => 25.4,
CENTIMETERS => 2.54,
METERS => 0.0254,
KILOMETERS => 2.54e-5,
FEET => 0.0833333,
USFEET => 0.0833331667,
YARDS => 0.027777694,
MILES => 1.57828e-5
},
FEET => {
MILLIMETERS => 304.8,
CENTIMETERS => 30.48,
METERS => 0.3048,
KILOMETERS => 0.0003048,
INCHES => 12,
USFEET => 0.999998,
YARDS => 0.333332328,
MILES => 0.000189394
},
USFEET => {
MILLIMETERS => 120000.0 / 3937.0,
CENTIMETERS => 12000.0 / 3937.0,
METERS => 1200.0 / 3937.0,
KILOMETERS => 1.2 / 3937.0,
INCHES => 12.000024,
FEET => 1.000002,
YARDS => 1.000002 / 3.0,
MILES => 1.000002 / 5280.0
},
YARDS => {
MILLIMETERS => 914.4,
CENTIMETERS => 91.44,
METERS => 0.9144,
KILOMETERS => 0.0009144,
INCHES => 36,
FEET => 3,
USFEET => 2.999994,
MILES => 1.0 / 1760.0
},
MILES => {
MILLIMETERS => 1.609e6,
CENTIMETERS => 160934,
METERS => 1609.34,
KILOMETERS => 1.60934,
INCHES => 63360,
FEET => 5280,
USFEET => 5279.98944002112,
YARDS => 1759.99469184
},
NONE => { NONE => 1 }
}.freeze
def self.unit_supported?(unit)
SUPPORTED_UNITS.include?(unit)
end
# USYards = "us_yd" the smelliest ones, can add later if people scream "USA #1"
# USMiles = "us_mi" the smelliest ones, can add later if people scream "USA #1"
def self.get_conversion_factor(from, to)
from = get_units_from_string(from)
to = get_units_from_string(to)
CONVERSION_TABLE[from][to] || 1
end
def self.get_units_from_string(unit)
return nil if unit.nil?
case unit.downcase
when 'mm', 'mil', 'millimeter', 'millimeters', 'millimetres'
MILLIMETERS
when 'cm', 'centimetre', 'centimeter', 'centimetres', 'centimeters'
CENTIMETERS
when 'm', 'meter', 'metre', 'meters', 'metres'
METERS
when 'inches', 'inch', 'in'
INCHES
when 'feet', 'foot', 'ft'
FEET
when 'ussurveyfeet'
USFEET
when 'yard', 'yards', 'yd'
YARDS
when 'miles', 'mile', 'mi'
MILES
when 'kilometers', 'kilometer', 'km'
KILOMETERS
when 'none'
NONE
else
raise "Cannot understand what unit #{unit} is."
end
end
def self.get_encoding_from_unit(unit)
case unit
when MILLIMETERS
1
when CENTIMETERS
2
when METERS
3
when KILOMETERS
4
when INCHES
5
when FEET
6
when YARDS
7
when MILES
8
else
0
end
end
def self.get_unit_from_encoding(unit)
case unit
when 1
MILLIMETERS
when 2
CENTIMETERS
when 3
METERS
when 4
KILOMETERS
when 5
INCHES
when 6
FEET
when 7
YARDS
when 8
MILES
else
NONE
end
end
end
end
end
end
@@ -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)
@@ -0,0 +1,28 @@
# frozen_string_literal: true
require_relative 'collection'
module SpeckleConnector
module SpeckleObjects
module Speckle
module Core
module Models
# VectorLayerCollection object that collect GIS vector elements under it's elements.
class GisLayerCollection < Collection
# @param state [States::State] state of the Speckle application.
def self.to_native(state, vector_layer_collection, layer_or_folder, entities, &convert_to_native)
elements = vector_layer_collection['elements']
elements.each do |element|
new_state, _converted_entities = convert_to_native.call(state, element, layer_or_folder, entities)
state = new_state
end
return state, []
end
end
end
end
end
end
end
@@ -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)
+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
})
+11 -1
View File
@@ -89,7 +89,7 @@
</v-container>
</v-expansion-panel-header>
<v-expansion-panel-content>
<mapper-source :source-state="this.sourceState"/>
<mapper-source :stream-text="streamText" :branch-text="branchText" :source-state="this.sourceState"/>
</v-expansion-panel-content>
</v-expansion-panel>
@@ -300,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'),
+10 -2
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"
@@ -63,6 +63,14 @@ export default {
props: {
streamSearchQuery: { type: String, default: null },
sourceState: { type: String, default: 'Not Set' },
streamText: {
type: String,
default: ''
},
branchText: {
type: String,
default: ''
}
},
data() {
return {
+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){