HRESULT CVWScale3DTool::OnDoneScaling()
{
	HRESULT hr = S_OK;
	POSITION pos;
	CTranslate3DObject * pCTrans = NULL;
	IVector			*pvPos = NULL;

	for( pos = m_TransformList.GetHeadPosition(); pos != NULL; )
	{
		pCTrans = m_TransformList.GetNext( pos );
		if(NULL != pCTrans)
		{
			pvPos = NULL;
			if (FAILED(hr = pCTrans->m_pThing->get_ObjectProperty(bstrScale, (IObjectProperty**)&pvPos)))
				goto FAIL_EXIT;

			pvPos->set(pCTrans->currentLocation.x, pCTrans->currentLocation.y, pCTrans->currentLocation.z);
		}
	}

FAIL_EXIT:
	SAFERELEASE(pvPos);
	return hr;
}
STDMETHODIMP CVWExecuteGeomUndo::Redo( IVWUndoItem * predo )
{
	HRESULT hr = S_OK;
	VARIANT varTarget, varRedo;
	IThing *pThing = NULL;
	IVector	*pvPos = NULL;
	IVector	*pvUp = NULL;
	float fX, fY, fCenterX, fCenterY;
	static CComBSTR	bstrScale("Scale");
	static CComBSTR	bstrPosition("Position");
	static CComBSTR	bstrDirection("Direction");
	static CComBSTR	bstrUp("Up");
	IBoundary *pEC = NULL;
	IPropertyList *pBoundaryList = NULL;
	UndoData *pud;
	VARIANT_BOOL vbSafe;
	int i;

	VariantInit(&varTarget);
	VariantInit(&varRedo);

	hr = predo->get_UndoTarget(&varTarget);
	if (FAILED(hr)) goto FAIL_EXIT;

	hr = predo->get_UndoData(&varRedo);
	if (FAILED(hr))	goto FAIL_EXIT;

	pud = (UndoData*) varRedo.byref;
	ASSERT(pud);
	switch(pud->m_ot)
	{
	case SCALE:
		pThing = (IThing*) varTarget.pdispVal;
		ASSERT(pThing);

		if (FAILED(hr = pThing->get_ObjectProperty(bstrScale, (IObjectProperty**)&pvPos)))
			goto FAIL_EXIT;
		pvPos->set(pud->extra.scale.newScale.x, pud->extra.scale.newScale.y, pud->extra.scale.newScale.z);
		break;
	case SCALE2D:
		pEC = (IBoundary*) varTarget.pdispVal;
		ASSERT(pEC);

		fCenterX = pud->extra.scale.oldScale.x;
		fCenterY = pud->extra.scale.oldScale.y;

		i = 0;
		while (TRUE)
		{
			hr = pEC->GetVertexXYExt(i, &fX, &fY);
			if (hr == E_INVALIDARG)
			{
				hr = S_OK;
				break;
			}
			if(FAILED( hr )) goto FAIL_EXIT;

			hr = pEC->SetVertexXY(i, (fX - fCenterX) * pud->extra.scale.newScale.x + fCenterX, (fY - fCenterY) * pud->extra.scale.newScale.y + fCenterY);
			if(FAILED( hr )) goto FAIL_EXIT;
			i++;
		}

		break;
	case TRANSLATE:
		pThing = (IThing*) varTarget.pdispVal;
		ASSERT(pThing);

		if (FAILED(hr = pThing->get_ObjectProperty(bstrPosition, (IObjectProperty**)&pvPos)))
			goto FAIL_EXIT;
		pvPos->set(pud->extra.trans.newPosition.x, pud->extra.trans.newPosition.y, pud->extra.trans.newPosition.z);
		break;
	case TRANSLATE2D:
		pEC = (IBoundary*) varTarget.pdispVal;
		ASSERT(pEC);

		if (pud->extra.trans.nSelectedVert >= 0)  
		{
			//hr = pEC->Translate(pud->extra.trans.newPosition.x + fX, pud->extra.trans.newPosition.y + fY);
			hr = pEC->Translate(pud->extra.trans.newPosition.x, pud->extra.trans.newPosition.y);
			if (FAILED(hr))	goto FAIL_EXIT;
		}
		else //Move the whole Boundary
		{
			hr = pEC->Translate(pud->extra.trans.newPosition.x, pud->extra.trans.newPosition.y);
			if (FAILED(hr))	goto FAIL_EXIT;
		}

		break;
	case ROTATE:
		pThing = (IThing*) varTarget.pdispVal;
		ASSERT(pThing);

		if (FAILED(hr = pThing->get_ObjectProperty(bstrDirection, (IObjectProperty**)&pvPos)))
			goto FAIL_EXIT;
		if (FAILED(hr = pThing->get_ObjectProperty(bstrUp, (IObjectProperty**)&pvUp)))
			goto FAIL_EXIT;
		pvPos->set(pud->extra.rotate.newDirection.x, pud->extra.rotate.newDirection.y, pud->extra.rotate.newDirection.z);
		pvUp->set(pud->extra.rotate.newUp.x, pud->extra.rotate.newUp.y, pud->extra.rotate.newUp.z);
		break;
	case ROTATE2D:
		pEC = (IBoundary*) varTarget.pdispVal;
		ASSERT(pEC);

		hr = pEC->Rotate(0.0f);
		break;
	case NEWBOUNDARY:
		pEC = (IBoundary*) varTarget.pdispVal;
		ASSERT(pEC);

		pud->extra.newboundary.BoundaryList->Add( CComVariant(pEC) );
		if (FAILED(hr)) goto FAIL_EXIT;

		break;
	case DELETEBOUNDARY:
		pEC = (IBoundary*) varTarget.pdispVal;
		ASSERT(pEC);

		pud->extra.newboundary.BoundaryList->Remove(CComVariant(pEC));
		if (FAILED(hr)) goto FAIL_EXIT;

		break;
	case DELETEVERTEX2D:
		pEC = (IBoundary*) varTarget.pdispVal;
		ASSERT(pEC);

		hr = pEC->DeleteVertexSafe(pud->extra.deletevertex.ecVert.index, &vbSafe);
		if (FAILED(hr)) goto FAIL_EXIT;

		hr = pud->extra.deletevertex.BoundaryList->Remove(CComVariant(pEC));
		if (FAILED(hr)) goto FAIL_EXIT;
		hr = pud->extra.deletevertex.BoundaryList->Add(CComVariant(pEC));
		if (FAILED(hr)) goto FAIL_EXIT;

		break;

	case INSERTVERTEX2D:
		pEC = (IBoundary*) varTarget.pdispVal;
		ASSERT(pEC);

		hr = pEC->InsertVertexSafe(	pud->extra.insertvertex.ecVert.index, 
									pud->extra.insertvertex.ecVert.x, 
									pud->extra.insertvertex.ecVert.y, 
									&vbSafe);
		if (FAILED(hr)) goto FAIL_EXIT;

		hr = pud->extra.insertvertex.BoundaryList->Remove(CComVariant(pEC));
		if (FAILED(hr)) goto FAIL_EXIT;
		hr = pud->extra.insertvertex.BoundaryList->Add(CComVariant(pEC));
		if (FAILED(hr)) goto FAIL_EXIT;

		break;
	case FLIPBOUNDARY:
		//pECB = (IBoundaryBuilder*) varTarget.pdispVal;
		//ASSERT(pECB);
		//pECB->ReverseVertices();
		break;
	default:
		OutputDebugString("CVWExecuteGeomRedo::Redo: Unhandled redo type\n");
	}

FAIL_EXIT:
	SAFERELEASE(pvUp);
	SAFERELEASE(pvPos);
	SAFERELEASE(pEC);
	SAFERELEASE(pBoundaryList);
	
	return hr;
}
HRESULT CVWScale3DTool::ScaleSelectedObjects( float flDeltaX, float flDeltaY )
{
	CTranslate3DObject * pCTrans = NULL;
	IDirect3DRMFrame *pRMObjFrame = NULL;
	IDirect3DRMFrame *pRMParentFrame = NULL;
	IDirect3DRMFrame *pRMTmpFrame = NULL;
	D3DVECTOR axis;
	IVWFrame * pScene = NULL;
	BOOL bXAxisLocked, bYAxisLocked, bZAxisLocked;
	DWORD dwTimeNow;
	CComBSTR bstr1, bstr2, bstr3;
	CString tmpStr;
	static DWORD dwTime = - 1;
	HRESULT hr = S_OK;
	POSITION pos;
	CString szTmp;
	D3DVECTOR vecDelta, initialPos;
	IVector* vecPtr = NULL, *vecDestPtr = NULL;
	float fRot;
	float fX, fY, fZ, fTmp;

	D3DVECTOR vecCameraPos, vecObjToCam;

	if (IsPressed('S'))
	{
		flDeltaX *= SLOWKEY_SLOWFACTOR;
		flDeltaY *= SLOWKEY_SLOWFACTOR;
	}

	bXAxisLocked = m_nAxisLock & X_LOCK;
	bYAxisLocked = m_nAxisLock & Y_LOCK;
	bZAxisLocked = m_nAxisLock & Z_LOCK;

	if (m_nCameraMode == TOP)
	{
		flDeltaX /= 64.0f;
		flDeltaY /= 64.0f;
	}

	if (IsPressed('X'))
	{
		if (m_nCameraMode == TOP)
		{
			vecDelta.x = -flDeltaX / 4.0f; 
			vecDelta.y = 0.0f; 
			vecDelta.z = 0.0f;
		}
		else
		{
			vecDelta.x = -flDeltaX / 32.0f; 
			vecDelta.y = 0.0f; 
			vecDelta.z = 0.0f;
		}
	}
	else if (IsPressed('Y'))
	{
		if (m_nCameraMode == TOP)
		{
			vecDelta.x = 0.0; 
			vecDelta.y = 0.0f; 
			vecDelta.z = flDeltaY / 4.0f;
		}
		else
		{
			vecDelta.x = 0.0; 
			vecDelta.y = flDeltaY / 32.0f; 
			vecDelta.z = 0.0f;
		}
	}
	else if (IsPressed('Z'))
	{
		if (m_nCameraMode == TOP)
		{ 
			vecDelta.x = 0.0; 
			vecDelta.y = flDeltaY / 4.0f; 
			vecDelta.z = 0.0f;
		}
		else
		{
			vecDelta.x = 0.0; 
			vecDelta.y = 0.0f; 
			vecDelta.z = flDeltaY / 32.0f;
		}
	}
	else
	{
		if (m_nCameraMode == TOP)
		{
			vecDelta.x = (bXAxisLocked ? 0.0f : -flDeltaX / 4.0f);
			vecDelta.y = 0.0f; 
			vecDelta.z = (bZAxisLocked ? 0.0f : flDeltaY / 4.0f);
		}
		else
		{
			vecDelta.x = (bXAxisLocked ? 0.0f : flDeltaX / 32.0f); 
			vecDelta.y = 0.0f;
			vecDelta.z = (bZAxisLocked ? 0.0f : flDeltaY / 32.0f);  //0.0f; //(bZAxisLocked ? 0.0f : flDeltaX / 32.0f);
		}
	}
	
	hr = m_pRMCameraFrame->GetPosition(NULL, &vecCameraPos);
	if (FAILED(hr)) goto EXIT_FAIL;

	hr = CoCreateInstance(CLSID_Vector, NULL, CLSCTX_INPROC_SERVER, IID_IVector, (LPVOID*)&vecPtr);
	if (FAILED(hr)) goto EXIT_FAIL;

	hr = CoCreateInstance(CLSID_Vector, NULL, CLSCTX_INPROC_SERVER, IID_IVector, (LPVOID*)&vecDestPtr);
	if (FAILED(hr)) goto EXIT_FAIL;
	
	for( pos = m_TransformList.GetHeadPosition(); pos != NULL; )
	{
		pCTrans = m_TransformList.GetNext( pos );
		if(pCTrans != NULL && pCTrans->m_pTrans != NULL)
		{
			hr = pCTrans->m_pVWFrame->get_Frame3D(&pRMObjFrame);
			if (FAILED(hr) || (!pRMObjFrame)) goto EXIT_FAIL;

			hr = pRMObjFrame->GetParent(&pRMParentFrame);
			if (FAILED(hr) || (!pRMParentFrame)) goto EXIT_FAIL;

			pRMObjFrame->GetPosition(NULL, &initialPos);
			if (FAILED(hr)) goto EXIT_FAIL;

			if (!IsPressed(VK_SHIFT))
			{
				vecObjToCam.x = initialPos.x - vecCameraPos.x;
				vecObjToCam.y = 0.0f; //initialPos.y - vecCameraPos.y;
				vecObjToCam.z = initialPos.z - vecCameraPos.z;

				D3DRMVectorNormalize(&vecObjToCam);

				vecPtr->set(vecObjToCam.x, vecObjToCam.y, vecObjToCam.z);
				vecPtr->get_Rotation(&fRot);

				if (fRot >= 0.785 && fRot <= 2.355)
				{ //Camera is behind the object
				}
				else if (fRot >= 2.355 && fRot <= 3.925)
				{ //Camera is left of the object
					float fTmp;

					fTmp = vecDelta.x;
					vecDelta.x = vecDelta.z;
					vecDelta.z = fTmp;
				}
				else if (fRot >= 3.925 && fRot <= 5.495)
				{ //Camera is in front of the object
				}
				else
				{ //Camera is right of the object
					float fTmp;

					fTmp = vecDelta.x;
					vecDelta.x = vecDelta.z;
					vecDelta.z = fTmp;
				}

				ComputeEulerAngles(pCTrans->m_pVWFrame, vecDestPtr);
				vecDestPtr->get(&fX, &fY, &fZ);

				if (fX >= 0.785 && fX <= 2.355)
				{ //Camera is behind the object
					fTmp = vecDelta.z;
					vecDelta.z = vecDelta.y;
					vecDelta.y = fTmp;
				}
				else if (fX >= 2.355 && fX <= 3.925)
				{ //Camera is left of the object
				}
				else if (fX >= 3.925 && fX <= 5.495)
				{ //Camera is in front of the object
					fTmp = vecDelta.z;
					vecDelta.z = vecDelta.y;
					vecDelta.y = fTmp;
				}
				else
				{ //Camera is right of the object
				}

				if (fY >= 0.785 && fY <= 2.355) // && !(fX >= 2.355 && fX <= 3.925))
				{ //Camera is behind the object
					fTmp = vecDelta.x;
					vecDelta.x = vecDelta.z;
					vecDelta.z = fTmp;
				}
				else if (fY >= 2.355 && fY <= 3.925)
				{ //Camera is left of the object
				}
				else if (fY >= 3.925 && fY <= 5.495) // && !(fX >= 2.355 && fX <= 3.925) )
				{ //Camera is in front of the object
					fTmp = vecDelta.x;
					vecDelta.x = vecDelta.z;
					vecDelta.z = fTmp;
				}
				else
				{ //Camera is right of the object
				}
			}
			else
			{	//Shift it pressed
				vecDelta.y = vecDelta.x;
			}

			pRMObjFrame->SetPosition(NULL, 0.0f, 0.0f, 0.0f);
			if (FAILED(hr)) goto EXIT_FAIL;
		
			//Do a uniform (all axis) scaling
//				axis.x = 1.0f + (vecDelta.x > 0 ? vecDelta.x : vecDelta.z);
//				axis.y = 1.0f + (vecDelta.x > 0 ? vecDelta.x : vecDelta.z);
//				axis.z = 1.0f + (vecDelta.x > 0 ? vecDelta.x : vecDelta.z);
//			}
//			else //Normal perspective viewing
//			{
				axis.x = 1.0f + vecDelta.x;
				axis.y = 1.0f + vecDelta.y;
				axis.z = 1.0f + vecDelta.z;
//			}

			//Fix up current scale and fire UI event
			if (SIGN(pCTrans->currentLocation.x) == SIGN(axis.x) && axis.x != 0.0f)
			{
				fTmp = pCTrans->currentLocation.x;

				pCTrans->currentLocation.x *= axis.x;

				if (pCTrans->currentLocation.x < MIN_SCALE || pCTrans->currentLocation.x > MAX_SCALE)
				{
					pCTrans->currentLocation.x = fTmp;
					axis.x = 1.0f;
				}
			}
			else
				axis.x = 1.0f;

			if (SIGN(pCTrans->currentLocation.y) == SIGN(axis.y) && axis.y != 0.0f)
			{
				fTmp = pCTrans->currentLocation.y;

				pCTrans->currentLocation.y *= axis.y;

				if (pCTrans->currentLocation.y < MIN_SCALE || pCTrans->currentLocation.y > MAX_SCALE)
				{
					pCTrans->currentLocation.y = fTmp;
					axis.y = 1.0f;
				}
			}
			else
				axis.y = 1.0f;

			if (SIGN(pCTrans->currentLocation.z) == SIGN(axis.z) && axis.z != 0.0f)
			{
				fTmp = pCTrans->currentLocation.z;

				pCTrans->currentLocation.z *= axis.z;

				if (pCTrans->currentLocation.z < MIN_SCALE || pCTrans->currentLocation.z > MAX_SCALE)
				{
					pCTrans->currentLocation.z = fTmp;
					axis.z = 1.0f;
				}
			}
			else
				axis.z = 1.0f;

			hr = pRMObjFrame->AddScale(D3DRMCOMBINE_BEFORE, axis.x, axis.y, axis.z);
			if (FAILED(hr)) goto EXIT_FAIL;

			pRMObjFrame->SetPosition(NULL, initialPos.x, initialPos.y, initialPos.z);
			if (FAILED(hr)) goto EXIT_FAIL;

			dwTimeNow = GetTickCount();

			if (dwTimeNow - dwTime > 200)
			{
				tmpStr.Format("%0.3f", pCTrans->currentLocation.x);
				bstr1 = tmpStr;
				tmpStr.Format("%0.3f", pCTrans->currentLocation.y); 
				bstr2 = tmpStr;
				tmpStr.Format("%0.3f", pCTrans->currentLocation.z); 
				bstr3 = tmpStr;

				hr = InvokeToolEvent(TOOLEVENT_3DOBJECTSCALED, pCTrans->m_pThing, bstr1.m_str, bstr2.m_str, bstr3.m_str, VARIANT_TRUE);
				if(FAILED( hr )) goto EXIT_FAIL;

				dwTime = dwTimeNow;
			}

			SAFERELEASE(pRMObjFrame);
			SAFERELEASE(pRMParentFrame);
		}
	}

EXIT_FAIL:
	SAFERELEASE(pRMParentFrame);
	SAFERELEASE(pRMObjFrame);
	SAFERELEASE(pScene);
	SAFERELEASE(vecDestPtr);
	SAFERELEASE(vecPtr);
	
	return hr;
}