void Pick3DObjectExample::CreateWorldSpaceRayFromScreen(const Eegeo::v2& screenPoint, Ray& ray)
{
	const Eegeo::Camera::RenderCamera& renderCamera = m_cameraProvider.GetRenderCamera();

	//normalize the point
	double nx = 2.0 * screenPoint.GetX() / m_renderContext.GetScreenWidth() - 1;
	double ny = - 2.0 * screenPoint.GetY() / m_renderContext.GetScreenHeight() + 1;

	//prepare near and far points
	Eegeo::v4 near(nx, ny, 0.0f, 1.0);
	Eegeo::v4 far(nx, ny, 1.0f, 1.0);

	Eegeo::m44 invVP;
	Eegeo::m44::Inverse(invVP, renderCamera.GetViewProjectionMatrix());

	//unproject the points
	Eegeo::v4 unprojectedNear = Eegeo::v4::Mul(near, invVP);
	Eegeo::v4 unprojectedFar = Eegeo::v4::Mul(far, invVP);

	//convert to 3d
	Eegeo::v3 unprojectedNearWorld = unprojectedNear / unprojectedNear.GetW();
	Eegeo::v3 unprojectedFarWorld = unprojectedFar / unprojectedFar.GetW();

	//check intersection with a ray cast from camera position
	ray.m_origin = renderCamera.GetEcefLocation();
	ray.m_direction = (unprojectedNearWorld - unprojectedFarWorld).Norm();
}
            void WorldPinsScaleController::UpdateWorldPin(WorldPinItemModel& worldPinItemModel,
                    float deltaSeconds,
                    const Eegeo::Camera::RenderCamera& renderCamera)
            {
                const bool showingInterior = m_interiorsController.ShowingInterior();
                bool shouldHideInteirorPin = worldPinItemModel.IsInterior();
                if( showingInterior == false)
                {
                    shouldHideInteirorPin = shouldHideInteirorPin && !worldPinItemModel.GetInteriorData().showInExterior;
                }
                else
                {
                    shouldHideInteirorPin = shouldHideInteirorPin && (worldPinItemModel.GetInteriorData().floor != m_interiorsController.GetCurrentFloorIndex());
                }
                
                Eegeo::v2 screenLocation;
                GetScreenLocation(worldPinItemModel, screenLocation, renderCamera);

                const float ratioX = screenLocation.GetX() / renderCamera.GetViewportWidth();
                const float ratioY = screenLocation.GetY() / renderCamera.GetViewportHeight();
                const bool shouldHide = (ratioX < 0.1f) || (ratioX > 0.9f) || (ratioY < 0.15f) || (ratioY > 0.9f) || shouldHideInteirorPin;

                if(shouldHide)
                {
                    worldPinItemModel.Hide();
                }
                else
                {
                    worldPinItemModel.Show();
                }

                worldPinItemModel.Update(deltaSeconds);
            }
    void PinsWithAttachedJavaUIExample::Draw()
    {
    	//lazily create the pin button when we start drawing so it is not displayed on top of the loading screen
		if(m_world.Initialising()) {
			return;
		}
		else if(m_buttonID == 0) {
			CreateJavaUIButton();
		}

		AndroidSafeNativeThreadAttachment attached(m_nativeState);
		JNIEnv* env = attached.envForThread;

		Eegeo_ASSERT(m_buttonID != 0);

		// Get the pin position on the screen
		Eegeo::Pins::PinRepository& pinRepo = m_pPinsModule->GetRepository();
		Eegeo::Pins::Pin* pPin = pinRepo.GetPinAtIndex(0);
		Eegeo_ASSERT(pPin != NULL);

		Eegeo::Pins::PinController& pinController = m_pPinsModule->GetController();
		Eegeo::Geometry::Bounds2D pinScreenBounds = Eegeo::Geometry::Bounds2D::Empty();
		pinController.GetScreenBoundsForPin(*pPin, pinScreenBounds);
		Eegeo::v2 screenPosition = pinScreenBounds.center();

		// now update the java ui to be in sync with the pin, positioned above it on screen.
		// the pixel nudging is hard-coded for simplicity; you should probably do something more sophisticated
		// (based on the size of your pin & java ui assets)
		const int buttonOffsetPixelsX = 40;
		const int buttonOffsetPixelsY = 110;

		env->CallVoidMethod(
			m_hudPinController,
			m_updateLocationMethodId,
			m_buttonID,
			screenPosition.GetX() - buttonOffsetPixelsX,
			screenPosition.GetY() - buttonOffsetPixelsY
		);
    }
    bool PinsWithAttachedJavaUIExample::Event_TouchTap(const AppInterface::TapData& data)
    {
        Eegeo::v2 screenTapPoint = Eegeo::v2(data.point.GetX(), data.point.GetY());

        Eegeo_TTY("Searching for Pins intersecting tap point %d,%d...", (int) screenTapPoint.GetX(), (int) screenTapPoint.GetY());

        Eegeo::Pins::PinController& pinController = m_pPinsModule->GetController();
        std::vector<Eegeo::Pins::Pin*> intersectingPinsClosestToCameraFirst;
        if(pinController.TryGetPinsIntersectingScreenPoint(screenTapPoint, intersectingPinsClosestToCameraFirst))
        {
            Eegeo_TTY("found %ld :\n", intersectingPinsClosestToCameraFirst.size());

            for(std::vector<Eegeo::Pins::Pin*>::const_iterator it = intersectingPinsClosestToCameraFirst.begin(); it != intersectingPinsClosestToCameraFirst.end(); ++it)
            {
                Eegeo::Pins::Pin* pPin = *it;

                Eegeo_TTY("\tId=%d, User Data='%s'\n", pPin->GetId(), ((std::string*) pPin->GetUserData())->c_str());
            }

            return true;
        }
        else
        {
            Eegeo_TTY("none found.\n");
            return false;
        }
    }
 bool WorldMenuItemView::IsCollidingWithPoint(const Eegeo::v2& screenPoint, Eegeo::UI::IUICameraProvider& cameraProvider)
 {
     
     if(!m_pSprite->GetItemShouldRender())
         return false;
     
     Eegeo::Camera::RenderCamera& renderCamera = cameraProvider.GetRenderCameraForUI();
     if (renderCamera.GetEcefLocation().SquareDistanceTo(m_pSprite->GetEcefPosition()) < (GetItemRadius() * GetItemRadius()))
     {
         return false;
     }
     
     Eegeo::dv3 rayOrigin = renderCamera.GetEcefLocation();
     Eegeo::dv3 rayDirection;
     
     Eegeo::Camera::CameraHelpers::GetScreenPickRay(renderCamera, screenPoint.GetX(), screenPoint.GetY(), rayDirection);
     return Eegeo::Geometry::IntersectionTests::TestRaySphere(rayOrigin, rayDirection, m_pSprite->GetEcefPosition(), GetItemRadius());
 }