SDK:Auto-dimension support

From Vectorworks Developer
Jump to navigation Jump to search
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.

.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);