├── .gitignore ├── CMakeLists.txt ├── CompileResources.py ├── LICENSE.md ├── README.md ├── RFIX.mac └── Info.plist ├── RFIX.win └── AdditionalJSONCommands.rc2 ├── RFIX └── AdditionalJSONCommandsFix.grc ├── RINT └── AdditionalJSONCommands.grc └── Src ├── APIEnvir.h ├── AdditionalJSONCommand.cpp ├── AdditionalJSONCommand.hpp ├── ChangeGDLParametersOfElementsCommand.cpp ├── ChangeGDLParametersOfElementsCommand.hpp ├── CreateColumnsCommand.cpp ├── CreateColumnsCommand.hpp ├── CreateObjectsCommand.cpp ├── CreateObjectsCommand.hpp ├── CreateRailingsCommand.cpp ├── CreateRailingsCommand.hpp ├── CreateSlabsCommand.cpp ├── CreateSlabsCommand.hpp ├── GetArchicadLocationCommand.cpp ├── GetArchicadLocationCommand.hpp ├── GetGDLParametersOfElementsCommand.cpp ├── GetGDLParametersOfElementsCommand.hpp ├── GetHotlinksCommand.cpp ├── GetHotlinksCommand.hpp ├── GetProjectInfoCommand.cpp ├── GetProjectInfoCommand.hpp ├── Main.cpp ├── MoveElementsCommand.cpp ├── MoveElementsCommand.hpp ├── PublishCommand.cpp ├── PublishCommand.hpp ├── QuitCommand.cpp ├── QuitCommand.hpp ├── ReloadLibrariesCommand.cpp ├── ReloadLibrariesCommand.hpp ├── TeamworkReceiveCommand.cpp └── TeamworkReceiveCommand.hpp /.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | /.vscode 3 | .DS_Store -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 3.16) 2 | 3 | function (SetCompilerOptions target) 4 | target_compile_features (${target} PUBLIC cxx_std_14) 5 | target_compile_options (${target} PUBLIC "$<$:-DDEBUG>") 6 | if (WIN32) 7 | target_compile_options (${target} PUBLIC /W4 /WX /wd4996 /wd4499 /Zc:wchar_t-) 8 | else () 9 | target_compile_options (${target} PUBLIC -Wall -Wextra -Werror -fvisibility=hidden 10 | -Wno-multichar 11 | -Wno-ctor-dtor-privacy 12 | -Wno-invalid-offsetof 13 | -Wno-ignored-qualifiers 14 | -Wno-reorder 15 | -Wno-overloaded-virtual 16 | -Wno-unused-parameter 17 | -Wno-missing-field-initializers 18 | -Wno-unknown-pragmas 19 | -Wno-missing-braces 20 | -Wno-unused-private-field 21 | -Wno-return-std-move 22 | -Wno-unused-value 23 | -Wno-switch) 24 | endif () 25 | endfunction () 26 | 27 | function (SubDirList dirlist curdir) 28 | file (GLOB children RELATIVE "${curdir}" "${curdir}/*") 29 | set (result "") 30 | foreach (child ${children}) 31 | if (IS_DIRECTORY "${curdir}/${child}") 32 | list (APPEND result ${child}) 33 | endif () 34 | endforeach () 35 | set (${dirlist} ${result} PARENT_SCOPE) 36 | endfunction () 37 | 38 | function (AddGSModuleToIncludeDirectories target folder) 39 | message (STATUS "Add ${folder} GS Module to include directories") 40 | target_include_directories (${target} PUBLIC "${AC_API_DEVKIT_DIR}/Support/Modules/${folder}") 41 | endfunction () 42 | 43 | function (AddGSModulesToLinkLibraries target folder) 44 | if (WIN32) 45 | file (GLOB LinkLibraries 46 | ${AC_API_DEVKIT_DIR}/Support/Modules/${folder}/Win/*.lib 47 | ) 48 | else () 49 | file (GLOB LinkLibraries 50 | ${AC_API_DEVKIT_DIR}/Support/Frameworks/*.framework 51 | ) 52 | endif () 53 | foreach (linkLibrary ${LinkLibraries}) 54 | get_filename_component (libraryName "${linkLibrary}" NAME) 55 | message (STATUS "Add ${libraryName} GS Module to link libraries") 56 | target_link_libraries (${target} ${linkLibrary}) 57 | endforeach () 58 | endfunction () 59 | 60 | set_property (GLOBAL PROPERTY USE_FOLDERS ON) 61 | 62 | get_filename_component (CMAKE_CURRENT_FOLDER_NAME "${CMAKE_CURRENT_LIST_DIR}" NAME) 63 | set (CMAKE_SUPPRESS_REGENERATION 1) 64 | set (CMAKE_CONFIGURATION_TYPES Debug;Release;RelWithDebInfo) 65 | set (CMAKE_OSX_DEPLOYMENT_TARGET "10.15") 66 | set (CMAKE_OSX_ARCHITECTURES "x86_64") 67 | set (CMAKE_XCODE_ATTRIBUTE_ONLY_ACTIVE_ARCH "NO") 68 | set (AC_API_DEVKIT_DIR "${CMAKE_CURRENT_LIST_DIR}/../.." CACHE PATH "API DevKit directory.") 69 | set (AC_ADDON_NAME "${CMAKE_CURRENT_FOLDER_NAME}" CACHE STRING "Add-On name.") 70 | set (AC_ADDON_LANGUAGE "INT" CACHE STRING "Add-On language code.") 71 | 72 | message (STATUS "APIDevKit directory: ${AC_API_DEVKIT_DIR}") 73 | set (ACAPINC_FILE_LOCATION ${AC_API_DEVKIT_DIR}/Support/Inc/ACAPinc.h) 74 | if (EXISTS ${ACAPINC_FILE_LOCATION}) 75 | file (READ ${ACAPINC_FILE_LOCATION} ACAPIncContent) 76 | string (REGEX MATCHALL "#define[ \t]+ServerMainVers_([0-9][0-9])" VersionList ${ACAPIncContent}) 77 | set (ARCHICAD_VERSION ${CMAKE_MATCH_1}) 78 | message (STATUS "Archicad Version: ${ARCHICAD_VERSION}") 79 | else () 80 | message (FATAL_ERROR "Failed to detect Archicad version, please check the value of the AC_API_DEVKIT_DIR variable.") 81 | endif () 82 | 83 | if (WIN32) 84 | add_definitions (-DUNICODE -D_UNICODE) 85 | else () 86 | add_definitions (-Dmacintosh=1) 87 | endif () 88 | add_definitions (-DACExtension) 89 | 90 | project (${AC_ADDON_NAME}) 91 | 92 | set (AddOnSourcesFolder ./Src) 93 | set (AddOnResourcesFolder .) 94 | 95 | # AddOnResources 96 | 97 | set (ResourceObjectsDir ${CMAKE_BINARY_DIR}/ResourceObjects) 98 | 99 | file (GLOB AddOnImageFiles 100 | ${AddOnResourcesFolder}/RFIX/Images/*.svg 101 | ) 102 | if (WIN32) 103 | file (GLOB AddOnResourceFiles 104 | ${AddOnResourcesFolder}/R${AC_ADDON_LANGUAGE}/*.grc 105 | ${AddOnResourcesFolder}/RFIX/*.grc 106 | ${AddOnResourcesFolder}/RFIX.win/*.rc2 107 | ) 108 | else () 109 | file (GLOB AddOnResourceFiles 110 | ${AddOnResourcesFolder}/R${AC_ADDON_LANGUAGE}/*.grc 111 | ${AddOnResourcesFolder}/RFIX/*.grc 112 | ${AddOnResourcesFolder}/RFIX.mac/*.plist 113 | ) 114 | endif () 115 | 116 | source_group ("Images" FILES ${AddOnImageFiles}) 117 | source_group ("Resources" FILES ${AddOnResourceFiles}) 118 | add_custom_target ( 119 | AddOnResources ALL 120 | DEPENDS "${ResourceObjectsDir}/AddOnResources.stamp" 121 | SOURCES ${AddOnResourceFiles} ${AddOnImageFiles} 122 | ) 123 | 124 | get_filename_component (AddOnSourcesFolderAbsolute "${CMAKE_CURRENT_LIST_DIR}/${AddOnSourcesFolder}" ABSOLUTE) 125 | get_filename_component (AddOnResourcesFolderAbsolute "${CMAKE_CURRENT_LIST_DIR}/${AddOnResourcesFolder}" ABSOLUTE) 126 | get_filename_component (APIDevKitToolsFolderAbsolute "${AC_API_DEVKIT_DIR}/Support/Tools" ABSOLUTE) 127 | if (WIN32) 128 | add_custom_command ( 129 | OUTPUT "${ResourceObjectsDir}/AddOnResources.stamp" 130 | DEPENDS ${AddOnResourceFiles} ${AddOnImageFiles} 131 | COMMENT "Compiling resources..." 132 | COMMAND ${CMAKE_COMMAND} -E make_directory "${ResourceObjectsDir}" 133 | COMMAND python "${AddOnResourcesFolderAbsolute}/CompileResources.py" "${AC_ADDON_LANGUAGE}" "${AC_API_DEVKIT_DIR}" "${AddOnSourcesFolderAbsolute}" "${AddOnResourcesFolderAbsolute}" "${ResourceObjectsDir}" "${ResourceObjectsDir}/${AC_ADDON_NAME}.res" 134 | COMMAND ${CMAKE_COMMAND} -E touch "${ResourceObjectsDir}/AddOnResources.stamp" 135 | ) 136 | else () 137 | add_custom_command ( 138 | OUTPUT "${ResourceObjectsDir}/AddOnResources.stamp" 139 | DEPENDS ${AddOnResourceFiles} ${AddOnImageFiles} 140 | COMMENT "Compiling resources..." 141 | COMMAND ${CMAKE_COMMAND} -E make_directory "${ResourceObjectsDir}" 142 | COMMAND python "${AddOnResourcesFolderAbsolute}/CompileResources.py" "${AC_ADDON_LANGUAGE}" "${AC_API_DEVKIT_DIR}" "${AddOnSourcesFolderAbsolute}" "${AddOnResourcesFolderAbsolute}" "${ResourceObjectsDir}" "${CMAKE_BINARY_DIR}/$/${AC_ADDON_NAME}.bundle/Contents/Resources" 143 | COMMAND ${CMAKE_COMMAND} -E copy "${AC_API_DEVKIT_DIR}/Support/Inc/PkgInfo" "${CMAKE_BINARY_DIR}/$/${AC_ADDON_NAME}.bundle/Contents/PkgInfo" 144 | COMMAND ${CMAKE_COMMAND} -E touch "${ResourceObjectsDir}/AddOnResources.stamp" 145 | ) 146 | endif () 147 | 148 | # AddOn 149 | 150 | file (GLOB AddOnHeaderFiles 151 | ${AddOnSourcesFolder}/*.h 152 | ${AddOnSourcesFolder}/*.hpp 153 | ) 154 | file (GLOB AddOnSourceFiles 155 | ${AddOnSourcesFolder}/*.c 156 | ${AddOnSourcesFolder}/*.cpp 157 | ) 158 | file (GLOB AllCFiles 159 | ${AddOnSourcesFolder}/*.c 160 | ) 161 | set_source_files_properties(${AllCFiles} PROPERTIES LANGUAGE CXX) 162 | set ( 163 | AddOnFiles 164 | ${AddOnHeaderFiles} 165 | ${AddOnSourceFiles} 166 | ) 167 | source_group ("Sources" FILES ${AddOnFiles}) 168 | if (WIN32) 169 | add_library (AddOn SHARED ${AddOnFiles}) 170 | else () 171 | add_library (AddOn MODULE ${AddOnFiles}) 172 | endif () 173 | 174 | set_target_properties (AddOn PROPERTIES OUTPUT_NAME ${AC_ADDON_NAME}) 175 | if (WIN32) 176 | set_target_properties (AddOn PROPERTIES SUFFIX ".apx") 177 | else () 178 | set_target_properties (AddOn PROPERTIES BUNDLE TRUE) 179 | set_target_properties (AddOn PROPERTIES MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_LIST_DIR}/${AddOnResourcesFolder}/RFIX.mac/Info.plist") 180 | set_target_properties (AddOn PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/$") 181 | endif () 182 | 183 | if (WIN32) 184 | target_link_options (AddOn PUBLIC "${ResourceObjectsDir}/${AC_ADDON_NAME}.res") 185 | target_link_options (AddOn PUBLIC /export:GetExportedFuncAddrs,@1 /export:SetImportedFuncAddrs,@2) 186 | endif () 187 | 188 | target_include_directories (AddOn PUBLIC 189 | ${AddOnSourcesFolder} 190 | ${AC_API_DEVKIT_DIR}/Support/Inc 191 | ) 192 | 193 | if (WIN32) 194 | target_link_libraries (AddOn 195 | "$<$:${AC_API_DEVKIT_DIR}/Support/Lib/Win/ACAP_STATD.lib>" 196 | "$<$:${AC_API_DEVKIT_DIR}/Support/Lib/Win/ACAP_STAT.lib>" 197 | "$<$:${AC_API_DEVKIT_DIR}/Support/Lib/Win/ACAP_STAT.lib>" 198 | ) 199 | else () 200 | find_library (CocoaFramework Cocoa) 201 | target_link_libraries (AddOn 202 | "${AC_API_DEVKIT_DIR}/Support/Lib/Mactel/libACAP_STAT.a" 203 | ${CocoaFramework} 204 | ) 205 | endif () 206 | 207 | SetCompilerOptions (AddOn) 208 | add_dependencies (AddOn AddOnResources) 209 | 210 | get_filename_component (APIDevKitModulesDir "${AC_API_DEVKIT_DIR}/Support/Modules" ABSOLUTE) 211 | set (GSModules "") 212 | SubDirList (GSModules "${APIDevKitModulesDir}") 213 | foreach (gsModule ${GSModules}) 214 | AddGSModuleToIncludeDirectories (AddOn ${gsModule}) 215 | endforeach () 216 | if (WIN32) 217 | foreach (gsModule ${GSModules}) 218 | AddGSModulesToLinkLibraries (AddOn ${gsModule}) 219 | endforeach () 220 | else () 221 | AddGSModulesToLinkLibraries (AddOn "") 222 | endif () 223 | -------------------------------------------------------------------------------- /CompileResources.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import platform 4 | import subprocess 5 | import shutil 6 | import codecs 7 | 8 | class ResourceCompiler (object): 9 | def __init__ (self, devKitPath, languageCode, sourcesPath, resourcesPath, resourceObjectsPath): 10 | self.devKitPath = devKitPath 11 | self.languageCode = languageCode 12 | self.sourcesPath = sourcesPath 13 | self.resourcesPath = resourcesPath 14 | self.resourceObjectsPath = resourceObjectsPath 15 | self.resConvPath = None 16 | 17 | def IsValid (self): 18 | if self.resConvPath == None: 19 | return False 20 | if not os.path.exists (self.resConvPath): 21 | return False 22 | return True 23 | 24 | def GetPrecompiledResourceFilePath (self, grcFilePath): 25 | grcFileName = os.path.split (grcFilePath)[1] 26 | return os.path.join (self.resourceObjectsPath, grcFileName + '.i') 27 | 28 | def CompileLocalizedResources (self): 29 | locResourcesFolder = os.path.join (self.resourcesPath, 'R' + self.languageCode) 30 | grcFiles = self.CollectFilesFromFolderWithExtension (locResourcesFolder, '.grc') 31 | for grcFilePath in grcFiles: 32 | assert self.CompileResourceFile (grcFilePath), 'Failed to compile resource: ' + grcFilePath 33 | 34 | def CompileFixResources (self): 35 | fixResourcesFolder = os.path.join (self.resourcesPath, 'RFIX') 36 | grcFiles = self.CollectFilesFromFolderWithExtension (fixResourcesFolder, '.grc') 37 | for grcFilePath in grcFiles: 38 | assert self.CompileResourceFile (grcFilePath), 'Failed to compile resource: ' + grcFilePath 39 | 40 | def RunResConv (self, platformSign, codepage, inputFilePath, nativeResourceFileExtenion): 41 | imageResourcesFolder = os.path.join (self.resourcesPath, 'RFIX', 'Images') 42 | inputFileBaseName = os.path.splitext (os.path.split (inputFilePath)[1])[0] 43 | nativeResourceFilePath = os.path.join (self.resourceObjectsPath, inputFileBaseName + nativeResourceFileExtenion) 44 | result = subprocess.call ([ 45 | self.resConvPath, 46 | '-m', 'r', # resource compile mode 47 | '-T', platformSign, # target platform 48 | '-q', 'utf8', codepage, # code page conversion 49 | '-w', '2', # HiDPI image size list 50 | '-p', imageResourcesFolder, # image search path 51 | '-i', inputFilePath, # input path 52 | '-o', nativeResourceFilePath # output path 53 | ]) 54 | if result != 0: 55 | return False 56 | return True 57 | 58 | def CollectFilesFromFolderWithExtension (self, folderPath, extension): 59 | result = [] 60 | for fileName in os.listdir (folderPath): 61 | fileExtension = os.path.splitext (fileName)[1] 62 | if fileExtension.lower () == extension.lower (): 63 | fullPath = os.path.join (folderPath, fileName) 64 | result.append (fullPath) 65 | return result 66 | 67 | class WinResourceCompiler (ResourceCompiler): 68 | def __init__ (self, devKitPath, languageCode, sourcesPath, resourcesPath, resourceObjectsPath): 69 | super (WinResourceCompiler, self).__init__ (devKitPath, languageCode, sourcesPath, resourcesPath, resourceObjectsPath) 70 | self.resConvPath = os.path.join (devKitPath, 'Support', 'Tools', 'Win', 'ResConv.exe') 71 | 72 | def PrecompileResourceFile (self, grcFilePath): 73 | precompiledGrcFilePath = self.GetPrecompiledResourceFilePath (grcFilePath) 74 | result = subprocess.call ([ 75 | 'cl', 76 | '/nologo', 77 | '/X', 78 | '/EP', 79 | '/P', 80 | '/I', os.path.join (self.devKitPath, 'Support', 'Inc'), 81 | '/I', os.path.join (self.devKitPath, 'Support', 'Modules', 'DGLib'), 82 | '/I', self.sourcesPath, 83 | '/DWINDOWS', 84 | '/execution-charset:utf-8', 85 | '/Fi{}'.format (precompiledGrcFilePath), 86 | grcFilePath, 87 | ]) 88 | assert result == 0, "Failed to precompile resource " + grcFilePath 89 | return precompiledGrcFilePath 90 | 91 | def CompileResourceFile (self, grcFilePath): 92 | precompiledGrcFilePath = self.PrecompileResourceFile (grcFilePath) 93 | return self.RunResConv ('W', '1252', precompiledGrcFilePath, '.rc2') 94 | 95 | def GetNativeResourceFile (self): 96 | defaultNativeResourceFile = os.path.join (self.resourcesPath, 'RFIX.win', 'AddOnMain.rc2') 97 | if os.path.exists (defaultNativeResourceFile): 98 | return defaultNativeResourceFile 99 | 100 | existingNativeResourceFiles = self.CollectFilesFromFolderWithExtension (os.path.join (self.resourcesPath, 'RFIX.win'), '.rc2') 101 | assert existingNativeResourceFiles, 'Native resource file was not found at RFIX.win folder' 102 | 103 | return existingNativeResourceFiles[0] 104 | 105 | def CompileNativeResource (self, resultResourcePath): 106 | nativeResourceFile = self.GetNativeResourceFile () 107 | result = subprocess.call ([ 108 | 'rc', 109 | '/i', os.path.join (self.devKitPath, 'Support', 'Inc'), 110 | '/i', os.path.join (self.devKitPath, 'Support', 'Modules', 'DGLib'), 111 | '/i', self.sourcesPath, 112 | '/i', self.resourceObjectsPath, 113 | '/fo', resultResourcePath, 114 | nativeResourceFile 115 | ]) 116 | assert result == 0, 'Failed to compile native resource ' + nativeResourceFile 117 | 118 | class MacResourceCompiler (ResourceCompiler): 119 | def __init__ (self, devKitPath, languageCode, sourcesPath, resourcesPath, resourceObjectsPath): 120 | super (MacResourceCompiler, self).__init__ (devKitPath, languageCode, sourcesPath, resourcesPath, resourceObjectsPath) 121 | self.resConvPath = os.path.join (devKitPath, 'Support', 'Tools', 'OSX', 'ResConv') 122 | 123 | def PrecompileResourceFile (self, grcFilePath): 124 | precompiledGrcFilePath = self.GetPrecompiledResourceFilePath (grcFilePath) 125 | result = subprocess.call ([ 126 | 'clang', 127 | '-x', 'c++', 128 | '-E', 129 | '-P', 130 | '-Dmacintosh', 131 | '-I', os.path.join (self.devKitPath, 'Support', 'Inc'), 132 | '-I', os.path.join (self.devKitPath, 'Support', 'Modules', 'DGLib'), 133 | '-I', self.sourcesPath, 134 | '-o', precompiledGrcFilePath, 135 | grcFilePath, 136 | ]) 137 | assert result == 0, "Failed to precompile resource " + grcFilePath 138 | return precompiledGrcFilePath 139 | 140 | def CompileResourceFile (self, grcFilePath): 141 | precompiledGrcFilePath = self.PrecompileResourceFile (grcFilePath) 142 | return self.RunResConv ('M', 'utf16', precompiledGrcFilePath, '.ro') 143 | 144 | def CompileNativeResource (self, resultResourcePath): 145 | resultLocalizedResourcePath = os.path.join (resultResourcePath, 'English.lproj') 146 | if not os.path.exists (resultLocalizedResourcePath): 147 | os.makedirs (resultLocalizedResourcePath) 148 | resultLocalizableStringsPath = os.path.join (resultLocalizedResourcePath, 'Localizable.strings') 149 | resultLocalizableStringsFile = codecs.open (resultLocalizableStringsPath, 'w', 'utf-16') 150 | for fileName in os.listdir (self.resourceObjectsPath): 151 | filePath = os.path.join (self.resourceObjectsPath, fileName) 152 | extension = os.path.splitext (fileName)[1].lower () 153 | if extension == '.tif': 154 | shutil.copy (filePath, resultResourcePath) 155 | elif extension == '.rsrd': 156 | shutil.copy (filePath, resultLocalizedResourcePath) 157 | elif extension == '.strings': 158 | stringsFile = codecs.open (filePath, 'r', 'utf-16') 159 | resultLocalizableStringsFile.write (stringsFile.read ()) 160 | stringsFile.close () 161 | resultLocalizableStringsFile.close () 162 | 163 | def Main (argv): 164 | assert len (argv) == 7, 'Usage: CompileResources.py ' 165 | 166 | currentDir = os.path.dirname (os.path.abspath (__file__)) 167 | os.chdir (currentDir) 168 | 169 | languageCode = argv[1] 170 | devKitPath = os.path.abspath (argv[2]) 171 | sourcesPath = os.path.abspath (argv[3]) 172 | resourcesPath = os.path.abspath (argv[4]) 173 | resourceObjectsPath = os.path.abspath (argv[5]) 174 | resultResourcePath = os.path.abspath (argv[6]) 175 | 176 | resourceCompiler = None 177 | system = platform.system () 178 | if system == 'Windows': 179 | resourceCompiler = WinResourceCompiler (devKitPath, languageCode, sourcesPath, resourcesPath, resourceObjectsPath) 180 | elif system == 'Darwin': 181 | resourceCompiler = MacResourceCompiler (devKitPath, languageCode, sourcesPath, resourcesPath, resourceObjectsPath) 182 | 183 | assert resourceCompiler, 'Platform is not supported' 184 | assert resourceCompiler.IsValid (), 'Invalid resource compiler' 185 | 186 | resourceCompiler.CompileLocalizedResources () 187 | resourceCompiler.CompileFixResources () 188 | resourceCompiler.CompileNativeResource (resultResourcePath) 189 | 190 | return 0 191 | 192 | sys.exit (Main (sys.argv)) 193 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Tibor Lorántfy 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Additional JSON/Python Commands Add-On for Archicad 2 | 3 | This Add-On extends the JSON interface of Archicad by implementing new JSON commands. 4 | These JSON commands are **callable via Python**, see examples below. 5 | 6 | Download the Add-On or build it for your own platform and Archicad version. 7 | 8 | * [Download the Add-On for Archicad 26 for Windows platform](https://github.com/tlorantfy/archicad-additional-json-commands/releases/download/26.4/archicad-additional-json-commands.26.apx) 9 | * [Download the Add-On for Archicad 25 for Windows platform](https://github.com/tlorantfy/archicad-additional-json-commands/releases/download/26.3/archicad-additional-json-commands.25.apx) 10 | 11 | **Requires Archicad 25 or later.** 12 | 13 | # Implemented Commands 14 | 15 | - [Publish](#publish) 16 | - [GetProjectInfo](#getprojectinfo) 17 | - [TeamworkReceive](#teamworkreceive) 18 | - [GetArchicadLocation](#getarchicadlocation) 19 | - [Quit](#quit) 20 | - [ReloadLibraries](#reloadlibraries) 21 | - [MoveElements](#moveelements) 22 | - [CreateColumns](#createcolumns) 23 | - [CreateSlabs](#createslabs) 24 | - [CreateObjects](#createobjects) 25 | - [GetHotlinks](#gethotlinks) 26 | - [GetGDLParametersOfElements](#getgdlparametersofelements) 27 | - [ChangeGDLParametersOfElements](#changegdlparametersofelements) 28 | 29 | ## Publish 30 | Performs a publish operation on the currently opened project. Only the given publisher set will be published. 31 | ### Parameters 32 | * publisherSetName (required) 33 | * Type: string 34 | * The name of the publisher set. 35 | * outputPath 36 | * Type: string 37 | * Full local or LAN path for publishing. Optional, by default the path set in the settings of the publiser set will be used. 38 | ### Response 39 | * errorMessage 40 | * Type: string 41 | * The error message upon error. If the command executed successfully, then there is no response. 42 | ### Python Example 43 | ```python 44 | from archicad import ACConnection 45 | 46 | conn = ACConnection.connect () 47 | 48 | acc = conn.commands 49 | act = conn.types 50 | 51 | publisherSetNames = acc.GetPublisherSetNames () 52 | for publisherSetName in publisherSetNames: 53 | parameters = { 'publisherSetName': publisherSetName } 54 | acc.ExecuteAddOnCommand (act.AddOnCommandId ('AdditionalJSONCommands', 'Publish'), parameters) 55 | ``` 56 | 57 | ## GetProjectInfo 58 | Retrieves the location of the currently running Archicad executable. 59 | ### Parameters 60 | ### Response 61 | * isUntitled (required) 62 | * Type: string 63 | * True, if the project is not saved yet. 64 | * isTeamwork (required) 65 | * Type: string 66 | * True, if the project is a Teamwork (BIMcloud) project. 67 | * projectLocation 68 | * Type: string 69 | * The location of the project in the filesystem or a BIMcloud project reference. 70 | * projectPath 71 | * Type: string 72 | * The path of the project. A filesystem path or a BIMcloud server relative path. 73 | * projectName 74 | * Type: string 75 | * The name of the project. 76 | ### Python Example 77 | ```python 78 | from archicad import ACConnection 79 | 80 | conn = ACConnection.connect () 81 | 82 | acc = conn.commands 83 | act = conn.types 84 | 85 | response = acc.ExecuteAddOnCommand (act.AddOnCommandId ('AdditionalJSONCommands', 'GetProjectInfo')) 86 | isTeamwork = response['isTeamwork'] 87 | if not response['isUntitled']: 88 | projectLocation = response['projectLocation'] 89 | ``` 90 | 91 | ## TeamworkReceive 92 | Performs a receive operation on the currently opened Teamwork (BIMcloud) project. 93 | ### Parameters 94 | ### Response 95 | * errorMessage 96 | * Type: string 97 | * The error message upon error. If the command executed successfully, then there is no response. 98 | ### Python Example 99 | ```python 100 | from archicad import ACConnection 101 | 102 | conn = ACConnection.connect () 103 | 104 | acc = conn.commands 105 | act = conn.types 106 | 107 | acc.ExecuteAddOnCommand (act.AddOnCommandId ('AdditionalJSONCommands', 'TeamworkReceive')) 108 | ``` 109 | 110 | ## GetArchicadLocation 111 | Retrieves the location of the currently running Archicad executable. 112 | ### Parameters 113 | ### Response 114 | * archicadLocation (required) 115 | * Type: string 116 | * The location of the Archicad executable in the filesystem. 117 | ### Python Example 118 | ```python 119 | from archicad import ACConnection 120 | 121 | conn = ACConnection.connect () 122 | 123 | acc = conn.commands 124 | act = conn.types 125 | 126 | response = acc.ExecuteAddOnCommand (act.AddOnCommandId ('AdditionalJSONCommands', 'GetArchicadLocation')) 127 | archicadLocation = response['archicadLocation'] 128 | ``` 129 | 130 | ## Quit 131 | Performs a quit operation on the currently running Archicad instance. 132 | ### Parameters 133 | ### Response 134 | * errorMessage 135 | * Type: string 136 | * The error message upon error. If the command executed successfully, then there is no response. 137 | ### Python Example 138 | ```python 139 | from archicad import ACConnection 140 | 141 | conn = ACConnection.connect () 142 | 143 | acc = conn.commands 144 | act = conn.types 145 | 146 | acc.ExecuteAddOnCommand (act.AddOnCommandId ('AdditionalJSONCommands', 'TeamworkReceive')) 147 | ``` 148 | 149 | ## ReloadLibraries 150 | Reloads the libraries of the current Archicad project. 151 | ### Parameters 152 | ### Response 153 | * errorMessage 154 | * Type: string 155 | * The error message upon error. If the command executed successfully, then there is no response. 156 | ### Python Example 157 | ```python 158 | from archicad import ACConnection 159 | 160 | conn = ACConnection.connect () 161 | 162 | acc = conn.commands 163 | act = conn.types 164 | 165 | acc.ExecuteAddOnCommand (act.AddOnCommandId ('AdditionalJSONCommands', 'ReloadLibraries')) 166 | ``` 167 | 168 | ## MoveElements 169 | Moves elements with a given movement vector. 170 | ### Parameters 171 | * elementsWithMoveVectors (required) 172 | * Type: array 173 | * Items: 174 | * Type: object 175 | * Fields: 176 | * elementId (required) 177 | * Type: Element identifier object (guid field) 178 | * moveVector (required) 179 | * Type: 3D vector object (x, y, z fields). 180 | ### Response 181 | * errorMessage 182 | * Type: string 183 | * The error message upon error. If the command executed successfully, then there is no response. 184 | ### Python Example 185 | ```python 186 | from archicad import ACConnection 187 | 188 | conn = ACConnection.connect () 189 | 190 | acc = conn.commands 191 | act = conn.types 192 | 193 | objects = acc.GetElementsByType ('Object') 194 | elementsWithMoveVectors = [{'elementId': {'guid': str (object.elementId.guid)}, 'moveVector': {'x': 1.0, 'y': 1.0, 'z': 0.0}} for object in objects] 195 | 196 | acc.ExecuteAddOnCommand (act.AddOnCommandId ('AdditionalJSONCommands', 'MoveElements'), {'elementsWithMoveVectors': elementsWithMoveVectors}) 197 | ``` 198 | 199 | ## CreateColumns 200 | Creates columns. The given coordinates will be origos of the columns. 201 | ### Parameters 202 | * coordinates (required) 203 | * Type: array of 3D coordinates with x,y,z values 204 | ### Response 205 | * errorMessage 206 | * Type: string 207 | * The error message upon error. If the command executed successfully, then there is no response. 208 | ### Python Example 209 | ```python 210 | from archicad import ACConnection 211 | 212 | conn = ACConnection.connect () 213 | 214 | acc = conn.commands 215 | act = conn.types 216 | 217 | storyHeight = 3.0 218 | origosOfNewColumns = [{'x': x*2, 'y': y*2, 'z': z*storyHeight} for x in range(10) for y in range(10) for z in range(2)] 219 | 220 | acc.ExecuteAddOnCommand (act.AddOnCommandId ('AdditionalJSONCommands', 'CreateColumns'), {'coordinates': origosOfNewColumns}) 221 | ``` 222 | 223 | ## CreateSlabs 224 | Creates polygonal slabs. The given coordinates will define the polygon of the edges. 225 | ### Parameters 226 | * slabs (required) 227 | * Type: object 228 | * Fields: 229 | * level (required) 230 | * Type: number 231 | * The elevation of the slab, the Z coordinate of the reference line. 232 | * polygonCoordinates (required) 233 | * Type: array of 2D coordinates with x,y values. 234 | * holes (optional) 235 | * polygonCoordinates (optional) 236 | * Type: array of 2D coordinates with x,y values. 237 | ### Response 238 | * errorMessage 239 | * Type: string 240 | * The error message upon error. If the command executed successfully, then there is no response. 241 | ### Python Example 242 | ```python 243 | from archicad import ACConnection 244 | 245 | conn = ACConnection.connect () 246 | 247 | acc = conn.commands 248 | act = conn.types 249 | 250 | origo = {'x': 0, 'y': 0, 'z': 0} 251 | slabWidth = 6.0 252 | slabHoleWidth = 2.0 253 | storyHeight = 3.0 254 | 255 | slabPolygonCoordinates = [ 256 | {'x': +3.0, 'y': -3.0}, 257 | {'x': +3.0, 'y': +3.0}, 258 | {'x': -3.0, 'y': +3.0}, 259 | {'x': -3.0, 'y': -3.0} 260 | ] 261 | slabHolePolygonCoordinates = [ 262 | {'x': +1.0, 'y': -1.0}, 263 | {'x': +1.0, 'y': +1.0}, 264 | {'x': -1.0, 'y': +1.0}, 265 | {'x': -1.0, 'y': -1.0} 266 | ] 267 | 268 | slabs = [{ 269 | 'level': i * storyHeight, 270 | 'polygonCoordinates': slabPolygonCoordinates, 271 | 'holes': [{'polygonCoordinates': slabHolePolygonCoordinates}] 272 | } for i in range(3)] 273 | 274 | acc.ExecuteAddOnCommand (act.AddOnCommandId ('AdditionalJSONCommands', 'CreateSlabs'), {'slabs': slabs}) 275 | ``` 276 | 277 | ## CreateObjects 278 | Creates library part based objects. The given coordinate will be the origo of the object. 279 | ### Parameters 280 | * objects (required) 281 | * Type: object 282 | * Fields: 283 | * name (required) 284 | * Type: string 285 | * The name of the library part. 286 | * coordinate (required) 287 | * Type: 3D coordinates with x,y,z values. 288 | * dimensions (required) 289 | * Type: Size coordinates with x,y,z values. 290 | ### Response 291 | * errorMessage 292 | * Type: string 293 | * The error message upon error. If the command executed successfully, then there is no response. 294 | ### Python Example 295 | ```python 296 | treeParameters = [{'name': 'Tree Model Detailed 26', 297 | 'coordinate': {'x': 0, 'y': 0, 'z': 0}, 298 | 'dimensions': {'x': 2, 'y': 2, 'z': 10}}] 299 | acc.ExecuteAddOnCommand (act.AddOnCommandId ('AdditionalJSONCommands', 'CreateObjects'), {'objects': treeParameters}) 300 | ``` 301 | 302 | ## GetHotlinks 303 | Get the file system locations (path) of the hotlink modules. The hotlinks can have tree hierarchy in the project. 304 | ### Response 305 | * hotlinks (required) 306 | * Type: array 307 | * List of hotlinks with locations and the children in the tree hierarchy. 308 | ### Python Example 309 | ```python 310 | from archicad import ACConnection 311 | 312 | conn = ACConnection.connect () 313 | 314 | acc = conn.commands 315 | act = conn.types 316 | 317 | print (acc.ExecuteAddOnCommand (act.AddOnCommandId ('AdditionalJSONCommands', 'GetHotlinks'))) 318 | ``` 319 | 320 | ## GetGDLParametersOfElements 321 | Get all the GDL parameters (name, type, value) of the given elements. 322 | ### Parameters 323 | * elements (required) 324 | * Type: array 325 | * Items: 326 | * Type: object 327 | * Fields: 328 | * elementId (required) 329 | * Type: Element identifier object (guid field) 330 | ### Response 331 | * gdlParametersOfElements (required) 332 | * Type: array of GDL parameters dictionary. 333 | ### Python Example 334 | ```python 335 | from archicad import ACConnection 336 | 337 | conn = ACConnection.connect () 338 | 339 | acc = conn.commands 340 | act = conn.types 341 | 342 | elements = [ { 'elementId' : { 'guid' : str (e.elementId.guid) } } for e in acc.GetElementsByType ('Object') ] 343 | 344 | print (acc.ExecuteAddOnCommand (act.AddOnCommandId ('AdditionalJSONCommands', 'GetGDLParametersOfElements', { 'elements' : elements }))) 345 | ``` 346 | 347 | ## ChangeGDLParametersOfElements 348 | Changes the given GDL parameters of the given elements. 349 | ### Parameters 350 | * elementsWithGDLParameters (required) 351 | * Type: array 352 | * Items: 353 | * Type: object 354 | * Fields: 355 | * elementId (required) 356 | * Type: Element identifier object (guid field) 357 | * gdlParameters (required) 358 | * Type: The dictionary of GDL parameters with the new values. 359 | ### Response 360 | * errorMessage 361 | * Type: string 362 | * The error message upon error. If the command executed successfully, then there is no response. 363 | ### Python Example 364 | ```python 365 | from archicad import ACConnection 366 | 367 | conn = ACConnection.connect () 368 | 369 | acc = conn.commands 370 | act = conn.types 371 | 372 | elementsWithGDLParameters = [ { 'elementId' : { 'guid' : str (e.elementId.guid) }, 'gdlParameters' : { 'gs_cont_pen' : 95 } } for e in acc.GetElementsByType ('Object') ] 373 | 374 | print (acc.ExecuteAddOnCommand (act.AddOnCommandId ('AdditionalJSONCommands', 'ChangeGDLParametersOfElements', { 'elementsWithGDLParameters' : elementsWithGDLParameters }))) 375 | ``` -------------------------------------------------------------------------------- /RFIX.mac/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleInfoDictionaryVersion 6 | 6.0 7 | CFBundleIdentifier 8 | com.tlorantfy.archicad-additional-json-commands 9 | CFBundleName 10 | archicad-additional-json-commands 11 | CFBundleGetInfoString 12 | This Add-On implements additional JSON/Python commands. 13 | CFBundleShortVersionString 14 | 1.0.0 15 | CFBundlePackageType 16 | .APX 17 | CFBundleSignature 18 | GSAP 19 | CFBundleVersion 20 | 1.0.0 21 | CFBundleDevelopmentRegion 22 | English 23 | CFBundleIconFile 24 | ArchiCADPlugin.icns 25 | LSMinimumSystemVersion 26 | 10.11.0 27 | LSRequiresCarbon 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /RFIX.win/AdditionalJSONCommands.rc2: -------------------------------------------------------------------------------- 1 | #include "AdditionalJSONCommands.grc.rc2" 2 | #include "AdditionalJSONCommandsFix.grc.rc2" 3 | 4 | 5 | 1 ICON LOADONCALL MOVEABLE IMPURE ACAP.ico 6 | -------------------------------------------------------------------------------- /RFIX/AdditionalJSONCommandsFix.grc: -------------------------------------------------------------------------------- 1 | 'MDID' 32500 "Add-On Identifier" { 2 | 628121456 3 | 1482304358 4 | } 5 | -------------------------------------------------------------------------------- /RINT/AdditionalJSONCommands.grc: -------------------------------------------------------------------------------- 1 | 'STR#' 32000 "Add-on Name and Description" { 2 | /* [ 1] */ "Additional JSON/Python Commands" 3 | /* [ 2] */ "This Add-On implements additional JSON/Python commands." 4 | } -------------------------------------------------------------------------------- /Src/APIEnvir.h: -------------------------------------------------------------------------------- 1 | // ***************************************************************************** 2 | // General settings for AddOn developments 3 | // ***************************************************************************** 4 | 5 | #ifndef _APIENVIR_H_ 6 | #define _APIENVIR_H_ 7 | 8 | 9 | #if defined (_MSC_VER) 10 | #if !defined (WINDOWS) 11 | #define WINDOWS 12 | #endif 13 | #endif 14 | 15 | #if defined (WINDOWS) 16 | #include "Win32Interface.hpp" 17 | #endif 18 | 19 | #if defined (macintosh) 20 | #include 21 | #endif 22 | 23 | #if !defined (ACExtension) 24 | #define ACExtension 25 | #endif 26 | 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /Src/AdditionalJSONCommand.cpp: -------------------------------------------------------------------------------- 1 | #include "AdditionalJSONCommand.hpp" 2 | #include "ObjectState.hpp" 3 | #include "FileSystem.hpp" 4 | #include "OnExit.hpp" 5 | 6 | 7 | constexpr const char* AdditionalJSONCommandsNamespace = "AdditionalJSONCommands"; 8 | constexpr const char* ErrorResponseField = "error"; 9 | constexpr const char* ErrorCodeResponseField = "code"; 10 | constexpr const char* ErrorMessageResponseField = "message"; 11 | constexpr const char* GuidField = "guid"; 12 | 13 | 14 | GS::String AdditionalJSONCommand::GetNamespace () const 15 | { 16 | return AdditionalJSONCommandsNamespace; 17 | } 18 | 19 | 20 | GS::Optional AdditionalJSONCommand::GetSchemaDefinitions () const 21 | { 22 | return {}; 23 | } 24 | 25 | 26 | GS::Optional AdditionalJSONCommand::GetInputParametersSchema () const 27 | { 28 | return {}; 29 | } 30 | 31 | 32 | GS::Optional AdditionalJSONCommand::GetResponseSchema () const 33 | { 34 | return GS::UniString::Printf (R"({ 35 | "type": "object", 36 | "properties": { 37 | "%s": { 38 | "$ref": "APITypes.json#/definitions/Error" 39 | } 40 | }, 41 | "additionalProperties": false, 42 | "required": [] 43 | })", 44 | ErrorResponseField); 45 | } 46 | 47 | 48 | void AdditionalJSONCommand::OnResponseValidationFailed (const GS::ObjectState& /*response*/) const 49 | { 50 | } 51 | 52 | #ifdef ServerMainVers_2600 53 | bool AdditionalJSONCommand::IsProcessWindowVisible () const 54 | { 55 | return false; 56 | } 57 | #endif 58 | 59 | 60 | GS::ObjectState AdditionalJSONCommand::CreateErrorResponse (APIErrCodes errorCode, const GS::UniString& errorMessage) 61 | { 62 | GS::ObjectState error; 63 | error.Add (ErrorCodeResponseField, errorCode); 64 | error.Add (ErrorMessageResponseField, errorMessage.ToCStr ().Get ()); 65 | return GS::ObjectState (ErrorResponseField, error); 66 | } 67 | 68 | 69 | API_Guid AdditionalJSONCommand::GetGuidFromElementIdField (const GS::ObjectState& os) 70 | { 71 | GS::String guid; 72 | os.Get (GuidField, guid); 73 | return APIGuidFromString (guid.ToCStr ()); 74 | } 75 | 76 | 77 | namespace Utilities { 78 | 79 | 80 | GS::Array> GetStoryLevels () 81 | { 82 | GS::Array> storyLevels; 83 | API_StoryInfo storyInfo = {}; 84 | 85 | GSErrCode err = ACAPI_Environment (APIEnv_GetStorySettingsID, &storyInfo); 86 | if (err == NoError) { 87 | const short numberOfStories = storyInfo.lastStory - storyInfo.firstStory + 1; 88 | for (short i = 0; i < numberOfStories; ++i) { 89 | storyLevels.PushNew ((*storyInfo.data)[i].index, (*storyInfo.data)[i].level); 90 | } 91 | BMKillHandle ((GSHandle*) &storyInfo.data); 92 | } 93 | return storyLevels; 94 | } 95 | 96 | 97 | short GetFloorIndexAndOffset (double zPos, const GS::Array>& storyLevels, double& zOffset) 98 | { 99 | if (storyLevels.IsEmpty ()) { 100 | zOffset = zPos; 101 | return 0; 102 | } 103 | 104 | auto* lastStoryIndexAndLevel = &storyLevels[0]; 105 | for (const auto& storyIndexAndLevel : storyLevels) { 106 | if (storyIndexAndLevel.second > zPos) { 107 | break; 108 | } 109 | lastStoryIndexAndLevel = &storyIndexAndLevel; 110 | } 111 | 112 | zOffset = zPos - lastStoryIndexAndLevel->second; 113 | return lastStoryIndexAndLevel->first; 114 | } 115 | 116 | 117 | API_Coord Get2DCoordinateFromObjectState (const GS::ObjectState& objectState) 118 | { 119 | API_Coord coordinate = {}; 120 | objectState.Get ("x", coordinate.x); 121 | objectState.Get ("y", coordinate.y); 122 | return coordinate; 123 | } 124 | 125 | 126 | API_Coord3D Get3DCoordinateFromObjectState (const GS::ObjectState& objectState) 127 | { 128 | API_Coord3D coordinate = {}; 129 | objectState.Get ("x", coordinate.x); 130 | objectState.Get ("y", coordinate.y); 131 | objectState.Get ("z", coordinate.z); 132 | return coordinate; 133 | } 134 | 135 | 136 | constexpr const char* ParameterValueFieldName = "value"; 137 | 138 | 139 | void SetValueInteger (API_ChangeParamType& changeParam, 140 | const GS::ObjectState& parameterDetails) 141 | { 142 | Int32 value; 143 | parameterDetails.Get (ParameterValueFieldName, value); 144 | changeParam.realValue = value; 145 | } 146 | 147 | 148 | void SetValueDouble (API_ChangeParamType& changeParam, 149 | const GS::ObjectState& parameterDetails) 150 | { 151 | double value; 152 | parameterDetails.Get (ParameterValueFieldName, value); 153 | changeParam.realValue = value; 154 | } 155 | 156 | 157 | void SetValueOnOff (API_ChangeParamType& changeParam, 158 | const GS::ObjectState& parameterDetails) 159 | { 160 | GS::String value; 161 | parameterDetails.Get (ParameterValueFieldName, value); 162 | changeParam.realValue = (value == "Off" ? 0 : 1); 163 | } 164 | 165 | 166 | void SetValueBool (API_ChangeParamType& changeParam, 167 | const GS::ObjectState& parameterDetails) 168 | { 169 | bool value; 170 | parameterDetails.Get (ParameterValueFieldName, value); 171 | changeParam.realValue = (value ? 0 : 1); 172 | } 173 | 174 | 175 | void SetValueString (API_ChangeParamType& changeParam, 176 | const GS::ObjectState& parameterDetails) 177 | { 178 | GS::UniString value; 179 | parameterDetails.Get (ParameterValueFieldName, value); 180 | 181 | constexpr USize MaxStrValueLength = 512; 182 | 183 | static GS::uchar_t strValuePtr[MaxStrValueLength]; 184 | GS::ucscpy (strValuePtr, value.ToUStr (0, GS::Min(value.GetLength (), MaxStrValueLength)).Get ()); 185 | 186 | changeParam.uStrValue = strValuePtr; 187 | } 188 | 189 | 190 | void SetValueInteger (API_AddParType& addPar, 191 | const GS::ObjectState& parameterDetails) 192 | { 193 | Int32 value; 194 | parameterDetails.Get (ParameterValueFieldName, value); 195 | addPar.value.real = value; 196 | } 197 | 198 | 199 | void SetValueDouble (API_AddParType& addPar, 200 | const GS::ObjectState& parameterDetails) 201 | { 202 | double value; 203 | parameterDetails.Get (ParameterValueFieldName, value); 204 | addPar.value.real = value; 205 | } 206 | 207 | 208 | void SetValueOnOff (API_AddParType& addPar, 209 | const GS::ObjectState& parameterDetails) 210 | { 211 | GS::String value; 212 | parameterDetails.Get (ParameterValueFieldName, value); 213 | addPar.value.real = (value == "Off" ? 0 : 1); 214 | } 215 | 216 | 217 | void SetValueBool (API_AddParType& addPar, 218 | const GS::ObjectState& parameterDetails) 219 | { 220 | bool value; 221 | parameterDetails.Get (ParameterValueFieldName, value); 222 | addPar.value.real = (value ? 0 : 1); 223 | } 224 | 225 | 226 | void SetValueString (API_AddParType& addPar, 227 | const GS::ObjectState& parameterDetails) 228 | { 229 | GS::UniString value; 230 | parameterDetails.Get (ParameterValueFieldName, value); 231 | 232 | GS::ucscpy (addPar.value.uStr, value.ToUStr (0, GS::Min(value.GetLength (), (USize)API_UAddParStrLen)).Get ()); 233 | } 234 | 235 | 236 | void ChangeParams (API_AddParType**& params, const GS::HashTable& changeParamsDictionary) 237 | { 238 | const GSSize nParams = BMGetHandleSize ((GSHandle) params) / sizeof (API_AddParType); 239 | GS::HashTable gdlParametersTypeDictionary; 240 | for (GSIndex ii = 0; ii < nParams; ++ii) { 241 | API_AddParType& actParam = (*params)[ii]; 242 | 243 | const GS::String name(actParam.name); 244 | const auto* value = changeParamsDictionary.GetPtr (name); 245 | if (value == nullptr) 246 | continue; 247 | 248 | switch (actParam.typeID) { 249 | case APIParT_Integer: 250 | case APIParT_PenCol: SetValueInteger (actParam, *value); break; 251 | case APIParT_ColRGB: 252 | case APIParT_Intens: 253 | case APIParT_Length: 254 | case APIParT_RealNum: 255 | case APIParT_Angle: SetValueDouble (actParam, *value); break; 256 | case APIParT_LightSw: SetValueOnOff (actParam, *value); break; 257 | case APIParT_Boolean: SetValueBool (actParam, *value); break; 258 | case APIParT_LineTyp: 259 | case APIParT_Mater: 260 | case APIParT_FillPat: 261 | case APIParT_BuildingMaterial: 262 | case APIParT_Profile: SetValueInteger (actParam, *value); break; 263 | case APIParT_CString: 264 | case APIParT_Title: SetValueString (actParam, *value); break; 265 | default: 266 | case APIParT_Dictionary: 267 | // Not supported by the Archicad API yet 268 | break; 269 | } 270 | } 271 | } 272 | 273 | 274 | } -------------------------------------------------------------------------------- /Src/AdditionalJSONCommand.hpp: -------------------------------------------------------------------------------- 1 | #if !defined (ADDITIONALJSONCOMMAND_HPP) 2 | #define ADDITIONALJSONCOMMAND_HPP 3 | 4 | #pragma once 5 | 6 | #include "APIEnvir.h" 7 | #include "ACAPinc.h" 8 | 9 | 10 | class AdditionalJSONCommand : public API_AddOnCommand { 11 | public: 12 | virtual GS::String GetNamespace () const override; 13 | virtual GS::Optional GetSchemaDefinitions () const override; 14 | virtual GS::Optional GetInputParametersSchema () const override; 15 | virtual GS::Optional GetResponseSchema () const override; 16 | virtual API_AddOnCommandExecutionPolicy GetExecutionPolicy () const override { return API_AddOnCommandExecutionPolicy::ScheduleForExecutionOnMainThread; } 17 | virtual void OnResponseValidationFailed (const GS::ObjectState& response) const override; 18 | #ifdef ServerMainVers_2600 19 | virtual bool IsProcessWindowVisible () const override; 20 | #endif 21 | 22 | static GS::ObjectState CreateErrorResponse (APIErrCodes errorCode, const GS::UniString& errorMessage); 23 | static API_Guid GetGuidFromElementIdField (const GS::ObjectState& os); 24 | }; 25 | 26 | constexpr const char* ElementIdField = "elementId"; 27 | 28 | namespace Utilities { 29 | GS::Array> GetStoryLevels (); 30 | short GetFloorIndexAndOffset (double zPos, const GS::Array>& storyLevels, double& zOffset); 31 | 32 | API_Coord Get2DCoordinateFromObjectState (const GS::ObjectState& objectState); 33 | API_Coord3D Get3DCoordinateFromObjectState (const GS::ObjectState& objectState); 34 | 35 | void SetValueInteger (API_ChangeParamType& changeParam, 36 | const GS::ObjectState& parameterDetails); 37 | void SetValueDouble (API_ChangeParamType& changeParam, 38 | const GS::ObjectState& parameterDetails); 39 | void SetValueOnOff (API_ChangeParamType& changeParam, 40 | const GS::ObjectState& parameterDetails); 41 | void SetValueBool (API_ChangeParamType& changeParam, 42 | const GS::ObjectState& parameterDetails); 43 | void SetValueString (API_ChangeParamType& changeParam, 44 | const GS::ObjectState& parameterDetails); 45 | void SetValueInteger (API_AddParType& addPar, 46 | const GS::ObjectState& parameterDetails); 47 | void SetValueDouble (API_AddParType& addPar, 48 | const GS::ObjectState& parameterDetails); 49 | void SetValueOnOff (API_AddParType& addPar, 50 | const GS::ObjectState& parameterDetails); 51 | void SetValueBool (API_AddParType& addPar, 52 | const GS::ObjectState& parameterDetails); 53 | void SetValueString (API_AddParType& addPar, 54 | const GS::ObjectState& parameterDetails); 55 | 56 | void ChangeParams (API_AddParType**& params, const GS::HashTable& changeParamsDictionary); 57 | } 58 | 59 | #endif -------------------------------------------------------------------------------- /Src/ChangeGDLParametersOfElementsCommand.cpp: -------------------------------------------------------------------------------- 1 | #include "ChangeGDLParametersOfElementsCommand.hpp" 2 | #include "ObjectState.hpp" 3 | 4 | 5 | GS::String ChangeGDLParametersOfElementsCommand::GetName () const 6 | { 7 | return "ChangeGDLParametersOfElements"; 8 | } 9 | 10 | 11 | constexpr const char* GDLParametersDictionarySchemaName = "GDLParametersDictionary"; 12 | constexpr const char* GDLParameterDetailsSchemaName = "GDLParameterDetails"; 13 | constexpr const char* ParameterTypeFieldName = "type"; 14 | constexpr const char* ParameterIndex1FieldName = "index1"; 15 | constexpr const char* ParameterIndex2FieldName = "index2"; 16 | constexpr const char* ParameterValueFieldName = "value"; 17 | constexpr const char* AttributeIndexFieldName = "index"; 18 | constexpr const char* AttributeNameFieldName = "name"; 19 | 20 | 21 | GS::Optional ChangeGDLParametersOfElementsCommand::GetSchemaDefinitions () const 22 | { 23 | return GS::UniString::Printf (R"({ 24 | "%s": { 25 | "type": "object", 26 | "description": "The dictionary of GDL parameters. The name of the parameter is the key and the details of the parameter are in the value." 27 | }, 28 | "%s": { 29 | "type": "object", 30 | "description": "Details of GDL parameter with value.", 31 | "properties": { 32 | "%s": { 33 | "type": "string", 34 | "description": "The 1st index of array (in case of array value)." 35 | }, 36 | "%s": { 37 | "type": "string", 38 | "description": "The 2nd index of array (in case of array value)." 39 | } 40 | }, 41 | "additionalProperties": true, 42 | "required": [ 43 | ] 44 | } 45 | })", 46 | GDLParametersDictionarySchemaName, 47 | GDLParameterDetailsSchemaName, 48 | ParameterIndex1FieldName, 49 | ParameterIndex2FieldName 50 | ); 51 | } 52 | 53 | 54 | constexpr const char* ElementsWithGDLParametersDictionaryParameterField = "elementsWithGDLParameters"; 55 | constexpr const char* GDLParametersDictionaryField = "gdlParameters"; 56 | 57 | 58 | GS::Optional ChangeGDLParametersOfElementsCommand::GetInputParametersSchema () const 59 | { 60 | return GS::UniString::Printf (R"({ 61 | "type": "object", 62 | "properties": { 63 | "%s": { 64 | "type": "array", 65 | "description": "The elements with GDL parameters dictionary pairs.", 66 | "items": { 67 | "type": "object", 68 | "properties": { 69 | "%s": { 70 | "$ref": "APITypes.json#/definitions/ElementId" 71 | }, 72 | "%s": { 73 | "type": "object", 74 | "description": "The dictionary of GDL parameters. The name of the parameter is the key and the details of the parameter are in the value." 75 | } 76 | }, 77 | "additionalProperties": false, 78 | "required": [ 79 | "%s", 80 | "%s" 81 | ] 82 | } 83 | } 84 | }, 85 | "additionalProperties": false, 86 | "required": [ 87 | "%s" 88 | ] 89 | })", 90 | ElementsWithGDLParametersDictionaryParameterField, 91 | ElementIdField, 92 | GDLParametersDictionaryField, 93 | ElementIdField, 94 | GDLParametersDictionaryField, 95 | ElementsWithGDLParametersDictionaryParameterField 96 | ); 97 | } 98 | 99 | 100 | GS::ObjectState ChangeGDLParametersOfElementsCommand::Execute (const GS::ObjectState& parameters, GS::ProcessControl& /*processControl*/) const 101 | { 102 | GS::Array elementsWithGDLParameters; 103 | parameters.Get (ElementsWithGDLParametersDictionaryParameterField, elementsWithGDLParameters); 104 | 105 | bool invalidParameter = false; 106 | bool notAbleToChangeParameter = false; 107 | GS::String badParameterName; 108 | 109 | API_Guid elemGuid; 110 | const APIErrCodes err = (APIErrCodes) ACAPI_CallUndoableCommand ("Change GDL Parameters of Elements", [&] () -> GSErrCode { 111 | GSErrCode err = NoError; 112 | for (const GS::ObjectState& elementWithGDLParameters : elementsWithGDLParameters) { 113 | const GS::ObjectState* elementId = elementWithGDLParameters.Get (ElementIdField); 114 | if (elementId == nullptr) { 115 | continue; 116 | } 117 | 118 | const GS::ObjectState* gdlParameters = elementWithGDLParameters.Get (GDLParametersDictionaryField); 119 | if (gdlParameters == nullptr) { 120 | continue; 121 | } 122 | 123 | elemGuid = GetGuidFromElementIdField (*elementId); 124 | 125 | API_ParamOwnerType paramOwner = {}; 126 | 127 | paramOwner.libInd = 0; 128 | #ifdef ServerMainVers_2600 129 | paramOwner.type = API_ObjectID; 130 | #else 131 | paramOwner.typeID = API_ObjectID; 132 | #endif 133 | paramOwner.guid = elemGuid; 134 | 135 | err = ACAPI_Goodies (APIAny_OpenParametersID, ¶mOwner); 136 | if (err == NoError) { 137 | API_GetParamsType getParams = {}; 138 | err = ACAPI_Goodies (APIAny_GetActParametersID, &getParams); 139 | if (err == NoError) { 140 | const GSSize nParams = BMGetHandleSize ((GSHandle) getParams.params) / sizeof (API_AddParType); 141 | GS::HashTable gdlParametersTypeDictionary; 142 | for (GSIndex ii = 0; ii < nParams; ++ii) { 143 | const API_AddParType& actParam = (*getParams.params)[ii]; 144 | 145 | if (actParam.typeID != APIParT_Separator) { 146 | gdlParametersTypeDictionary.Add (GS::String (actParam.name), actParam.typeID); 147 | } 148 | } 149 | 150 | GS::HashTable changeParamsDictionary; 151 | gdlParameters->EnumerateFields ([&] (const GS::String& parameterName) { 152 | changeParamsDictionary.Add (parameterName, gdlParameters->Get (parameterName)); 153 | }); 154 | 155 | API_ChangeParamType changeParam = {}; 156 | for (const auto& kv : changeParamsDictionary) { 157 | const GS::String& parameterName = *kv.key; 158 | const GS::ObjectState& parameterDetails = **kv.value; 159 | 160 | 161 | if (!gdlParametersTypeDictionary.ContainsKey (parameterName)) { 162 | invalidParameter = true; 163 | badParameterName = parameterName; 164 | return APIERR_BADPARS; 165 | } 166 | 167 | CHTruncate (parameterName.ToCStr (), changeParam.name, sizeof (changeParam.name)); 168 | if (parameterDetails.Contains (ParameterIndex1FieldName)) { 169 | parameterDetails.Get (ParameterIndex1FieldName, changeParam.ind1); 170 | if (parameterDetails.Contains (ParameterIndex2FieldName)) { 171 | parameterDetails.Get (ParameterIndex2FieldName, changeParam.ind2); 172 | } 173 | } 174 | 175 | switch (gdlParametersTypeDictionary[parameterName]) { 176 | case APIParT_Integer: 177 | case APIParT_PenCol: Utilities::SetValueInteger (changeParam, parameterDetails); break; 178 | case APIParT_ColRGB: 179 | case APIParT_Intens: 180 | case APIParT_Length: 181 | case APIParT_RealNum: 182 | case APIParT_Angle: Utilities::SetValueDouble (changeParam, parameterDetails); break; 183 | case APIParT_LightSw: Utilities::SetValueOnOff (changeParam, parameterDetails); break; 184 | case APIParT_Boolean: Utilities::SetValueBool (changeParam, parameterDetails); break; 185 | case APIParT_LineTyp: 186 | case APIParT_Mater: 187 | case APIParT_FillPat: 188 | case APIParT_BuildingMaterial: 189 | case APIParT_Profile: Utilities::SetValueInteger (changeParam, parameterDetails); break; 190 | case APIParT_CString: 191 | case APIParT_Title: Utilities::SetValueString (changeParam, parameterDetails); break; 192 | default: 193 | case APIParT_Dictionary: 194 | // Not supported by the Archicad API yet 195 | break; 196 | } 197 | 198 | err = ACAPI_Goodies (APIAny_ChangeAParameterID, &changeParam); 199 | if (err != NoError) { 200 | notAbleToChangeParameter = true; 201 | badParameterName = parameterName; 202 | return APIERR_BADPARS; 203 | } 204 | 205 | ACAPI_DisposeAddParHdl (&getParams.params); 206 | ACAPI_Goodies (APIAny_GetActParametersID, &getParams); 207 | } 208 | 209 | API_Element element = {}; 210 | element.header.guid = elemGuid; 211 | 212 | err = ACAPI_Element_Get (&element); 213 | if (err == NoError) { 214 | API_Element mask = {}; 215 | API_ElementMemo memo = {}; 216 | 217 | ACAPI_ELEMENT_MASK_CLEAR (mask); 218 | #ifdef ServerMainVers_2600 219 | switch (element.header.type.typeID) { 220 | #else 221 | switch (element.header.typeID) { 222 | #endif 223 | case API_ObjectID: 224 | element.object.xRatio = getParams.a; 225 | element.object.yRatio = getParams.b; 226 | ACAPI_ELEMENT_MASK_SET (mask, API_ObjectType, xRatio); 227 | ACAPI_ELEMENT_MASK_SET (mask, API_ObjectType, yRatio); 228 | break; 229 | case API_WindowID: 230 | case API_DoorID: 231 | element.window.openingBase.width = getParams.a; 232 | element.window.openingBase.height = getParams.b; 233 | ACAPI_ELEMENT_MASK_SET (mask, API_WindowType, openingBase.width); 234 | ACAPI_ELEMENT_MASK_SET (mask, API_WindowType, openingBase.height); 235 | break; 236 | case API_SkylightID: 237 | element.skylight.openingBase.width = getParams.a; 238 | element.skylight.openingBase.height = getParams.b; 239 | ACAPI_ELEMENT_MASK_SET (mask, API_SkylightType, openingBase.width); 240 | ACAPI_ELEMENT_MASK_SET (mask, API_SkylightType, openingBase.height); 241 | break; 242 | default: 243 | // Not supported yet 244 | break; 245 | } 246 | 247 | memo.params = getParams.params; 248 | err = ACAPI_Element_Change (&element, &mask, &memo, APIMemoMask_AddPars, true); 249 | } 250 | } 251 | 252 | ACAPI_Goodies (APIAny_CloseParametersID); 253 | ACAPI_DisposeAddParHdl (&getParams.params); 254 | } 255 | } 256 | 257 | return err; 258 | }); 259 | 260 | if (err != NoError) { 261 | GS::UniString errorMsg; 262 | if (invalidParameter) { 263 | errorMsg = GS::UniString::Printf ("Invalid input: %s is not a GDL parameter of element %T", badParameterName.ToCStr (), APIGuidToString (elemGuid).ToPrintf ()); 264 | } else if (notAbleToChangeParameter) { 265 | errorMsg = GS::UniString::Printf ("Failed to change parameter %s of element with guid %T", badParameterName.ToCStr (), APIGuidToString (elemGuid).ToPrintf ()); 266 | } 267 | 268 | errorMsg = GS::UniString::Printf ("Failed to change parameters of element with guid %T", APIGuidToString (elemGuid).ToPrintf ()); 269 | return CreateErrorResponse ((APIErrCodes) err, errorMsg); 270 | } 271 | 272 | return {}; 273 | } -------------------------------------------------------------------------------- /Src/ChangeGDLParametersOfElementsCommand.hpp: -------------------------------------------------------------------------------- 1 | #if !defined (CHANGEGDLPARAMETERSOFELEMENTSCOMMAND_HPP) 2 | #define CHANGEGDLPARAMETERSOFELEMENTSCOMMAND_HPP 3 | 4 | #pragma once 5 | 6 | #include "AdditionalJSONCommand.hpp" 7 | 8 | 9 | class ChangeGDLParametersOfElementsCommand : public AdditionalJSONCommand { 10 | public: 11 | virtual GS::String GetName () const override; 12 | virtual GS::Optional GetSchemaDefinitions () const override; 13 | virtual GS::Optional GetInputParametersSchema () const override; 14 | virtual GS::ObjectState Execute (const GS::ObjectState& parameters, GS::ProcessControl& processControl) const override; 15 | }; 16 | 17 | 18 | #endif -------------------------------------------------------------------------------- /Src/CreateColumnsCommand.cpp: -------------------------------------------------------------------------------- 1 | #include "CreateColumnsCommand.hpp" 2 | #include "ObjectState.hpp" 3 | #include "OnExit.hpp" 4 | 5 | 6 | GS::String CreateColumnsCommand::GetName () const 7 | { 8 | return "CreateColumns"; 9 | } 10 | 11 | 12 | constexpr const char* CoordinatesParameterField = "coordinates"; 13 | 14 | 15 | GS::Optional CreateColumnsCommand::GetInputParametersSchema () const 16 | { 17 | return GS::UniString::Printf (R"({ 18 | "type": "object", 19 | "properties": { 20 | "%s": { 21 | "type": "array", 22 | "description": "The 3D coordinates of the new columns' origos.", 23 | "items": { 24 | "type": "object", 25 | "description" : "3D coordinate.", 26 | "properties" : { 27 | "x": { 28 | "type": "number", 29 | "description" : "X value of the coordinate." 30 | }, 31 | "y" : { 32 | "type": "number", 33 | "description" : "Y value of the coordinate." 34 | }, 35 | "z" : { 36 | "type": "number", 37 | "description" : "Z value of the coordinate." 38 | } 39 | }, 40 | "additionalProperties": false, 41 | "required" : [ 42 | "x", 43 | "y", 44 | "z" 45 | ] 46 | } 47 | } 48 | }, 49 | "additionalProperties": false, 50 | "required": [ 51 | "%s" 52 | ] 53 | })", 54 | CoordinatesParameterField, 55 | CoordinatesParameterField); 56 | } 57 | 58 | 59 | GS::ObjectState CreateColumnsCommand::Execute (const GS::ObjectState& parameters, GS::ProcessControl& /*processControl*/) const 60 | { 61 | GS::Array coordinates; 62 | parameters.Get (CoordinatesParameterField, coordinates); 63 | 64 | API_Coord3D apiCoordinate = {}; 65 | const APIErrCodes err = (APIErrCodes) ACAPI_CallUndoableCommand ("Create Columns", [&] () -> GSErrCode { 66 | API_Element element = {}; 67 | API_ElementMemo memo = {}; 68 | const GS::OnExit guard ([&memo] () { ACAPI_DisposeElemMemoHdls (&memo); }); 69 | 70 | #ifdef ServerMainVers_2600 71 | element.header.type = API_ColumnID; 72 | #else 73 | element.header.typeID = API_ColumnID; 74 | #endif 75 | APIErrCodes err = (APIErrCodes) ACAPI_Element_GetDefaults (&element, &memo); 76 | 77 | const GS::Array> storyLevels = Utilities::GetStoryLevels (); 78 | 79 | for (const GS::ObjectState& coordinate : coordinates) { 80 | apiCoordinate = Utilities::Get3DCoordinateFromObjectState (coordinate); 81 | 82 | element.header.floorInd = Utilities::GetFloorIndexAndOffset (apiCoordinate.z, storyLevels, element.column.bottomOffset); 83 | element.column.origoPos.x = apiCoordinate.x; 84 | element.column.origoPos.y = apiCoordinate.y; 85 | err = (APIErrCodes) ACAPI_Element_Create (&element, &memo); 86 | 87 | if (err != NoError) { 88 | return err; 89 | } 90 | } 91 | 92 | return NoError; 93 | }); 94 | 95 | if (err != NoError) { 96 | const GS::UniString errorMsg = GS::UniString::Printf ("Failed to create column to coordinate: {%.2f, %.2f, %.2f}!", apiCoordinate.x, apiCoordinate.y, apiCoordinate.z); 97 | return CreateErrorResponse (err, errorMsg); 98 | } 99 | 100 | return {}; 101 | } -------------------------------------------------------------------------------- /Src/CreateColumnsCommand.hpp: -------------------------------------------------------------------------------- 1 | #if !defined (CREATECOLUMNCOMMAND_HPP) 2 | #define CREATECOLUMNCOMMAND_HPP 3 | 4 | #pragma once 5 | 6 | #include "AdditionalJSONCommand.hpp" 7 | 8 | 9 | class CreateColumnsCommand : public AdditionalJSONCommand { 10 | public: 11 | virtual GS::String GetName () const override; 12 | virtual GS::Optional GetInputParametersSchema () const override; 13 | virtual GS::ObjectState Execute (const GS::ObjectState& parameters, GS::ProcessControl& processControl) const override; 14 | }; 15 | 16 | 17 | #endif -------------------------------------------------------------------------------- /Src/CreateObjectsCommand.cpp: -------------------------------------------------------------------------------- 1 | #include "CreateObjectsCommand.hpp" 2 | #include "ObjectState.hpp" 3 | #include "OnExit.hpp" 4 | 5 | 6 | GS::String CreateObjectsCommand::GetName () const 7 | { 8 | return "CreateObjects"; 9 | } 10 | 11 | 12 | constexpr const char* ObjectsParameterField = "objects"; 13 | constexpr const char* ObjectNameParameterField = "name"; 14 | constexpr const char* ObjectCoordinateParameterField = "coordinate"; 15 | constexpr const char* ObjectDimensionsParameterField = "dimensions"; 16 | 17 | 18 | GS::Optional CreateObjectsCommand::GetInputParametersSchema () const 19 | { 20 | return GS::UniString::Printf (R"({ 21 | "type": "object", 22 | "properties": { 23 | "%s": { 24 | "type": "array", 25 | "description": "The parameters of the new Objects.", 26 | "items": { 27 | "type": "object", 28 | "description" : "The parameters of the new Object.", 29 | "properties" : { 30 | "%s": { 31 | "type": "string", 32 | "description" : "The name of the object." 33 | }, 34 | "%s": { 35 | "type": "object", 36 | "description" : "3D coordinate.", 37 | "properties" : { 38 | "x": { 39 | "type": "number", 40 | "description" : "X value of the coordinate." 41 | }, 42 | "y" : { 43 | "type": "number", 44 | "description" : "Y value of the coordinate." 45 | }, 46 | "z" : { 47 | "type": "number", 48 | "description" : "Z value of the coordinate." 49 | } 50 | }, 51 | "additionalProperties": false, 52 | "required" : [ 53 | "x", 54 | "y", 55 | "z" 56 | ] 57 | }, 58 | "%s": { 59 | "type": "object", 60 | "description" : "3D size.", 61 | "properties" : { 62 | "x": { 63 | "type": "number", 64 | "description" : "X dimension." 65 | }, 66 | "y" : { 67 | "type": "number", 68 | "description" : "Y dimension." 69 | }, 70 | "z" : { 71 | "type": "number", 72 | "description" : "Z dimension." 73 | } 74 | }, 75 | "additionalProperties": false, 76 | "required" : [ 77 | "x", 78 | "y", 79 | "z" 80 | ] 81 | } 82 | }, 83 | "additionalProperties": true, 84 | "required" : [ 85 | "%s", 86 | "%s", 87 | "%s" 88 | ] 89 | } 90 | } 91 | }, 92 | "additionalProperties": false, 93 | "required": [ 94 | "%s" 95 | ] 96 | })", 97 | ObjectsParameterField, 98 | ObjectNameParameterField, 99 | ObjectCoordinateParameterField, 100 | ObjectDimensionsParameterField, 101 | ObjectNameParameterField, 102 | ObjectCoordinateParameterField, 103 | ObjectDimensionsParameterField, 104 | ObjectsParameterField); 105 | } 106 | 107 | 108 | GS::ObjectState CreateObjectsCommand::Execute (const GS::ObjectState& parameters, GS::ProcessControl& /*processControl*/) const 109 | { 110 | GS::Array objects; 111 | parameters.Get (ObjectsParameterField, objects); 112 | 113 | GS::UniString name; 114 | API_Coord3D apiCoordinate; 115 | const APIErrCodes err = (APIErrCodes) ACAPI_CallUndoableCommand ("Create Objects", [&] () -> GSErrCode { 116 | API_Element element = {}; 117 | API_ElementMemo memo = {}; 118 | const GS::OnExit guard ([&memo] () { ACAPI_DisposeElemMemoHdls (&memo); }); 119 | 120 | #ifdef ServerMainVers_2600 121 | element.header.type = API_ObjectID; 122 | #else 123 | element.header.typeID = API_ObjectID; 124 | #endif 125 | APIErrCodes err = (APIErrCodes) ACAPI_Element_GetDefaults (&element, &memo); 126 | 127 | const GS::Array> storyLevels = Utilities::GetStoryLevels (); 128 | 129 | for (const GS::ObjectState& object : objects) { 130 | if (!object.Contains (ObjectNameParameterField) || 131 | !object.Contains (ObjectCoordinateParameterField)) { 132 | continue; 133 | } 134 | 135 | API_LibPart libPart = {}; 136 | GS::UniString uName; 137 | object.Get (ObjectNameParameterField, uName); 138 | GS::ucscpy (libPart.docu_UName, uName.ToUStr ()); 139 | 140 | err = (APIErrCodes) ACAPI_LibPart_Search (&libPart, false); 141 | delete libPart.location; 142 | 143 | if (err != NoError) { 144 | return err; 145 | } 146 | 147 | element.object.libInd = libPart.index; 148 | 149 | GS::ObjectState coordinate; 150 | object.Get (ObjectCoordinateParameterField, coordinate); 151 | apiCoordinate = Utilities::Get3DCoordinateFromObjectState (coordinate); 152 | 153 | object.Get (ObjectDimensionsParameterField, coordinate); 154 | API_Coord3D dimensions = Utilities::Get3DCoordinateFromObjectState (coordinate); 155 | 156 | element.object.pos.x = apiCoordinate.x; 157 | element.object.pos.y = apiCoordinate.y; 158 | element.header.floorInd = Utilities::GetFloorIndexAndOffset (apiCoordinate.z, storyLevels, element.object.level); 159 | 160 | element.object.xRatio = dimensions.x; 161 | element.object.yRatio = dimensions.y; 162 | GS::ObjectState os; 163 | os.Add("value", dimensions.z); 164 | Utilities::ChangeParams(memo.params, {{"ZZYZX", os}}); 165 | 166 | err = (APIErrCodes) ACAPI_Element_Create (&element, &memo); 167 | 168 | if (err != NoError) { 169 | return err; 170 | } 171 | } 172 | 173 | return NoError; 174 | }); 175 | 176 | if (err != NoError) { 177 | const GS::UniString errorMsg = GS::UniString::Printf ("Failed to create object with name {%T} to coordinate: {%.2f, %.2f, %.2f}!", name.ToPrintf(), apiCoordinate.x, apiCoordinate.y, apiCoordinate.z); 178 | return CreateErrorResponse (err, errorMsg); 179 | } 180 | 181 | return {}; 182 | } -------------------------------------------------------------------------------- /Src/CreateObjectsCommand.hpp: -------------------------------------------------------------------------------- 1 | #if !defined (CREATEOBJECTCOMMAND_HPP) 2 | #define CREATEOBJECTCOMMAND_HPP 3 | 4 | #pragma once 5 | 6 | #include "AdditionalJSONCommand.hpp" 7 | 8 | 9 | class CreateObjectsCommand : public AdditionalJSONCommand { 10 | public: 11 | virtual GS::String GetName () const override; 12 | virtual GS::Optional GetInputParametersSchema () const override; 13 | virtual GS::ObjectState Execute (const GS::ObjectState& parameters, GS::ProcessControl& processControl) const override; 14 | }; 15 | 16 | 17 | #endif -------------------------------------------------------------------------------- /Src/CreateRailingsCommand.cpp: -------------------------------------------------------------------------------- 1 | #include "CreateRailingsCommand.hpp" 2 | #include "ObjectState.hpp" 3 | #include "OnExit.hpp" 4 | 5 | 6 | GS::String CreateRailingsCommand::GetName () const 7 | { 8 | return "CreateRailings"; 9 | } 10 | 11 | 12 | constexpr const char* RailingsParameterField = "railings"; 13 | constexpr const char* LevelParameterField = "level"; 14 | constexpr const char* PolygonCoordinatesParameterField = "polygonCoordinates"; 15 | constexpr const char* HolesParameterField = "holes"; 16 | 17 | 18 | GS::Optional CreateRailingsCommand::GetInputParametersSchema () const 19 | { 20 | return GS::UniString::Printf (R"({ 21 | "type": "object", 22 | "properties": { 23 | "%s": { 24 | "type": "array", 25 | "description": "The parameters of the new Railings.", 26 | "items": { 27 | "type": "object", 28 | "description" : "The parameters of the new Railing.", 29 | "properties" : { 30 | "%s": { 31 | "type": "number", 32 | "description" : "The Z coordinate value of the reference line of the railing." 33 | }, 34 | "%s": { 35 | "type": "array", 36 | "description": "The 2D coordinates of the edge of the railing.", 37 | "items": { 38 | "type": "object", 39 | "description" : "Position of a 2D point.", 40 | "properties" : { 41 | "x": { 42 | "type": "number", 43 | "description" : "X value of the point." 44 | }, 45 | "y" : { 46 | "type": "number", 47 | "description" : "Y value of the point." 48 | } 49 | }, 50 | "additionalProperties": false, 51 | "required" : [ 52 | "x", 53 | "y" 54 | ] 55 | } 56 | } 57 | }, 58 | "additionalProperties": true, 59 | "required" : [ 60 | "%s", 61 | "%s" 62 | ] 63 | } 64 | } 65 | }, 66 | "additionalProperties": false, 67 | "required": [ 68 | "%s" 69 | ] 70 | })", 71 | RailingsParameterField, 72 | LevelParameterField, 73 | PolygonCoordinatesParameterField, 74 | LevelParameterField, 75 | PolygonCoordinatesParameterField, 76 | RailingsParameterField); 77 | } 78 | 79 | 80 | static void AddPolyToMemo (const GS::Array& polygonCoordinates, 81 | const API_OverriddenAttribute& sideMat, 82 | Int32& iCoord, 83 | Int32& iPends, 84 | API_ElementMemo& memo) 85 | { 86 | Int32 iStart = iCoord; 87 | for (const GS::ObjectState& polygonCoordinate : polygonCoordinates) { 88 | (*memo.coords)[iCoord] = Utilities::Get2DCoordinateFromObjectState (polygonCoordinate); 89 | (*memo.edgeTrims)[iCoord].sideType = APIEdgeTrim_Vertical; // Only vertical trim is supported yet by my code 90 | memo.sideMaterials[iCoord] = sideMat; 91 | ++iCoord; 92 | } 93 | (*memo.coords)[iCoord] = (*memo.coords)[iStart]; 94 | (*memo.pends)[iPends++] = iCoord; 95 | (*memo.edgeTrims)[iCoord].sideType = (*memo.edgeTrims)[iStart].sideType; 96 | (*memo.edgeTrims)[iCoord].sideAngle = (*memo.edgeTrims)[iStart].sideAngle; 97 | memo.sideMaterials[iCoord] = memo.sideMaterials[iStart]; 98 | ++iCoord; 99 | } 100 | 101 | 102 | GS::ObjectState CreateRailingsCommand::Execute (const GS::ObjectState& parameters, GS::ProcessControl& /*processControl*/) const 103 | { 104 | GS::Array railings; 105 | parameters.Get (RailingsParameterField, railings); 106 | 107 | GSIndex iRailing = 0; 108 | const APIErrCodes err = (APIErrCodes) ACAPI_CallUndoableCommand ("Create Railings", [&] () -> GSErrCode { 109 | APIErrCodes err = (APIErrCodes) NoError; 110 | const GS::Array> storyLevels = Utilities::GetStoryLevels (); 111 | for (const GS::ObjectState& railing : railings) { 112 | if (!railing.Contains (LevelParameterField) || 113 | !railing.Contains (PolygonCoordinatesParameterField)) { 114 | continue; 115 | } 116 | 117 | API_Element element = {}; 118 | API_ElementMemo memo = {}; 119 | const GS::OnExit guard ([&memo] () { ACAPI_DisposeElemMemoHdls (&memo); }); 120 | 121 | #ifdef ServerMainVers_2600 122 | element.header.type = API_RailingID; 123 | #else 124 | element.header.typeID = API_RailingID; 125 | #endif 126 | err = (APIErrCodes) ACAPI_Element_GetDefaults (&element, &memo); 127 | 128 | railing.Get(LevelParameterField, element.railing.bottomOffset); 129 | element.header.floorInd = Utilities::GetFloorIndexAndOffset (element.railing.bottomOffset, storyLevels, element.railing.bottomOffset); 130 | 131 | GS::Array polygonCoordinates; 132 | GS::Array holes; 133 | railing.Get (PolygonCoordinatesParameterField, polygonCoordinates); 134 | if (railing.Contains (HolesParameterField)) { 135 | railing.Get (HolesParameterField, holes); 136 | } 137 | API_Polygon poly = {}; 138 | poly.nCoords = polygonCoordinates.GetSize() + 1; 139 | poly.nSubPolys = 1; 140 | 141 | memo.coords = reinterpret_cast (BMAllocateHandle ((poly.nCoords + 1) * sizeof (API_Coord), ALLOCATE_CLEAR, 0)); 142 | memo.edgeTrims = reinterpret_cast (BMAllocateHandle ((poly.nCoords + 1) * sizeof (API_EdgeTrim), ALLOCATE_CLEAR, 0)); 143 | memo.sideMaterials = reinterpret_cast (BMAllocatePtr ((poly.nCoords + 1) * sizeof (API_OverriddenAttribute), ALLOCATE_CLEAR, 0)); 144 | memo.pends = reinterpret_cast (BMAllocateHandle ((poly.nSubPolys + 1) * sizeof (Int32), ALLOCATE_CLEAR, 0)); 145 | 146 | element.railing.nVertices = poly.nCoords; 147 | 148 | Int32 iCoord = 1; 149 | Int32 iPends = 1; 150 | AddPolyToMemo(polygonCoordinates, 151 | API_OverriddenAttribute(), 152 | iCoord, 153 | iPends, 154 | memo); 155 | 156 | err = (APIErrCodes) ACAPI_Element_Create (&element, &memo); 157 | 158 | if (err != NoError) { 159 | break; 160 | } 161 | 162 | ++iRailing; 163 | } 164 | 165 | return err; 166 | }); 167 | 168 | if (err != NoError) { 169 | const GS::UniString errorMsg = GS::UniString::Printf ("Failed to create railing #%d!", iRailing); 170 | return CreateErrorResponse (err, errorMsg); 171 | } 172 | 173 | return {}; 174 | } -------------------------------------------------------------------------------- /Src/CreateRailingsCommand.hpp: -------------------------------------------------------------------------------- 1 | #if !defined (CREATERAILINGCOMMAND_HPP) 2 | #define CREATERAILINGCOMMAND_HPP 3 | 4 | #pragma once 5 | 6 | #include "AdditionalJSONCommand.hpp" 7 | 8 | 9 | class CreateRailingsCommand : public AdditionalJSONCommand { 10 | public: 11 | virtual GS::String GetName () const override; 12 | virtual GS::Optional GetInputParametersSchema () const override; 13 | virtual GS::ObjectState Execute (const GS::ObjectState& parameters, GS::ProcessControl& processControl) const override; 14 | }; 15 | 16 | 17 | #endif -------------------------------------------------------------------------------- /Src/CreateSlabsCommand.cpp: -------------------------------------------------------------------------------- 1 | #include "CreateSlabsCommand.hpp" 2 | #include "ObjectState.hpp" 3 | #include "OnExit.hpp" 4 | 5 | 6 | GS::String CreateSlabsCommand::GetName () const 7 | { 8 | return "CreateSlabs"; 9 | } 10 | 11 | 12 | constexpr const char* SlabsParameterField = "slabs"; 13 | constexpr const char* LevelParameterField = "level"; 14 | constexpr const char* PolygonCoordinatesParameterField = "polygonCoordinates"; 15 | constexpr const char* HolesParameterField = "holes"; 16 | 17 | 18 | GS::Optional CreateSlabsCommand::GetInputParametersSchema () const 19 | { 20 | return GS::UniString::Printf (R"({ 21 | "type": "object", 22 | "properties": { 23 | "%s": { 24 | "type": "array", 25 | "description": "The parameters of the new Slabs.", 26 | "items": { 27 | "type": "object", 28 | "description" : "The parameters of the new Slab.", 29 | "properties" : { 30 | "%s": { 31 | "type": "number", 32 | "description" : "The Z coordinate value of the reference line of the slab." 33 | }, 34 | "%s": { 35 | "type": "array", 36 | "description": "The 2D coordinates of the edge of the slab.", 37 | "items": { 38 | "type": "object", 39 | "description" : "Position of a 2D point.", 40 | "properties" : { 41 | "x": { 42 | "type": "number", 43 | "description" : "X value of the point." 44 | }, 45 | "y" : { 46 | "type": "number", 47 | "description" : "Y value of the point." 48 | } 49 | }, 50 | "additionalProperties": false, 51 | "required" : [ 52 | "x", 53 | "y" 54 | ] 55 | } 56 | } 57 | }, 58 | "additionalProperties": true, 59 | "required" : [ 60 | "%s", 61 | "%s" 62 | ] 63 | } 64 | } 65 | }, 66 | "additionalProperties": false, 67 | "required": [ 68 | "%s" 69 | ] 70 | })", 71 | SlabsParameterField, 72 | LevelParameterField, 73 | PolygonCoordinatesParameterField, 74 | LevelParameterField, 75 | PolygonCoordinatesParameterField, 76 | SlabsParameterField); 77 | } 78 | 79 | 80 | static void AddPolyToMemo (const GS::Array& polygonCoordinates, 81 | const API_OverriddenAttribute& sideMat, 82 | Int32& iCoord, 83 | Int32& iPends, 84 | API_ElementMemo& memo) 85 | { 86 | Int32 iStart = iCoord; 87 | for (const GS::ObjectState& polygonCoordinate : polygonCoordinates) { 88 | (*memo.coords)[iCoord] = Utilities::Get2DCoordinateFromObjectState (polygonCoordinate); 89 | (*memo.edgeTrims)[iCoord].sideType = APIEdgeTrim_Vertical; // Only vertical trim is supported yet by my code 90 | memo.sideMaterials[iCoord] = sideMat; 91 | ++iCoord; 92 | } 93 | (*memo.coords)[iCoord] = (*memo.coords)[iStart]; 94 | (*memo.pends)[iPends++] = iCoord; 95 | (*memo.edgeTrims)[iCoord].sideType = (*memo.edgeTrims)[iStart].sideType; 96 | (*memo.edgeTrims)[iCoord].sideAngle = (*memo.edgeTrims)[iStart].sideAngle; 97 | memo.sideMaterials[iCoord] = memo.sideMaterials[iStart]; 98 | ++iCoord; 99 | } 100 | 101 | 102 | GS::ObjectState CreateSlabsCommand::Execute (const GS::ObjectState& parameters, GS::ProcessControl& /*processControl*/) const 103 | { 104 | GS::Array slabs; 105 | parameters.Get (SlabsParameterField, slabs); 106 | 107 | GSIndex iSlab = 0; 108 | const APIErrCodes err = (APIErrCodes) ACAPI_CallUndoableCommand ("Create Slabs", [&] () -> GSErrCode { 109 | APIErrCodes err = (APIErrCodes) NoError; 110 | const GS::Array> storyLevels = Utilities::GetStoryLevels (); 111 | for (const GS::ObjectState& slab : slabs) { 112 | if (!slab.Contains (LevelParameterField) || 113 | !slab.Contains (PolygonCoordinatesParameterField)) { 114 | continue; 115 | } 116 | 117 | API_Element element = {}; 118 | API_ElementMemo memo = {}; 119 | const GS::OnExit guard ([&memo] () { ACAPI_DisposeElemMemoHdls (&memo); }); 120 | 121 | #ifdef ServerMainVers_2600 122 | element.header.type = API_SlabID; 123 | #else 124 | element.header.typeID = API_SlabID; 125 | #endif 126 | err = (APIErrCodes) ACAPI_Element_GetDefaults (&element, &memo); 127 | 128 | slab.Get(LevelParameterField, element.slab.level); 129 | element.header.floorInd = Utilities::GetFloorIndexAndOffset (element.slab.level, storyLevels, element.slab.level); 130 | 131 | GS::Array polygonCoordinates; 132 | GS::Array holes; 133 | slab.Get (PolygonCoordinatesParameterField, polygonCoordinates); 134 | if (slab.Contains (HolesParameterField)) { 135 | slab.Get (HolesParameterField, holes); 136 | } 137 | element.slab.poly.nCoords = polygonCoordinates.GetSize() + 1; 138 | element.slab.poly.nSubPolys = 1; 139 | element.slab.poly.nArcs = 0; // Curved edges are not supported yet by my code 140 | 141 | for (const GS::ObjectState& hole : holes) { 142 | if (!hole.Contains (PolygonCoordinatesParameterField)) { 143 | continue; 144 | } 145 | GS::Array holePolygonCoordinates; 146 | hole.Get (PolygonCoordinatesParameterField, holePolygonCoordinates); 147 | element.slab.poly.nCoords += holePolygonCoordinates.GetSize() + 1; 148 | ++element.slab.poly.nSubPolys; 149 | } 150 | 151 | memo.coords = reinterpret_cast (BMAllocateHandle ((element.slab.poly.nCoords + 1) * sizeof (API_Coord), ALLOCATE_CLEAR, 0)); 152 | memo.edgeTrims = reinterpret_cast (BMAllocateHandle ((element.slab.poly.nCoords + 1) * sizeof (API_EdgeTrim), ALLOCATE_CLEAR, 0)); 153 | memo.sideMaterials = reinterpret_cast (BMAllocatePtr ((element.slab.poly.nCoords + 1) * sizeof (API_OverriddenAttribute), ALLOCATE_CLEAR, 0)); 154 | memo.pends = reinterpret_cast (BMAllocateHandle ((element.slab.poly.nSubPolys + 1) * sizeof (Int32), ALLOCATE_CLEAR, 0)); 155 | 156 | Int32 iCoord = 1; 157 | Int32 iPends = 1; 158 | AddPolyToMemo(polygonCoordinates, 159 | element.slab.sideMat, 160 | iCoord, 161 | iPends, 162 | memo); 163 | 164 | for (const GS::ObjectState& hole : holes) { 165 | if (!hole.Contains (PolygonCoordinatesParameterField)) { 166 | continue; 167 | } 168 | GS::Array holePolygonCoordinates; 169 | hole.Get (PolygonCoordinatesParameterField, holePolygonCoordinates); 170 | 171 | AddPolyToMemo(holePolygonCoordinates, 172 | element.slab.sideMat, 173 | iCoord, 174 | iPends, 175 | memo); 176 | } 177 | 178 | err = (APIErrCodes) ACAPI_Element_Create (&element, &memo); 179 | 180 | if (err != NoError) { 181 | break; 182 | } 183 | 184 | ++iSlab; 185 | } 186 | 187 | return err; 188 | }); 189 | 190 | if (err != NoError) { 191 | const GS::UniString errorMsg = GS::UniString::Printf ("Failed to create slab #%d!", iSlab); 192 | return CreateErrorResponse (err, errorMsg); 193 | } 194 | 195 | return {}; 196 | } -------------------------------------------------------------------------------- /Src/CreateSlabsCommand.hpp: -------------------------------------------------------------------------------- 1 | #if !defined (CREATESLABCOMMAND_HPP) 2 | #define CREATESLABCOMMAND_HPP 3 | 4 | #pragma once 5 | 6 | #include "AdditionalJSONCommand.hpp" 7 | 8 | 9 | class CreateSlabsCommand : public AdditionalJSONCommand { 10 | public: 11 | virtual GS::String GetName () const override; 12 | virtual GS::Optional GetInputParametersSchema () const override; 13 | virtual GS::ObjectState Execute (const GS::ObjectState& parameters, GS::ProcessControl& processControl) const override; 14 | }; 15 | 16 | 17 | #endif -------------------------------------------------------------------------------- /Src/GetArchicadLocationCommand.cpp: -------------------------------------------------------------------------------- 1 | #include "GetArchicadLocationCommand.hpp" 2 | #include "ObjectState.hpp" 3 | #include "FileSystem.hpp" 4 | 5 | 6 | static GS::Optional GetApplicationLocation () 7 | { 8 | IO::Location applicationFileLocation; 9 | 10 | GSErrCode error = IO::fileSystem.GetSpecialLocation (IO::FileSystem::ApplicationFile, &applicationFileLocation); 11 | if (error != NoError) { 12 | return GS::NoValue; 13 | } 14 | 15 | return applicationFileLocation; 16 | } 17 | 18 | 19 | GS::String GetArchicadLocationCommand::GetName () const 20 | { 21 | return "GetArchicadLocation"; 22 | } 23 | 24 | 25 | constexpr const char* ArchicadLocationResponseField = "archicadLocation"; 26 | 27 | 28 | GS::Optional GetArchicadLocationCommand::GetResponseSchema () const 29 | { 30 | return GS::UniString::Printf (R"({ 31 | "type": "object", 32 | "properties": { 33 | "%s": { 34 | "type": "string", 35 | "description": "The location of the Archicad executable in the filesystem.", 36 | "minLength": 1 37 | } 38 | }, 39 | "additionalProperties": false, 40 | "required": [ 41 | "%s" 42 | ] 43 | })", 44 | ArchicadLocationResponseField, 45 | ArchicadLocationResponseField); 46 | } 47 | 48 | 49 | GS::ObjectState GetArchicadLocationCommand::Execute (const GS::ObjectState& /*parameters*/, GS::ProcessControl& /*processControl*/) const 50 | { 51 | const GS::Optional applicationFileLocation = GetApplicationLocation (); 52 | 53 | if (!applicationFileLocation.HasValue ()) { 54 | return CreateErrorResponse (APIERR_GENERAL, "Failed to get the location of the Archicad application!"); 55 | } 56 | 57 | return GS::ObjectState (ArchicadLocationResponseField, applicationFileLocation.Get ().ToDisplayText ()); 58 | } -------------------------------------------------------------------------------- /Src/GetArchicadLocationCommand.hpp: -------------------------------------------------------------------------------- 1 | #if !defined (GETARCHICADLOCATIONCOMMAND_HPP) 2 | #define GETARCHICADLOCATIONCOMMAND_HPP 3 | 4 | #pragma once 5 | 6 | #include "AdditionalJSONCommand.hpp" 7 | 8 | 9 | class GetArchicadLocationCommand : public AdditionalJSONCommand { 10 | public: 11 | virtual GS::String GetName () const override; 12 | virtual GS::Optional GetResponseSchema () const override; 13 | virtual GS::ObjectState Execute (const GS::ObjectState& parameters, GS::ProcessControl& processControl) const override; 14 | }; 15 | 16 | 17 | #endif -------------------------------------------------------------------------------- /Src/GetGDLParametersOfElementsCommand.cpp: -------------------------------------------------------------------------------- 1 | #include "GetGDLParametersOfElementsCommand.hpp" 2 | #include "ObjectState.hpp" 3 | 4 | 5 | GS::String GetGDLParametersOfElementsCommand::GetName () const 6 | { 7 | return "GetGDLParametersOfElements"; 8 | } 9 | 10 | 11 | constexpr const char* GDLParametersDictionarySchemaName = "GDLParametersDictionary"; 12 | constexpr const char* GDLParameterDetailsSchemaName = "GDLParameterDetails"; 13 | constexpr const char* ParameterIndexFieldName = "index"; 14 | constexpr const char* ParameterTypeFieldName = "type"; 15 | constexpr const char* ParameterDimension1FieldName = "dimension1"; 16 | constexpr const char* ParameterDimension2FieldName = "dimension2"; 17 | constexpr const char* ParameterValueFieldName = "value"; 18 | constexpr const char* AttributeIndexFieldName = "index"; 19 | constexpr const char* AttributeNameFieldName = "name"; 20 | 21 | 22 | GS::Optional GetGDLParametersOfElementsCommand::GetSchemaDefinitions () const 23 | { 24 | return GS::UniString::Printf (R"({ 25 | "%s": { 26 | "type": "object", 27 | "description": "The dictionary of GDL parameters. The name of the parameter is the key and the details of the parameter are in the value." 28 | }, 29 | "%s": { 30 | "type": "object", 31 | "description": "Details of GDL parameter with value.", 32 | "properties": { 33 | "%s": { 34 | "type": "string", 35 | "description": "The index of the parameter." 36 | }, 37 | "%s": { 38 | "type": "string", 39 | "description": "The type of the parameter." 40 | }, 41 | "%s": { 42 | "type": "string", 43 | "description": "The 1st dimension of array (in case of array value)." 44 | }, 45 | "%s": { 46 | "type": "string", 47 | "description": "The 2nd dimension of array (in case of array value)." 48 | } 49 | }, 50 | "additionalProperties": true, 51 | "required": [ 52 | "%s", 53 | "%s" 54 | ] 55 | } 56 | })", 57 | GDLParametersDictionarySchemaName, 58 | GDLParameterDetailsSchemaName, 59 | ParameterIndexFieldName, 60 | ParameterTypeFieldName, 61 | ParameterDimension1FieldName, 62 | ParameterDimension2FieldName, 63 | ParameterIndexFieldName, 64 | ParameterTypeFieldName 65 | ); 66 | } 67 | 68 | 69 | constexpr const char* ElementsParameterField = "elements"; 70 | 71 | 72 | GS::Optional GetGDLParametersOfElementsCommand::GetInputParametersSchema () const 73 | { 74 | return GS::UniString::Printf (R"({ 75 | "type": "object", 76 | "properties": { 77 | "%s": { 78 | "$ref": "APITypes.json#/definitions/Elements" 79 | } 80 | }, 81 | "additionalProperties": false, 82 | "required": [ 83 | "%s" 84 | ] 85 | })", 86 | ElementsParameterField, 87 | ElementsParameterField 88 | ); 89 | } 90 | 91 | 92 | constexpr const char* GDLParametersOfElementsResponseFieldName = "gdlParametersOfElements"; 93 | 94 | 95 | GS::Optional GetGDLParametersOfElementsCommand::GetResponseSchema () const 96 | { 97 | return GS::UniString::Printf (R"({ 98 | "type": "object", 99 | "properties": { 100 | "%s": { 101 | "type": "array", 102 | "description": "The GDL parameters of elements.", 103 | "items": { 104 | "$ref": "#/%s" 105 | } 106 | } 107 | }, 108 | "additionalProperties": false, 109 | "required": [ 110 | "%s" 111 | ] 112 | })", 113 | GDLParametersOfElementsResponseFieldName, 114 | GDLParametersDictionarySchemaName, 115 | GDLParametersOfElementsResponseFieldName); 116 | } 117 | 118 | 119 | static GS::UniString ConvertAddParIDToString (API_AddParID addParID) 120 | { 121 | switch (addParID) { 122 | case APIParT_Integer: return "Integer"; 123 | case APIParT_Length: return "Length"; 124 | case APIParT_Angle: return "Angle"; 125 | case APIParT_RealNum: return "RealNum"; 126 | case APIParT_LightSw: return "LightSwitch"; 127 | case APIParT_ColRGB: return "ColorRGB"; 128 | case APIParT_Intens: return "Intens"; 129 | case APIParT_LineTyp: return "LineType"; 130 | case APIParT_Mater: return "Material"; 131 | case APIParT_FillPat: return "FillPattern"; 132 | case APIParT_PenCol: return "PenCol"; 133 | case APIParT_CString: return "String"; 134 | case APIParT_Boolean: return "Boolean"; 135 | case APIParT_Separator: return "Separator"; 136 | case APIParT_Title: return "Title"; 137 | case APIParT_BuildingMaterial: return "BuildingMaterial"; 138 | case APIParT_Profile: return "Profile"; 139 | case APIParT_Dictionary: return "Dictionary"; 140 | default: return "UNKNOWN"; 141 | } 142 | } 143 | 144 | 145 | static API_AttrTypeID ConvertAddParIDToAttrTypeID (API_AddParID addParID) 146 | { 147 | switch (addParID) { 148 | case APIParT_FillPat: return API_FilltypeID; 149 | case APIParT_Mater: return API_MaterialID; 150 | case APIParT_BuildingMaterial: return API_BuildingMaterialID; 151 | case APIParT_Profile: return API_ProfileID; 152 | case APIParT_LineTyp: return API_LinetypeID; 153 | default: return API_ZombieAttrID; 154 | } 155 | } 156 | 157 | 158 | static GS::UniString GetAttributeName (API_AttrTypeID typeID, 159 | API_AttributeIndex index) 160 | { 161 | API_Attribute attrib = {}; 162 | 163 | GS::UniString name; 164 | attrib.header.typeID = typeID; 165 | attrib.header.index = index; 166 | attrib.header.uniStringNamePtr = &name; 167 | 168 | ACAPI_Attribute_Get (&attrib); 169 | 170 | if (typeID == API_MaterialID && attrib.material.texture.fileLoc != nullptr) { 171 | delete attrib.material.texture.fileLoc; 172 | attrib.material.texture.fileLoc = nullptr; 173 | } 174 | 175 | return name; 176 | } 177 | 178 | 179 | static GS::ObjectState GetAttributeObjectState (API_AttrTypeID typeID, 180 | API_AttributeIndex index) 181 | { 182 | GS::ObjectState attribute; 183 | attribute.Add (AttributeIndexFieldName, index); 184 | attribute.Add (AttributeNameFieldName, GetAttributeName (typeID, index)); 185 | return attribute; 186 | } 187 | 188 | 189 | static void AddValueInteger (GS::ObjectState& gdlParameterDetails, 190 | const API_AddParType& actParam) 191 | { 192 | if (actParam.typeMod == API_ParSimple) { 193 | gdlParameterDetails.Add (ParameterValueFieldName, static_cast (actParam.value.real)); 194 | } else { 195 | const auto& arrayValueItemAdder = gdlParameterDetails.AddList (ParameterValueFieldName); 196 | Int32 arrayIndex = 0; 197 | for (Int32 i1 = 1; i1 <= actParam.dim1; i1++) { 198 | for (Int32 i2 = 1; i2 <= actParam.dim2; i2++) { 199 | arrayValueItemAdder (static_cast (((double*)*actParam.value.array) [arrayIndex++])); 200 | } 201 | } 202 | } 203 | } 204 | 205 | 206 | static void AddValueDouble (GS::ObjectState& gdlParameterDetails, 207 | const API_AddParType& actParam) 208 | { 209 | if (actParam.typeMod == API_ParSimple) { 210 | gdlParameterDetails.Add (ParameterValueFieldName, actParam.value.real); 211 | } else { 212 | const auto& arrayValueItemAdder = gdlParameterDetails.AddList (ParameterValueFieldName); 213 | Int32 arrayIndex = 0; 214 | for (Int32 i1 = 1; i1 <= actParam.dim1; i1++) { 215 | for (Int32 i2 = 1; i2 <= actParam.dim2; i2++) { 216 | arrayValueItemAdder (((double*)*actParam.value.array) [arrayIndex++]); 217 | } 218 | } 219 | } 220 | } 221 | 222 | 223 | static void AddValueAttribute (GS::ObjectState& gdlParameterDetails, 224 | const API_AddParType& actParam) 225 | { 226 | if (actParam.typeMod == API_ParSimple) { 227 | gdlParameterDetails.Add (ParameterValueFieldName, 228 | GetAttributeObjectState (ConvertAddParIDToAttrTypeID (actParam.typeID), 229 | static_cast (actParam.value.real))); 230 | } else { 231 | const auto& arrayValueItemAdder = gdlParameterDetails.AddList (ParameterValueFieldName); 232 | Int32 arrayIndex = 0; 233 | for (Int32 i1 = 1; i1 <= actParam.dim1; i1++) { 234 | for (Int32 i2 = 1; i2 <= actParam.dim2; i2++) { 235 | arrayValueItemAdder (GetAttributeObjectState (ConvertAddParIDToAttrTypeID (actParam.typeID), 236 | static_cast (((double*)*actParam.value.array) [arrayIndex++]))); 237 | } 238 | } 239 | } 240 | } 241 | 242 | template 243 | static void AddValueTrueFalseOptions (GS::ObjectState& gdlParameterDetails, 244 | const API_AddParType& actParam, 245 | T optionTrue, 246 | T optionFalse) 247 | { 248 | if (actParam.typeMod == API_ParSimple) { 249 | gdlParameterDetails.Add (ParameterValueFieldName, static_cast (actParam.value.real) == 0 ? optionFalse : optionTrue); 250 | } else { 251 | const auto& arrayValueItemAdder = gdlParameterDetails.AddList (ParameterValueFieldName); 252 | Int32 arrayIndex = 0; 253 | for (Int32 i1 = 1; i1 <= actParam.dim1; i1++) { 254 | for (Int32 i2 = 1; i2 <= actParam.dim2; i2++) { 255 | arrayValueItemAdder (static_cast (((double*)*actParam.value.array) [arrayIndex++]) == 0 ? optionFalse : optionTrue); 256 | } 257 | } 258 | } 259 | } 260 | 261 | 262 | static void AddValueOnOff (GS::ObjectState& gdlParameterDetails, 263 | const API_AddParType& actParam) 264 | { 265 | AddValueTrueFalseOptions (gdlParameterDetails, actParam, GS::String ("On"), GS::String ("Off")); 266 | } 267 | 268 | 269 | static void AddValueBool (GS::ObjectState& gdlParameterDetails, 270 | const API_AddParType& actParam) 271 | { 272 | AddValueTrueFalseOptions (gdlParameterDetails, actParam, true, false); 273 | } 274 | 275 | 276 | static void AddValueString (GS::ObjectState& gdlParameterDetails, 277 | const API_AddParType& actParam) 278 | { 279 | if (actParam.typeMod == API_ParSimple) { 280 | gdlParameterDetails.Add (ParameterValueFieldName, GS::UniString (actParam.value.uStr)); 281 | } else { 282 | const auto& arrayValueItemAdder = gdlParameterDetails.AddList (ParameterValueFieldName); 283 | Int32 arrayIndex = 0; 284 | for (Int32 i1 = 1; i1 <= actParam.dim1; i1++) { 285 | for (Int32 i2 = 1; i2 <= actParam.dim2; i2++) { 286 | GS::uchar_t* uValueStr = (reinterpret_cast(*actParam.value.array)) + arrayIndex; 287 | arrayIndex += GS::ucslen32 (uValueStr) + 1; 288 | arrayValueItemAdder (GS::UniString (uValueStr)); 289 | } 290 | } 291 | } 292 | } 293 | 294 | 295 | GS::ObjectState GetGDLParametersOfElementsCommand::Execute (const GS::ObjectState& parameters, GS::ProcessControl& /*processControl*/) const 296 | { 297 | GS::Array elements; 298 | parameters.Get (ElementsParameterField, elements); 299 | 300 | GS::ObjectState response; 301 | const auto& listAdder = response.AddList (GDLParametersOfElementsResponseFieldName); 302 | 303 | API_Guid elemGuid; 304 | for (const GS::ObjectState& element : elements) { 305 | const GS::ObjectState* elementId = element.Get (ElementIdField); 306 | if (elementId == nullptr) { 307 | continue; 308 | } 309 | 310 | elemGuid = GetGuidFromElementIdField (*elementId); 311 | 312 | API_ParamOwnerType paramOwner = {}; 313 | paramOwner.libInd = 0; 314 | #ifdef ServerMainVers_2600 315 | paramOwner.type = API_ObjectID; 316 | #else 317 | paramOwner.typeID = API_ObjectID; 318 | #endif 319 | paramOwner.guid = elemGuid; 320 | 321 | API_ElementMemo memo = {}; 322 | GSErrCode err = ACAPI_Element_GetMemo (elemGuid, &memo, APIMemoMask_AddPars); 323 | if (err == NoError) { 324 | const GSSize nParams = BMGetHandleSize ((GSHandle) memo.params) / sizeof (API_AddParType); 325 | GS::ObjectState gdlParametersDictionary; 326 | for (GSIndex ii = 0; ii < nParams; ++ii) { 327 | const API_AddParType& actParam = (*memo.params)[ii]; 328 | 329 | if (actParam.typeID == APIParT_Separator) { 330 | continue; 331 | } 332 | 333 | GS::ObjectState gdlParameterDetails; 334 | gdlParameterDetails.Add (ParameterIndexFieldName, actParam.index); 335 | gdlParameterDetails.Add (ParameterTypeFieldName, ConvertAddParIDToString (actParam.typeID)); 336 | if (actParam.typeMod == API_ParArray) { 337 | gdlParameterDetails.Add (ParameterDimension1FieldName, actParam.dim1); 338 | gdlParameterDetails.Add (ParameterDimension2FieldName, actParam.dim2); 339 | } 340 | 341 | switch (actParam.typeID) { 342 | case APIParT_Integer: 343 | case APIParT_PenCol: AddValueInteger (gdlParameterDetails, actParam); break; 344 | case APIParT_ColRGB: 345 | case APIParT_Intens: 346 | case APIParT_Length: 347 | case APIParT_RealNum: 348 | case APIParT_Angle: AddValueDouble (gdlParameterDetails, actParam); break; 349 | case APIParT_LightSw: AddValueOnOff (gdlParameterDetails, actParam); break; 350 | case APIParT_Boolean: AddValueBool (gdlParameterDetails, actParam); break; 351 | case APIParT_LineTyp: 352 | case APIParT_Mater: 353 | case APIParT_FillPat: 354 | case APIParT_BuildingMaterial: 355 | case APIParT_Profile: AddValueAttribute (gdlParameterDetails, actParam); break; 356 | case APIParT_CString: 357 | case APIParT_Title: AddValueString (gdlParameterDetails, actParam); break; 358 | default: 359 | case APIParT_Dictionary: 360 | // Not supported by the Archicad API yet 361 | break; 362 | } 363 | 364 | gdlParametersDictionary.Add (actParam.name, gdlParameterDetails); 365 | } 366 | listAdder (gdlParametersDictionary); 367 | ACAPI_DisposeAddParHdl (&memo.params); 368 | } else { 369 | const GS::UniString errorMsg = GS::UniString::Printf ("Failed to get parameters of element with guid %T!", APIGuidToString (elemGuid).ToPrintf ()); 370 | return CreateErrorResponse ((APIErrCodes) err, errorMsg); 371 | } 372 | } 373 | 374 | return response; 375 | } -------------------------------------------------------------------------------- /Src/GetGDLParametersOfElementsCommand.hpp: -------------------------------------------------------------------------------- 1 | #if !defined (GETGDLPARAMETERSOFELEMENTSCOMMAND_HPP) 2 | #define GETGDLPARAMETERSOFELEMENTSCOMMAND_HPP 3 | 4 | #pragma once 5 | 6 | #include "AdditionalJSONCommand.hpp" 7 | 8 | 9 | class GetGDLParametersOfElementsCommand : public AdditionalJSONCommand { 10 | public: 11 | virtual GS::String GetName () const override; 12 | virtual GS::Optional GetSchemaDefinitions () const override; 13 | virtual GS::Optional GetInputParametersSchema () const override; 14 | virtual GS::Optional GetResponseSchema () const override; 15 | virtual GS::ObjectState Execute (const GS::ObjectState& parameters, GS::ProcessControl& processControl) const override; 16 | }; 17 | 18 | 19 | #endif -------------------------------------------------------------------------------- /Src/GetHotlinksCommand.cpp: -------------------------------------------------------------------------------- 1 | #include "GetHotlinksCommand.hpp" 2 | #include "ObjectState.hpp" 3 | 4 | 5 | GS::String GetHotlinksCommand::GetName () const 6 | { 7 | return "GetHotlinks"; 8 | } 9 | 10 | 11 | constexpr const char* HotlinksSchemaName = "Hotlinks"; 12 | constexpr const char* HotlinkSchemaName = "Hotlink"; 13 | constexpr const char* LocationResponseField = "location"; 14 | constexpr const char* ChildrenResponseField = "children"; 15 | constexpr const char* HotlinksResponseField = "hotlinks"; 16 | 17 | 18 | GS::Optional GetHotlinksCommand::GetSchemaDefinitions () const 19 | { 20 | return GS::UniString::Printf (R"({ 21 | "%s": { 22 | "type": "array", 23 | "description": "A list of hotlink nodes.", 24 | "items": { 25 | "$ref": "#/%s" 26 | } 27 | }, 28 | "%s": { 29 | "type": "object", 30 | "description": "The details of a hotlink node.", 31 | "properties": { 32 | "%s": { 33 | "type": "string", 34 | "description": "The path of the hotlink file." 35 | }, 36 | "%s": { 37 | "$ref": "#/%s", 38 | "description": "The children of the hotlink node if it has any." 39 | } 40 | }, 41 | "additionalProperties": false, 42 | "required": [ 43 | "%s" 44 | ] 45 | } 46 | })", 47 | HotlinksSchemaName, 48 | HotlinkSchemaName, HotlinkSchemaName, 49 | LocationResponseField, ChildrenResponseField, 50 | HotlinksSchemaName, 51 | LocationResponseField 52 | ); 53 | } 54 | 55 | 56 | GS::Optional GetHotlinksCommand::GetResponseSchema () const 57 | { 58 | return GS::UniString::Printf (R"({ 59 | "type": "object", 60 | "properties": { 61 | "%s": { 62 | "$ref": "#/%s" 63 | } 64 | }, 65 | "additionalProperties": false, 66 | "required": [ 67 | "%s" 68 | ] 69 | })", 70 | HotlinksResponseField, 71 | HotlinkSchemaName, 72 | HotlinksResponseField); 73 | } 74 | 75 | 76 | static GS::Optional GetLocationOfHotlink (const API_Guid& hotlinkGuid) 77 | { 78 | API_HotlinkNode hotlinkNode = {}; 79 | hotlinkNode.guid = hotlinkGuid; 80 | 81 | ACAPI_Database (APIDb_GetHotlinkNodeID, &hotlinkNode); 82 | 83 | if (hotlinkNode.sourceLocation == nullptr) { 84 | return GS::NoValue; 85 | } 86 | 87 | return hotlinkNode.sourceLocation->ToDisplayText (); 88 | } 89 | 90 | 91 | static GS::ObjectState DumpHotlinkWithChildren (const API_Guid& hotlinkGuid, 92 | GS::HashTable>& hotlinkTree) 93 | { 94 | GS::ObjectState hotlinkNodeOS; 95 | 96 | const auto& location = GetLocationOfHotlink (hotlinkGuid); 97 | if (location.HasValue ()) { 98 | hotlinkNodeOS.Add (LocationResponseField, location.Get ()); 99 | } 100 | 101 | const auto& children = hotlinkTree.Retrieve (hotlinkGuid); 102 | if (!children.IsEmpty ()) { 103 | const auto& listAdder = hotlinkNodeOS.AddList (ChildrenResponseField); 104 | for (const API_Guid& childNodeGuid : hotlinkTree.Retrieve (hotlinkGuid)) { 105 | listAdder (DumpHotlinkWithChildren (childNodeGuid, hotlinkTree)); 106 | } 107 | } 108 | 109 | return hotlinkNodeOS; 110 | } 111 | 112 | 113 | GS::ObjectState GetHotlinksCommand::Execute (const GS::ObjectState& /*parameters*/, GS::ProcessControl& /*processControl*/) const 114 | { 115 | GS::ObjectState response; 116 | const auto& listAdder = response.AddList (HotlinksResponseField); 117 | 118 | for (API_HotlinkTypeID type : {APIHotlink_Module, APIHotlink_XRef}) { 119 | API_Guid hotlinkRootNodeGuid = APINULLGuid; 120 | if (ACAPI_Database (APIDb_GetHotlinkRootNodeGuidID, &type, &hotlinkRootNodeGuid) == NoError) { 121 | GS::HashTable> hotlinkTree; 122 | if (ACAPI_Database (APIDb_GetHotlinkNodeTreeID, &hotlinkRootNodeGuid, &hotlinkTree) == NoError) { 123 | for (const API_Guid& childNodeGuid : hotlinkTree.Retrieve (hotlinkRootNodeGuid)) { 124 | listAdder (DumpHotlinkWithChildren (childNodeGuid, hotlinkTree)); 125 | } 126 | } 127 | } 128 | } 129 | 130 | return response; 131 | } -------------------------------------------------------------------------------- /Src/GetHotlinksCommand.hpp: -------------------------------------------------------------------------------- 1 | #if !defined (GETHOTLINKSCOMMAND_HPP) 2 | #define GETHOTLINKSCOMMAND_HPP 3 | 4 | #pragma once 5 | 6 | #include "AdditionalJSONCommand.hpp" 7 | 8 | 9 | class GetHotlinksCommand : public AdditionalJSONCommand { 10 | public: 11 | virtual GS::String GetName () const override; 12 | virtual GS::Optional GetSchemaDefinitions () const override; 13 | virtual GS::Optional GetResponseSchema () const override; 14 | virtual GS::ObjectState Execute (const GS::ObjectState& parameters, GS::ProcessControl& processControl) const override; 15 | }; 16 | 17 | 18 | #endif -------------------------------------------------------------------------------- /Src/GetProjectInfoCommand.cpp: -------------------------------------------------------------------------------- 1 | #include "GetProjectInfoCommand.hpp" 2 | #include "ObjectState.hpp" 3 | 4 | 5 | GS::String GetProjectInfoCommand::GetName () const 6 | { 7 | return "GetProjectInfo"; 8 | } 9 | 10 | 11 | constexpr const char* IsUntitledResponseField = "isUntitled"; 12 | constexpr const char* IsTeamworkResponseField = "isTeamwork"; 13 | constexpr const char* ProjectLocationResponseField = "projectLocation"; 14 | constexpr const char* ProjectPathResponseField = "projectPath"; 15 | constexpr const char* ProjectNameResponseField = "projectName"; 16 | 17 | 18 | GS::Optional GetProjectInfoCommand::GetResponseSchema () const 19 | { 20 | return GS::UniString::Printf (R"({ 21 | "type": "object", 22 | "properties": { 23 | "%s": { 24 | "type": "boolean", 25 | "description": "True, if the project is not saved yet." 26 | }, 27 | "%s": { 28 | "type": "boolean", 29 | "description": "True, if the project is a Teamwork (BIMcloud) project." 30 | }, 31 | "%s": { 32 | "type": "string", 33 | "description": "The location of the project in the filesystem or a BIMcloud project reference.", 34 | "minLength": 1 35 | }, 36 | "%s": { 37 | "type": "string", 38 | "description": "The path of the project. A filesystem path or a BIMcloud server relative path.", 39 | "minLength": 1 40 | }, 41 | "%s": { 42 | "type": "string", 43 | "description": "The name of the project.", 44 | "minLength": 1 45 | } 46 | }, 47 | "additionalProperties": false, 48 | "required": [ 49 | "%s", 50 | "%s" 51 | ] 52 | })", 53 | IsUntitledResponseField, IsTeamworkResponseField, ProjectLocationResponseField, ProjectPathResponseField, ProjectNameResponseField, 54 | IsUntitledResponseField, IsTeamworkResponseField); 55 | } 56 | 57 | 58 | GS::ObjectState GetProjectInfoCommand::Execute (const GS::ObjectState& /*parameters*/, GS::ProcessControl& /*processControl*/) const 59 | { 60 | API_ProjectInfo projectInfo = {}; 61 | GSErrCode err = ACAPI_Environment (APIEnv_ProjectID, &projectInfo); 62 | 63 | if (err != NoError) { 64 | return CreateErrorResponse (APIERR_NOPLAN, "Failed to retrieve project information. Check the opened project!"); 65 | } 66 | 67 | GS::ObjectState response; 68 | response.Add (IsUntitledResponseField, projectInfo.untitled); 69 | if (!projectInfo.untitled) { 70 | response.Add (IsTeamworkResponseField, projectInfo.teamwork); 71 | if (projectInfo.location) { 72 | response.Add (ProjectLocationResponseField, projectInfo.location->ToDisplayText ()); 73 | } 74 | if (projectInfo.projectPath) { 75 | response.Add (ProjectPathResponseField, *projectInfo.projectPath); 76 | } 77 | if (projectInfo.projectName) { 78 | response.Add (ProjectNameResponseField, *projectInfo.projectName); 79 | } 80 | } 81 | 82 | return response; 83 | } -------------------------------------------------------------------------------- /Src/GetProjectInfoCommand.hpp: -------------------------------------------------------------------------------- 1 | #if !defined (GETPROJECTINFOCOMMAND_HPP) 2 | #define GETPROJECTINFOCOMMAND_HPP 3 | 4 | #pragma once 5 | 6 | #include "AdditionalJSONCommand.hpp" 7 | 8 | 9 | class GetProjectInfoCommand : public AdditionalJSONCommand { 10 | public: 11 | virtual GS::String GetName () const override; 12 | virtual GS::Optional GetResponseSchema () const override; 13 | virtual GS::ObjectState Execute (const GS::ObjectState& parameters, GS::ProcessControl& processControl) const override; 14 | }; 15 | 16 | 17 | #endif -------------------------------------------------------------------------------- /Src/Main.cpp: -------------------------------------------------------------------------------- 1 | // ***************************************************************************** 2 | // Contact person: Tibor Lorántfy (lorantfyt@gmail.com) 3 | // ***************************************************************************** 4 | 5 | #include "APIEnvir.h" 6 | #include "ACAPinc.h" // also includes APIdefs.h 7 | 8 | #include "PublishCommand.hpp" 9 | #include "PublishCommand.hpp" 10 | #include "TeamworkReceiveCommand.hpp" 11 | #include "GetProjectInfoCommand.hpp" 12 | #include "GetArchicadLocationCommand.hpp" 13 | #include "QuitCommand.hpp" 14 | #include "ReloadLibrariesCommand.hpp" 15 | #include "MoveElementsCommand.hpp" 16 | #include "CreateColumnsCommand.hpp" 17 | #include "CreateSlabsCommand.hpp" 18 | #include "CreateObjectsCommand.hpp" 19 | #include "GetHotlinksCommand.hpp" 20 | #include "GetGDLParametersOfElementsCommand.hpp" 21 | #include "ChangeGDLParametersOfElementsCommand.hpp" 22 | 23 | 24 | // ============================================================================= 25 | // 26 | // Required functions 27 | // 28 | // ============================================================================= 29 | 30 | // ----------------------------------------------------------------------------- 31 | // Dependency definitions 32 | // ----------------------------------------------------------------------------- 33 | 34 | API_AddonType __ACDLL_CALL CheckEnvironment (API_EnvirParams* envir) 35 | { 36 | RSGetIndString (&envir->addOnInfo.name, 32000, 1, ACAPI_GetOwnResModule ()); 37 | RSGetIndString (&envir->addOnInfo.description, 32000, 2, ACAPI_GetOwnResModule ()); 38 | 39 | return APIAddon_Preload; 40 | } // CheckEnvironment 41 | 42 | 43 | // ----------------------------------------------------------------------------- 44 | // Interface definitions 45 | // ----------------------------------------------------------------------------- 46 | 47 | GSErrCode __ACDLL_CALL RegisterInterface (void) 48 | { 49 | return NoError; 50 | } // RegisterInterface 51 | 52 | 53 | // ----------------------------------------------------------------------------- 54 | // Initialize 55 | // called after the Add-On has been loaded into memory 56 | // ----------------------------------------------------------------------------- 57 | 58 | GSErrCode __ACENV_CALL Initialize (void) 59 | { 60 | GSErrCode err = NoError; 61 | 62 | err |= ACAPI_Install_AddOnCommandHandler (GS::NewOwned ()); 63 | err |= ACAPI_Install_AddOnCommandHandler (GS::NewOwned ()); 64 | err |= ACAPI_Install_AddOnCommandHandler (GS::NewOwned ()); 65 | err |= ACAPI_Install_AddOnCommandHandler (GS::NewOwned ()); 66 | err |= ACAPI_Install_AddOnCommandHandler (GS::NewOwned ()); 67 | err |= ACAPI_Install_AddOnCommandHandler (GS::NewOwned ()); 68 | err |= ACAPI_Install_AddOnCommandHandler (GS::NewOwned ()); 69 | err |= ACAPI_Install_AddOnCommandHandler (GS::NewOwned ()); 70 | err |= ACAPI_Install_AddOnCommandHandler (GS::NewOwned ()); 71 | err |= ACAPI_Install_AddOnCommandHandler (GS::NewOwned ()); 72 | err |= ACAPI_Install_AddOnCommandHandler (GS::NewOwned ()); 73 | err |= ACAPI_Install_AddOnCommandHandler (GS::NewOwned ()); 74 | err |= ACAPI_Install_AddOnCommandHandler (GS::NewOwned ()); 75 | 76 | return err; 77 | } // Initialize 78 | 79 | 80 | // ----------------------------------------------------------------------------- 81 | // FreeData 82 | // called when the Add-On is going to be unloaded 83 | // ----------------------------------------------------------------------------- 84 | 85 | GSErrCode __ACENV_CALL FreeData (void) 86 | { 87 | return NoError; 88 | } // FreeData 89 | -------------------------------------------------------------------------------- /Src/MoveElementsCommand.cpp: -------------------------------------------------------------------------------- 1 | #include "MoveElementsCommand.hpp" 2 | #include "ObjectState.hpp" 3 | 4 | 5 | GS::String MoveElementsCommand::GetName () const 6 | { 7 | return "MoveElements"; 8 | } 9 | 10 | 11 | constexpr const char* ElementsWithMoveVectorsParameterField = "elementsWithMoveVectors"; 12 | constexpr const char* MoveVectorField = "moveVector"; 13 | constexpr const char* CopyField = "copy"; 14 | 15 | 16 | GS::Optional MoveElementsCommand::GetInputParametersSchema () const 17 | { 18 | return GS::UniString::Printf (R"({ 19 | "type": "object", 20 | "properties": { 21 | "%s": { 22 | "type": "array", 23 | "description": "The elements with move vector pairs.", 24 | "items": { 25 | "type": "object", 26 | "properties": { 27 | "%s": { 28 | "$ref": "APITypes.json#/definitions/ElementId" 29 | }, 30 | "%s": { 31 | "type": "object", 32 | "description" : "Move vector of a 3D point.", 33 | "properties" : { 34 | "x": { 35 | "type": "number", 36 | "description" : "X value of the vector." 37 | }, 38 | "y" : { 39 | "type": "number", 40 | "description" : "Y value of the vector." 41 | }, 42 | "z" : { 43 | "type": "number", 44 | "description" : "Z value of the vector." 45 | } 46 | }, 47 | "additionalProperties": false, 48 | "required" : [ 49 | "x", 50 | "y", 51 | "z" 52 | ] 53 | }, 54 | "%s": { 55 | "type": "boolean", 56 | "description" : "Optional parameter. If true, then a copy of the element will be moved. By default it's false." 57 | } 58 | }, 59 | "additionalProperties": false, 60 | "required": [ 61 | "%s", 62 | "%s" 63 | ] 64 | } 65 | } 66 | }, 67 | "additionalProperties": false, 68 | "required": [ 69 | "%s" 70 | ] 71 | })", 72 | ElementsWithMoveVectorsParameterField, 73 | ElementIdField, 74 | MoveVectorField, 75 | CopyField, 76 | ElementIdField, MoveVectorField, 77 | ElementsWithMoveVectorsParameterField); 78 | } 79 | 80 | 81 | static API_Vector3D GetVector3DFromMoveVectorField (const GS::ObjectState& os) 82 | { 83 | API_Vector3D v; 84 | os.Get ("x", v.x); 85 | os.Get ("y", v.y); 86 | os.Get ("z", v.z); 87 | return v; 88 | } 89 | 90 | 91 | static GSErrCode MoveElement (const API_Guid& elemGuid, const API_Vector3D& moveVector, bool withCopy) 92 | { 93 | GS::Array elementsToEdit = { API_Neig (elemGuid) }; 94 | 95 | API_EditPars editPars = {}; 96 | editPars.typeID = APIEdit_Drag; 97 | editPars.endC = moveVector; 98 | editPars.withDelete = !withCopy; 99 | 100 | return ACAPI_Element_Edit (&elementsToEdit, editPars); 101 | } 102 | 103 | 104 | GS::ObjectState MoveElementsCommand::Execute (const GS::ObjectState& parameters, GS::ProcessControl& /*processControl*/) const 105 | { 106 | GS::Array elementsWithMoveVectors; 107 | parameters.Get (ElementsWithMoveVectorsParameterField, elementsWithMoveVectors); 108 | 109 | API_Guid elemGuid; 110 | const APIErrCodes err = (APIErrCodes) ACAPI_CallUndoableCommand ("Move Elements", [&] () -> GSErrCode { 111 | for (const GS::ObjectState& elementWithMoveVector : elementsWithMoveVectors) { 112 | const GS::ObjectState* elementId = elementWithMoveVector.Get (ElementIdField); 113 | const GS::ObjectState* moveVector = elementWithMoveVector.Get (MoveVectorField); 114 | if (elementId == nullptr || moveVector == nullptr) { 115 | continue; 116 | } 117 | 118 | elemGuid = GetGuidFromElementIdField (*elementId); 119 | 120 | bool copy = false; 121 | elementWithMoveVector.Get (CopyField, copy); 122 | 123 | const GSErrCode err = MoveElement (elemGuid, 124 | GetVector3DFromMoveVectorField (*moveVector), 125 | copy); 126 | if (err != NoError) { 127 | return err; 128 | } 129 | } 130 | 131 | return NoError; 132 | }); 133 | 134 | if (err != NoError) { 135 | const GS::UniString errorMsg = GS::UniString::Printf ("Failed to move element with guid %T!", APIGuidToString (elemGuid).ToPrintf ()); 136 | return CreateErrorResponse (err, errorMsg); 137 | } 138 | 139 | return {}; 140 | } -------------------------------------------------------------------------------- /Src/MoveElementsCommand.hpp: -------------------------------------------------------------------------------- 1 | #if !defined (MOVEELEMENTSCOMMAND_HPP) 2 | #define MOVEELEMENTSCOMMAND_HPP 3 | 4 | #pragma once 5 | 6 | #include "AdditionalJSONCommand.hpp" 7 | 8 | 9 | class MoveElementsCommand : public AdditionalJSONCommand { 10 | public: 11 | virtual GS::String GetName () const override; 12 | virtual GS::Optional GetInputParametersSchema () const override; 13 | virtual GS::ObjectState Execute (const GS::ObjectState& parameters, GS::ProcessControl& processControl) const override; 14 | }; 15 | 16 | 17 | #endif -------------------------------------------------------------------------------- /Src/PublishCommand.cpp: -------------------------------------------------------------------------------- 1 | #include "PublishCommand.hpp" 2 | #include "ObjectState.hpp" 3 | 4 | 5 | static GS::HashTable GetPublisherSetNameGuidTable () 6 | { 7 | GS::HashTable table; 8 | 9 | Int32 numberOfPublisherSets = 0; 10 | ACAPI_Navigator (APINavigator_GetNavigatorSetNumID, &numberOfPublisherSets); 11 | 12 | API_NavigatorSet set = {}; 13 | for (Int32 ii = 0; ii < numberOfPublisherSets; ++ii) { 14 | set.mapId = API_PublisherSets; 15 | if (ACAPI_Navigator (APINavigator_GetNavigatorSetID, &set, &ii) == NoError) { 16 | table.Add (set.name, set.rootGuid); 17 | } 18 | } 19 | 20 | return table; 21 | } 22 | 23 | 24 | GS::String PublishCommand::GetName () const 25 | { 26 | return "Publish"; 27 | } 28 | 29 | 30 | constexpr const char* PublisherSetNameParameterField = "publisherSetName"; 31 | constexpr const char* OutputPathParameterField = "outputPath"; 32 | 33 | 34 | GS::Optional PublishCommand::GetInputParametersSchema () const 35 | { 36 | return GS::UniString::Printf (R"({ 37 | "type": "object", 38 | "properties": { 39 | "%s": { 40 | "type": "string", 41 | "description": "The name of the publisher set.", 42 | "minLength": 1 43 | }, 44 | "%s": { 45 | "type": "string", 46 | "description": "Full local or LAN path for publishing. Optional, by default the path set in the settings of the publiser set will be used.", 47 | "minLength": 1 48 | } 49 | }, 50 | "additionalProperties": false, 51 | "required": [ 52 | "%s" 53 | ] 54 | })", 55 | PublisherSetNameParameterField, OutputPathParameterField, 56 | PublisherSetNameParameterField); 57 | } 58 | 59 | 60 | GS::ObjectState PublishCommand::Execute (const GS::ObjectState& parameters, GS::ProcessControl& /*processControl*/) const 61 | { 62 | GS::UniString publisherSetName; 63 | parameters.Get (PublisherSetNameParameterField, publisherSetName); 64 | 65 | const auto publisherSetNameGuidTable = GetPublisherSetNameGuidTable (); 66 | if (!publisherSetNameGuidTable.ContainsKey (publisherSetName)) { 67 | return CreateErrorResponse (APIERR_BADNAME, "Not valid publisher set name."); 68 | } 69 | 70 | API_PublishPars publishPars = {}; 71 | publishPars.guid = publisherSetNameGuidTable.Get (publisherSetName); 72 | 73 | if (parameters.Contains (OutputPathParameterField)) { 74 | GS::UniString outputPath; 75 | parameters.Get (OutputPathParameterField, outputPath); 76 | publishPars.path = new IO::Location (outputPath); 77 | } 78 | 79 | GSErrCode err = ACAPI_Automate (APIDo_PublishID, &publishPars); 80 | 81 | delete publishPars.path; 82 | 83 | if (err != NoError) { 84 | return CreateErrorResponse (APIERR_COMMANDFAILED, "Publishing failed. Check output path!"); 85 | } 86 | 87 | return {}; 88 | } -------------------------------------------------------------------------------- /Src/PublishCommand.hpp: -------------------------------------------------------------------------------- 1 | #if !defined (PUBLISHCOMMAND_HPP) 2 | #define PUBLISHCOMMAND_HPP 3 | 4 | #pragma once 5 | 6 | #include "AdditionalJSONCommand.hpp" 7 | 8 | 9 | class PublishCommand : public AdditionalJSONCommand { 10 | public: 11 | virtual GS::String GetName () const override; 12 | virtual GS::Optional GetInputParametersSchema () const override; 13 | virtual GS::ObjectState Execute (const GS::ObjectState& parameters, GS::ProcessControl& processControl) const override; 14 | }; 15 | 16 | 17 | #endif -------------------------------------------------------------------------------- /Src/QuitCommand.cpp: -------------------------------------------------------------------------------- 1 | #include "QuitCommand.hpp" 2 | #include "ObjectState.hpp" 3 | 4 | 5 | GS::String QuitCommand::GetName () const 6 | { 7 | return "Quit"; 8 | } 9 | 10 | 11 | GS::ObjectState QuitCommand::Execute (const GS::ObjectState& /*parameters*/, GS::ProcessControl& /*processControl*/) const 12 | { 13 | Int64 magicCode = 1234; 14 | GSErrCode err = ACAPI_Automate (APIDo_QuitID, reinterpret_cast (magicCode)); 15 | 16 | if (err != NoError) { 17 | return CreateErrorResponse (APIERR_COMMANDFAILED, "Failed to quit Archicad!"); 18 | } 19 | 20 | return {}; 21 | } -------------------------------------------------------------------------------- /Src/QuitCommand.hpp: -------------------------------------------------------------------------------- 1 | #if !defined (QUITCOMMAND_HPP) 2 | #define QUITCOMMAND_HPP 3 | 4 | #pragma once 5 | 6 | #include "AdditionalJSONCommand.hpp" 7 | 8 | 9 | class QuitCommand : public AdditionalJSONCommand { 10 | public: 11 | virtual GS::String GetName () const override; 12 | virtual GS::ObjectState Execute (const GS::ObjectState& parameters, GS::ProcessControl& processControl) const override; 13 | }; 14 | 15 | 16 | #endif -------------------------------------------------------------------------------- /Src/ReloadLibrariesCommand.cpp: -------------------------------------------------------------------------------- 1 | #include "ReloadLibrariesCommand.hpp" 2 | #include "ObjectState.hpp" 3 | 4 | 5 | GS::String ReloadLibrariesCommand::GetName () const 6 | { 7 | return "ReloadLibraries"; 8 | } 9 | 10 | 11 | GS::ObjectState ReloadLibrariesCommand::Execute (const GS::ObjectState& /*parameters*/, GS::ProcessControl& /*processControl*/) const 12 | { 13 | GSErrCode err = ACAPI_Automate (APIDo_ReloadLibrariesID); 14 | 15 | if (err != NoError) { 16 | return CreateErrorResponse (APIERR_COMMANDFAILED, "Reloading Libraries failed. Check internet connection if you have active libraries from BIMcloud!"); 17 | } 18 | 19 | return {}; 20 | } -------------------------------------------------------------------------------- /Src/ReloadLibrariesCommand.hpp: -------------------------------------------------------------------------------- 1 | #if !defined (RELOADLIBRARIESCOMMAND_HPP) 2 | #define RELOADLIBRARIESCOMMAND_HPP 3 | 4 | #pragma once 5 | 6 | #include "AdditionalJSONCommand.hpp" 7 | 8 | 9 | class ReloadLibrariesCommand : public AdditionalJSONCommand { 10 | public: 11 | virtual GS::String GetName () const override; 12 | virtual GS::ObjectState Execute (const GS::ObjectState& parameters, GS::ProcessControl& processControl) const override; 13 | }; 14 | 15 | 16 | #endif -------------------------------------------------------------------------------- /Src/TeamworkReceiveCommand.cpp: -------------------------------------------------------------------------------- 1 | #include "TeamworkReceiveCommand.hpp" 2 | #include "ObjectState.hpp" 3 | 4 | 5 | GS::String TeamworkReceiveCommand::GetName () const 6 | { 7 | return "TeamworkReceive"; 8 | } 9 | 10 | 11 | GS::ObjectState TeamworkReceiveCommand::Execute (const GS::ObjectState& /*parameters*/, GS::ProcessControl& /*processControl*/) const 12 | { 13 | GSErrCode err = ACAPI_TeamworkControl_ReceiveChanges (); 14 | 15 | if (err != NoError) { 16 | return CreateErrorResponse (APIERR_SERVICEFAILED, "Receive failed. Check internet connection!"); 17 | } 18 | 19 | return {}; 20 | } -------------------------------------------------------------------------------- /Src/TeamworkReceiveCommand.hpp: -------------------------------------------------------------------------------- 1 | #if !defined (TEAMWORKRECEIVECOMMAND_HPP) 2 | #define TEAMWORKRECEIVECOMMAND_HPP 3 | 4 | #pragma once 5 | 6 | #include "AdditionalJSONCommand.hpp" 7 | 8 | 9 | class TeamworkReceiveCommand : public AdditionalJSONCommand { 10 | public: 11 | virtual GS::String GetName () const override; 12 | virtual GS::ObjectState Execute (const GS::ObjectState& parameters, GS::ProcessControl& processControl) const override; 13 | }; 14 | 15 | 16 | #endif --------------------------------------------------------------------------------