SDK:Auto-dimension support
.SDK|SDK ..SDK:Types|SDK Types ..SDK:Using the SDK|Using the SDK ..VCOM:VCOM (Vectorworks Component Object Model)|VCOM Basics ..VCOM:Class Reference|VCOM Class Reference
By Josh Loy
Automatic dimension support
Graphic Legends have provisions for automatic dimensioning which is especially useful for doors and windows but it can be included with almost any plug-in object.
The different types of auto-dimensions are identified by a universal name, Vectorworks provides some predefined types in the following string file: "Vectorworks/Strings/AutoDimensionIdentifiers.vwstrings"
Developers can implement some, none, or all of the predefined types or provide their own custom types. Auto-dimensions may be restricted to be visible in certain views or orientations, and they may also be stacked.
To support auto-dimensioning your plug-in should implement the following event sync functions:
OnAutoDimMessage_GetLocalizedTypeName - Has the universal name as the input parameter and the developer will output the translated long name/description. Most time you would just look for the universal name in the vwstrings file above and return the long string.
OnAutoDimMessage_GetSupportedTypes - Has the "view" as in input and the developer will output an array of TAutoDimensionTypeInfo which contains the universal names for dimension types supported for that view along with the orientation/location of its supported dimensions.
OnAutoDimMessage_GetDimensionDefinitions - Has the "view", universal name, and orientation as input parameters and the developer will output an array of TAutoDimensionDefinition which contains 3D points to place the dimensions along with an "offset" parameter. The "offset" parameter (1,2,3...) is used to control the stacking of dimensions, usually defaulted to 0, adding 1 will make the dimensions stack on 0 dimensions, 2 will stack on 1, etc.
Sample SDK code to implement auto-dimensioning by modifying Plug-Ins\Samples\TesterModule\Source\Advanced
:
ExtObjAdvComplex.h
class CObjAdvComplex_EventSink : public VWParametric_EventSink { public: ... virtual bool OnAutoDimMessage_GetLocalizedTypeName(const TXString& instrDimID_UniversalName, TXString& outstrDimID_LocalizedName); virtual bool OnAutoDimMessage_GetSupportedTypes(EViewTypes inView, std::vector<VectorWorks::Extension::TAutoDimensionTypeInfo>& outvecTypes); virtual bool OnAutoDimMessage_GetDimensionDefinitions(EViewTypes inView, const TXString& instrDimID_UniversalName, VectorWorks::Extension::EAutoDimensionPlacement inPlace, std::vector<VectorWorks::Extension::TAutoDimensionDefinition>& outvecDimensions); };
ExtObjAdvComplex.cpp
////////////////////////////////////////////////////////////////////////////// // Auto Dimension handler ////////////////////////////////////////////////////////////////////////////// // Universal Names in "AutoDimensionIdentifiers.vwstrings" enum EDimIDIndex { kUnit, kUnitBottomSash, kPIOCustom, kNumDimIDs}; const TXString karrstrDimIDUniversal[kNumDimIDs] = { "Unit", "UnitBottomAndSash", "ThisPluginCustom" }; const TXString kThisPluginCustomDimName = "Custom PIO Dimension"; //---------------------------------------------------------------------------- static EDimIDIndex DimIDIndexFromUniversalTypeName(const TXString& instrDimID_UniversalName) { EDimIDIndex outDimIDIndex = kNumDimIDs; for (int i = 0; i < kNumDimIDs; i++) { if (instrDimID_UniversalName.EqualNoCase(karrstrDimIDUniversal[i])) { outDimIDIndex = (EDimIDIndex)i; break; } } return outDimIDIndex; } //---------------------------------------------------------------------------- bool LLGetLocalizedWindowTypeName(const TXString& instrDimID_UniversalName, TXString& outstrDimID_LocalizedName) { bool outbSuccess = false; const TXString kStringFileName = "Vectorworks/Strings/AutoDimensionIdentifiers.vwstrings"; TXString strLocalized; gSDK->GetVWResourceString(strLocalized, kStringFileName, instrDimID_UniversalName, eAllowEmptyResult); if (!strLocalized.IsEmpty()) { outstrDimID_LocalizedName = strLocalized; outbSuccess = true; } return outbSuccess; } bool CObjAdvComplex_EventSink::OnAutoDimMessage_GetLocalizedTypeName(const TXString& instrDimID_UniversalName, TXString& outstrDimID_LocalizedName) { bool outResult = true; if (!instrDimID_UniversalName.IsEmpty()) { EDimIDIndex dimID = DimIDIndexFromUniversalTypeName(instrDimID_UniversalName); if (dimID < kNumDimIDs) { if (!LLGetLocalizedWindowTypeName(instrDimID_UniversalName, outstrDimID_LocalizedName)) outResult = false; } else { outResult = false; } } else { outResult = false; } return outResult; } bool CObjAdvComplex_EventSink::OnAutoDimMessage_GetSupportedTypes(EViewTypes inView, std::vector<VectorWorks::Extension::TAutoDimensionTypeInfo>& outvecADTI) { outvecADTI.clear(); if (setmember(inView, EViewTypes::TopPlan, EViewTypes::Front)) { for (int i = 0; i < kNumDimIDs; i++) { TXString strLocalizedName; // Get the dimension type localized Name if (!LLGetLocalizedWindowTypeName(karrstrDimIDUniversal[i], strLocalizedName)) strLocalizedName = kThisPluginCustomDimName; // Set the support dimension and views TAutoDimensionTypeInfo adti(karrstrDimIDUniversal[i], strLocalizedName); if (i == kUnit) { adti.fvecPlaces.push_back(EAutoDimensionPlacement::eHorizontalTop); adti.fvecPlaces.push_back(EAutoDimensionPlacement::eHorizontalBottom); adti.fvecPlaces.push_back(EAutoDimensionPlacement::eVerticalLeft); adti.fvecPlaces.push_back(EAutoDimensionPlacement::eVerticalRight); } else if (i == kUnitBottomSash && inView == EViewTypes::Front) { adti.fvecPlaces.push_back(EAutoDimensionPlacement::eVerticalRight); } else if (i == kPIOCustom && inView == EViewTypes::TopPlan) { adti.fvecPlaces.push_back(EAutoDimensionPlacement::eHorizontalTop); adti.fvecPlaces.push_back(EAutoDimensionPlacement::eVerticalRight); } outvecADTI.emplace_back(adti); } } return true; } bool CObjAdvComplex_EventSink::OnAutoDimMessage_GetDimensionDefinitions(EViewTypes inView, const TXString& instrDimID_UniversalName, VectorWorks::Extension::EAutoDimensionPlacement inPlace, std::vector<VectorWorks::Extension::TAutoDimensionDefinition>& outvecDimensions) { bool outResult = false; WorldRect dimBox; WorldPt3 wpt3S, wpt3E; EDimIDIndex dimID = DimIDIndexFromUniversalTypeName(instrDimID_UniversalName); if (dimID == kUnit && (inView == EViewTypes::TopPlan)) { switch (inPlace) { case EAutoDimensionPlacement::eHorizontalTop: wpt3S.Set(-1000, 1000, 0); wpt3E.Set( 1000, 1000, 0); break; case EAutoDimensionPlacement::eHorizontalBottom: wpt3S.Set(-1000, 0, 0); wpt3E.Set( 1000, 0, 0); break; case EAutoDimensionPlacement::eVerticalLeft: wpt3S.Set(-1000, 1000, 0); wpt3E.Set(-1000, 0, 0); break; case EAutoDimensionPlacement::eVerticalRight: wpt3S.Set(1000, 0, 0); wpt3E.Set(1000, 1000, 0); break; default: DSTOP((kEveryone, "Unexpected")); break; } outvecDimensions.emplace_back(wpt3S, wpt3E); outResult = true; } else if (dimID == kUnit && (inView == EViewTypes::Front)) { switch (inPlace) { case EAutoDimensionPlacement::eHorizontalTop: wpt3S.Set(-1000, 0, 1000); wpt3E.Set(1000, 0, 1000); break; case EAutoDimensionPlacement::eHorizontalBottom: wpt3S.Set(-1000, 0, 0); wpt3E.Set(1000, 0, 0); break; case EAutoDimensionPlacement::eVerticalLeft: wpt3S.Set(-1000, 0, 1000); wpt3E.Set(-1000, 0, 0); break; case EAutoDimensionPlacement::eVerticalRight: wpt3S.Set(1000, 0, 0); wpt3E.Set(1000, 0, 1000); break; default: DSTOP((kEveryone, "Unexpected")); break; } outvecDimensions.emplace_back(wpt3S, wpt3E); outResult = true; } else if (dimID == kPIOCustom && inView == EViewTypes::TopPlan) { switch (inPlace) { case EAutoDimensionPlacement::eHorizontalTop: wpt3S.Set(-500, 1000, 0); wpt3E.Set(500, 1000, 0); break; case EAutoDimensionPlacement::eVerticalRight: wpt3S.Set(500, 0, 0); wpt3E.Set(500, 1000, 0); break; default: DSTOP((kEveryone, "Unexpected")); break; } outvecDimensions.emplace_back(wpt3S, wpt3E); outResult = true; } else if (dimID == kUnitBottomSash && inView == EViewTypes::Front && inPlace == EAutoDimensionPlacement::eVerticalRight) { // "Unit Size + Bottom of Unit to Floor + Leaf/Sash Size"; wpt3S.Set(500, 0, 100); wpt3E.Set(500, 0, 900); outvecDimensions.emplace_back(wpt3S, wpt3E, 0); wpt3S.Set(500, 0, 0); wpt3E.Set(500, 0, 1000); outvecDimensions.emplace_back(wpt3S, wpt3E, 1); wpt3S.Set(500, 0, 0); wpt3E.Set(500, 0, -2000); outvecDimensions.emplace_back(wpt3S, wpt3E, 1); outResult = true; } else { DSTOP((kEveryone, "Unexpected")); } return outResult; }
Sample VS code to implement auto-dimensioning:
PROCEDURE EventWrapper; CONST {$Include Common\Includes\vsoEventsConstants.px} kADTResFile = 'Vectorworks/Strings/AutoDimensionIdentifiers.vwstrings'; kUniADT_Cat = 'NNA_DefaultAutoDimWinDoorCategory'; kUniADT_Sash = 'Sash'; kUniADT_Unit = 'Unit'; kUniADT_Leaf = 'Leaf'; kUniADT_RO = 'RoughOpening'; kADT_Leaf = 1; {indices into arrUniADT} kADT_Unit = 2; kADT_RO = 3; kADTCount = 3; kVT_NotSet = 0; kVT_Top = 1; kVT_Bottom = 2; kVT_TopBottomCut = 3; kVT_Front = 4; kVT_Back = 5; kVT_FrontBackCut = 6; kVT_Left = 7; kVT_Right = 8; kVT_LeftRightCut = 9; kVT_TopPlan = 10; kDP_HorizontalTop = 0; kDP_HorizontalBottom = 1; kDP_VerticalLeft = 2; kDP_VerticalRight = 3; kADP_GetLocTypeName = 76; kADP_GetSupportedTypes = 77; kADP_GetDefinitions = 78; kADP_GetCategoryName = 79; kLeafWidth = 36; kLeafHeight = 84; kJambWidth = 2; kShimGap = 1; kDoorThickness = 2; VAR gPluginName : STRING; {plug-in name} gPluginH : HANDLE; {handle to the plug-in} recordH : HANDLE; {handle to the plug-in record} wallH : HANDLE; {handle to the wall, if the plug-in is inserted into a wall} noneClass : STRING; {global variable from ObjectStandardInclude.px [not used]} saveClass : STRING; {global variable from ObjectStandardInclude.px [not used]} theEvent : LONGINT; stateMessage : LONGINT; uniADType : STRING; locADType : STRING; viewType : INTEGER; dimPlace : INTEGER; arrUniADT : ARRAY [1..kADTCount] OF STRING; iADT : INTEGER; catLocName : STRING; catUniName : STRING; useWidth : REAL; useHeight : REAL; p1x : REAL; p1y : REAL; p1z : REAL; p2x : REAL; p2y : REAL; p2z : REAL; offset : INTEGER; placeFactor : INTEGER; viewFactor : INTEGER; bSuccess : BOOLEAN; isObjOK : BOOLEAN; {---------------------------------------------------------------------------------------------} {$INCLUDE Common\Includes\ObjectStandardInclude.px} {$INCLUDE Common\Includes\CheckParameterValues2.px} {$INCLUDE Common\Includes\FileChk.px} {---------------------------------------------------------------------------------------------} PROCEDURE DoorLikeObject; VAR dx : REAL; dy : REAL; h : REAL; BEGIN {* Main *} DselectAll; IF SetUpObject (gPluginName, gPluginH, recordH, wallH, saveClass, noneClass) THEN BEGIN dx := kLeafWidth / 2; dy := kDoorThickness / 2; h := kLeafHeight; Poly3D(-dx,-dy,0, dx,-dy,0, dx,-dy,h, -dx,-dy,h, -dx,-dy,0, -dx,dy,0, dx,dy,0, dx,dy,h, -dx,dy,h, -dx,dy,0); SetDownObject; END; {of SetUpObject = TRUE} END; {of Main} BEGIN { EventWrapper } vsoGetEventInfo( theEvent, stateMessage ); isObjOK := SetUpObject( gPluginName, gPluginH, recordH, wallH, saveClass, noneClass ); CASE theEvent OF kObjOnInitXProperties: BEGIN END; kADP_GetCategoryName: BEGIN catUniName := kUniADT_Cat; GetVWRString(catLocName, kADTResFile, catUniName); vsoADPSetCatName(stateMessage, catUniName, catLocName); vsoSetEventResult( kObjectEventHandled ); END; kADP_GetLocTypeName: BEGIN vsoADPGetUniTypeName(stateMessage, uniADType); IF ((uniADType = kUniADT_Unit) | (uniADType = kUniADT_Leaf) | (uniADType = kUniADT_RO)) THEN GetVWRString(locADType, kADTResFile, uniADType) ELSE locADType := ''; vsoADPSetLocTypeName(stateMessage, locADType); vsoSetEventResult( kObjectEventHandled ); END; {of CASE kADP_GetLocTypeName} kADP_GetSupportedTypes: BEGIN vsoADPGetViewType(stateMessage, viewType); IF ((viewType = kVT_TopPlan) | (viewType = kVT_Top) | (viewType = kVT_Bottom) | (viewType = kVT_Front) | (viewType = kVT_Back) | (viewType = kVT_Left) | (viewType = kVT_Right)) THEN BEGIN arrUniADT[kADT_Leaf] := kUniADT_Leaf; arrUniADT[kADT_Unit] := kUniADT_Unit; arrUniADT[kADT_RO] := kUniADT_RO; for iADT := kADT_Leaf TO kADT_RO DO BEGIN GetVWRString(locADType, kADTResFile, arrUniADT[iADT]); IF locADType <> '' THEN BEGIN vsoADPBeginDimType(stateMessage, arrUniADT[iADT], locADType); IF ( ((viewType = kVT_TopPlan) | (viewType = kVT_Top) | (viewType = kVT_Bottom) | (viewType = kVT_Front) | (viewType = kVT_Back)) | ((iADT = kADT_Leaf) & ((viewType = kVT_Left) | (viewType = kVT_Right))) ) THEN BEGIN vsoADPAddDimPlace(stateMessage, kDP_HorizontalTop); vsoADPAddDimPlace(stateMessage, kDP_HorizontalBottom); END; IF ( ((viewType = kVT_Front) | (viewType = kVT_Back) | (viewType = kVT_Left) | (viewType = kVT_Right)) | ((iADT = kADT_Leaf) & ((viewType = kVT_TopPlan) | (viewType = kVT_Top) | (viewType = kVT_Bottom))) ) THEN BEGIN vsoADPAddDimPlace(stateMessage, kDP_VerticalLeft); vsoADPAddDimPlace(stateMessage, kDP_VerticalRight); END; END; END; END; vsoSetEventResult( kObjectEventHandled ); END; {of CASE kADP_GetSupportedTypes} kADP_GetDefinitions: BEGIN vsoADPGetDimDefParms(stateMessage, viewType, uniADType, dimPlace); IF ((viewType = kVT_TopPlan) | (viewType = kVT_Top) | (viewType = kVT_Bottom) | (viewType = kVT_Front) | (viewType = kVT_Back) | (viewType = kVT_Left) | (viewType = kVT_Right)) THEN BEGIN IF ((uniADType = kUniADT_Leaf) | (uniADType = kUniADT_Unit) | (uniADType = kUniADT_RO)) THEN BEGIN IF ((dimPlace = kDP_HorizontalTop) | (dimPlace = kDP_HorizontalBottom) | (dimPlace = kDP_VerticalLeft) | (dimPlace = kDP_VerticalRight)) THEN BEGIN IF uniADType = kUniADT_Leaf THEN BEGIN useWidth := kLeafWidth; useHeight := kLeafHeight; END ELSE IF uniADType = kUniADT_Unit THEN BEGIN useWidth := kLeafWidth + ( kJambWidth * 2 ); useHeight := kLeafHeight + kJambWidth; END ELSE {rough opening} BEGIN useWidth := kLeafWidth + ( kJambWidth * 2 ) + ( kShimGap * 2 ); useHeight := kLeafHeight + kJambWidth + kShimGap; END; bSuccess := false; CASE viewType OF kVT_TopPlan, kVT_Top, kVT_Bottom: BEGIN CASE dimPlace OF kDP_HorizontalTop, kDP_HorizontalBottom: BEGIN IF dimPlace = kDP_HorizontalTop THEN placeFactor := 1 ELSE placeFactor := -1; IF viewType = kVT_Bottom THEN viewFactor := -1 ELSE viewFactor := 1; p1x := -useWidth / 2; p1y := placeFactor * viewFactor * (kDoorThickness / 2); p1z := 0; p2x := useWidth / 2; p2y := placeFactor * viewFactor * (kDoorThickness / 2); p2z := 0; offset := 0; bSuccess := true; END; {of CASE kDP_HorizontalTop, kDP_HorizontalBottom} kDP_VerticalLeft, kDP_VerticalRight: BEGIN IF uniADType = kUniADT_Leaf THEN BEGIN IF dimPlace = kDP_VerticalRight THEN placeFactor := 1 ELSE placeFactor := -1; p1x := placeFactor * (useWidth / 2); p1y := kDoorThickness / 2; p1z := 0; p2x := placeFactor * (useWidth / 2); p2y := -kDoorThickness / 2; p2z := 0; offset := 0; bSuccess := true; END; END; {of CASE kDP_VerticalLeft, kDP_VerticalRight} END; {of CASE dimPlace} END; {of CASE kVT_TopPlan, kVT_Top, kVT_Bottom} kVT_Front, kVT_Back: BEGIN CASE dimPlace OF kDP_HorizontalTop, kDP_HorizontalBottom: BEGIN IF dimPlace = kDP_HorizontalTop THEN placeFactor := 1 ELSE placeFactor := 0; p1x := -useWidth / 2; p1y := 0; p1z := placeFactor * useHeight; p2x := useWidth / 2; p2y := 0; p2z := placeFactor * useHeight; offset := 0; bSuccess := true; END; {of CASE kDP_HorizontalTop, kDP_HorizontalBottom} kDP_VerticalLeft, kDP_VerticalRight: BEGIN IF dimPlace = kDP_VerticalRight THEN placeFactor := 1 ELSE placeFactor := -1; IF viewType = kVT_Front THEN viewFactor := 1 ELSE viewFactor := -1; p1x := placeFactor * viewFactor * (useWidth / 2); p1y := 0; p1z := 0; p2x := placeFactor * viewFactor * (useWidth / 2); p2y := 0; p2z := useHeight; offset := 0; bSuccess := true; END; {of CASE kDP_VerticalLeft, kDP_VerticalRight} END; {of CASE dimPlace} END; {of CASE kVT_Front, kVT_Back} kVT_Left, kVT_Right: BEGIN CASE dimPlace OF kDP_HorizontalTop, kDP_HorizontalBottom: BEGIN IF uniADType = kUniADT_Leaf THEN BEGIN IF dimPlace = kDP_HorizontalTop THEN placeFactor := 1 ELSE placeFactor := 0; p1x := 0; p1y := -kDoorThickness / 2; p1z := placeFactor * useHeight; p2x := 0; p2y := kDoorThickness / 2; p2z := placeFactor * useHeight; offset := 0; bSuccess := true; END; END; {of CASE kDP_HorizontalTop, kDP_HorizontalBottom} kDP_VerticalLeft, kDP_VerticalRight: BEGIN IF dimPlace = kDP_VerticalLeft THEN placeFactor := 1 ELSE placeFactor := -1; IF viewType = kVT_Left THEN viewFactor := 1 ELSE viewFactor := -1; p1x := 0; p1y := placeFactor * viewFactor * kDoorThickness / 2; p1z := 0; p2x := 0; p2y := placeFactor * viewFactor * kDoorThickness / 2; p2z := useHeight; offset := 0; bSuccess := true; END; {of CASE kDP_VerticalLeft, kDP_VerticalRight} END; {of CASE dimPlace} END; {of CASE kVT_Left, kVT_Right} END; {of CASE viewType} IF bSuccess THEN vsoADPAddDimDef(stateMessage, p1x, p1y, p1z, p2x, p2y, p2z, 0); vsoADPAddDimDef(stateMessage, p1x, p1y, p1z, p2x, p2y, p2z, 1); END; {of IF dimPlace} END; {of IF uniADType} END; {of IF viewType} vsoSetEventResult( kObjectEventHandled ); END; {of CASE kADP_GetDefinitions } kResetEventID: BEGIN DoorLikeObject; END; {of CASE kResetEventID } END; END; RUN (EventWrapper);