Example #1
0
void Listener::onFrame(const Leap::Controller &controller) {
    Leap::Frame curFrame = controller.frame();
    if (firstFrameLeap == 0 && ++frameCount > 10) {
        gettimeofday(&firstFrameAbs, NULL);
        firstFrameLeap = curFrame.timestamp();
        cout << "First frame clock time: " << tv_to_usec(firstFrameAbs) << endl;
        cout << "First frame leap time: " << firstFrameLeap << endl;
    }
    
    // use current active gesture recognizers to locate gestures
    // and then trigger appropriate note/controls
    // feed frames to recognizers
    vector<GesturePtr> recognizers = gestureRecognizers();
    for (vector<GesturePtr>::iterator it = recognizers.begin(); it != recognizers.end(); ++it) {
        // get controls recognized from gestures
        GesturePtr gesture = *it;
        std::vector<ControlPtr> gestureControls; // controls from this gesture
        gesture->recognizedControls(controller, gestureControls);
        
        if (! gestureControls.size())
            continue;
        
        // call gesture recognized callback
        onGestureRecognized(controller, gesture);
        
        for (vector<ControlPtr>::iterator ctl = gestureControls.begin(); ctl != gestureControls.end(); ++ctl) {
            ControlPtr control = *ctl;
            
            onControlUpdated(controller, gesture, control);
        }
    }
}
Example #2
0
void Quickstart::onFrame(const Leap::Controller &controller) {
    // returns the most recent frame. older frames can be accessed by passing in 
    // a "history" parameter to retrieve an older frame, up to about 60
    // (exact number subject to change)
    const Leap::Frame frame = controller.frame();

    // do nothing unless hands are detected
    if (frame.hands().empty())
        return;
    
    // first detected hand
    const Leap::Hand firstHand = frame.hands()[0];
    // first pointable object (finger or tool)
    const Leap::PointableList pointables = firstHand.pointables();
    if (pointables.empty()) return;
    const Leap::Pointable firstPointable = pointables[0];
    
    // print velocity on the X axis
    cout << "Pointable X velocity: " << firstPointable.tipVelocity()[0] << endl;
    
    const Leap::FingerList fingers = firstHand.fingers();
    if (fingers.empty()) return;
    
    for (int i = 0; i < fingers.count(); i++) {
        const Leap::Finger finger = fingers[i];
        
        std::cout << "Detected finger " << i << " at position (" <<
            finger.tipPosition().x << ", " <<
            finger.tipPosition().y << ", " <<
            finger.tipPosition().z << ")" << std::endl;
    }
}
Example #3
0
void Listener::onControlUpdated(const Leap::Controller &controller, GesturePtr gesture, ControlPtr control) {
    midi_control_index ctrlIdx = control->controlIndex();
    midi_control_value ctrlVal = control->mappedValue();
//    
//    cout << "Recognized control index " << ctrlIdx
//         << " (" << control->description() << ")"
//         << ", raw value: "
//         << control->rawValue() << " mapped value: " << ctrlVal << endl;
    
    if (frameCount <= 10) return;
    
    // control latency
    struct timeval tv;
    gettimeofday(&tv, NULL);
    double elapsedTime = (tv.tv_sec - control->timestamp().tv_sec) * 1000.0;      // sec to ms
    elapsedTime += (tv.tv_usec - control->timestamp().tv_usec) / 1000.0;   // us to ms
    
    // frame latency
    double absoluteTimeOffset = tv_to_usec(tv) - tv_to_usec(firstFrameAbs);
//    cout << "absolute time offset: " << absoluteTimeOffset << endl;
    int64_t curFrameTime = controller.frame().timestamp();
    int64_t frameOffset = curFrameTime - firstFrameLeap;
    int64_t frameLatency = absoluteTimeOffset - frameOffset;
//    cout << "frame: " << curFrameTime << ", absolute offset: " << (absoluteTimeOffset / 1000) << ", frameOffset: " << (frameOffset / 1000) << ", diff: " << (frameLatency / 1000) << endl;
    
    if (minLatency == 0 || frameLatency < minLatency)
        minLatency = frameLatency;
    if (frameLatency > maxLatency)
        maxLatency = frameLatency;
    controlCount++;
    totalLatency += frameLatency;
    
    if (elapsedTime > 3)
        cout << "frame latency: " << (frameLatency / 1000) << ", control output latency: " << elapsedTime << endl;
}
void LeapFishyApp::processGesture()
{
	Leap::Frame frame = m_LeapController.frame();

	if( m_LastFrame == frame )
		return;

	Leap::GestureList gestures =	m_LastFrame.isValid()			?
									frame.gestures( m_LastFrame )	:
									frame.gestures();

	m_LastFrame = frame;

	for( int i = 0; i < gestures.count(); i++ )
	{
		if( gestures[i].type() == Leap::Gesture::TYPE_SWIPE )
		{
			Leap::SwipeGesture swipe = gestures[i];
			Leap::Vector diff = 0.006f*(swipe.position() - swipe.startPosition());
			Vec2f curSwipe(diff.x, -diff.y);
			m_pPlayer->AddVelocity( curSwipe );
		}
		else if(	gestures[i].type() == Leap::Gesture::TYPE_KEY_TAP || 
					gestures[i].type() == Leap::Gesture::TYPE_SCREEN_TAP )
		{
			m_pPlayer->KillVelocity();
		}
	}
}
Example #5
0
void MouseController::onFrame(const Leap::Controller &controller) {
    // get list of detected screens
    const Leap::ScreenList screens = controller.calibratedScreens();
    
    // make sure we have a detected screen
    if (screens.empty()) return;
    const Leap::Screen screen = screens[0];
    
    // find the first finger or tool
    const Leap::Frame frame = controller.frame();
    const Leap::HandList hands = frame.hands();
    if (hands.empty()) return;
    const Leap::PointableList pointables = hands[0].pointables();
    if (pointables.empty()) return;
    const Leap::Pointable firstPointable = pointables[0];
    
    // get x, y coordinates on the first screen
    const Leap::Vector intersection = screen.intersect(
                                                       firstPointable,
                                                       true,  // normalize
                                                       1.0f   // clampRatio
                                                       );
    
    // if the user is not pointing at the screen all components of
    // the returned vector will be Not A Number (NaN)
    // isValid() returns true only if all components are finite
    if (! intersection.isValid()) return;
    
    unsigned int x = screen.widthPixels() * intersection.x;
    // flip y coordinate to standard top-left origin
    unsigned int y = screen.heightPixels() * (1.0f - intersection.y);
    
    CGPoint destPoint = CGPointMake(x, y);
    CGDisplayMoveCursorToPoint(kCGDirectMainDisplay, destPoint);
}
void LeapMotionListener::onFrame( const Leap::Controller& controller )
{
	// get least frame
	frame = controller.frame( 0 );
	

}
void Listener::onFrame( const Leap::Controller& controller ) 
{
	lock_guard<mutex> lock( *mMutex );
	if ( !mNewFrame ) {
		mFrame		= controller.frame();
		mNewFrame	= true;
	}
}
fdata get_finger_positions()
{
    Leap::Frame frame = control.frame();
    Leap::FingerList fingers = frame.fingers();
    Leap::ToolList tools = frame.tools();
    Leap::HandList hands = frame.hands();

    //std::vector<std::pair<cl_float4, int>> positions;

    fdata hand_data;


    int p = 0;

    for(int i=0; i<40; i++)
    {
        hand_data.fingers[i] = 0.0f;
    }

    ///will explode if more than 2
    for(int i=0; i<hands.count(); i++)
    {
        const Leap::Hand hand = hands[i];
        Leap::FingerList h_fingers = hand.fingers();

        float grab_strength = hand.grabStrength();

        hand_data.grab_confidence[i] = grab_strength;

        for(int j=0; j<h_fingers.count(); j++)
        {
            const Leap::Finger finger = h_fingers[j];

            float mfingerposx = finger.tipPosition().x;
            float mfingerposy = finger.tipPosition().y;
            float mfingerposz = finger.tipPosition().z;

            //cl_float4 ps = {mfingerposx, mfingerposy, mfingerposz, 0.0f};
            //cl_float4 ps = {mfingerposx, mfingerposy, mfingerposz, 0.0f};

            int id = finger.id();

            hand_data.fingers[p++] = mfingerposx;
            hand_data.fingers[p++] = mfingerposy;
            hand_data.fingers[p++] = mfingerposz;
            hand_data.fingers[p++] = 0.0f;

            //positions.push_back(std::pair<cl_float4, int>(ps, id));

        }
    }

    return hand_data;
}
void LeapCinderRainApp::processFingers()
{
	Leap::Frame frame = m_LeapController.frame();
	Leap::FingerList fingers = frame.fingers();

	m_Rain->ClearPointTo();

	for( int i = 0; i < fingers.count(); i++ )
	{
		m_Rain->CheckPointTo( normalizeCoords( fingers[i].tipPosition() ), 40.0f );
	}
}
// This is called every SL viewer frame
void LLLMImpl::stepFrame()
{
	if (mLMController
		&& mFrameAvailable
		&& mLMConnected)
	{
		mFrameAvailable = false;

		// Get the most recent frame and report some basic information
		const Leap::Frame frame = mLMController->frame();
		Leap::HandList hands = frame.hands();
		
		static LLCachedControl<S32> sControllerMode(gSavedSettings, "LeapMotionTestMode", 0);

		if( !mTool || mTool->getId() != sControllerMode )
		{
			delete mTool;
			mTool = nd::leap::constructTool( sControllerMode );
		}

		if( mTool )
			mTool->onRenderFrame( frame );
		else
		{
			switch (sControllerMode)
			{
				case 1:
					modeFlyingControlTest(hands);
					break;
				case 2:
					modeStreamDataToSL(hands);
					break;
				case 3:
					modeGestureDetection1(hands);
					break;
				case 4:
					modeMoveAndCamTest1(hands);
					break;
				// <FS:Zi> Leap Motion flycam
				case 10:
					modeFlycam(hands);
					break;
				// </FS:Zi>
				case 411:
					modeDumpDebugInfo(hands);
					break;
				default:
					// Do nothing
					break;
			}
		}
	}
}
Example #11
0
void eleap::eleap_t::impl_t::onFrame(const Leap::Controller& controller)
{
    const Leap::Frame frame = controller.frame();
    if (frame.isValid())
    {
        // send the known hands in this frame, this will handle hands coming and going
        const Leap::HandList hands = frame.hands();
        {
            unsigned long long time_encoded = (0&0xffffffff)<<8 | (DATA_KNOWN_HANDS&0xff);

            float *f;
            unsigned char *dp;
            piw::data_nb_t d = ctx_.allocate_host(time_encoded,INT32_MAX,INT32_MIN,0,BCTVTYPE_INT,sizeof(int32_t),&dp,hands.count(),&f);
            memset(f,0,hands.count()*sizeof(int32_t));
            *dp = 0;

            for(int i = 0; i < hands.count(); ++i)
            {
                const Leap::Hand hand = hands[i];
                if(hand.isValid() && hand.fingers().count() > 1)
                {
                    ((int32_t *)f)[i] = hand.id();
                }
            }
            enqueue_fast(d,1);
        }
        
        // handle the actual data for the detected hands
        for(int i = 0; i < hands.count(); ++i)
        {
            const Leap::Hand hand = hands[i];
            if(hand.isValid() && hand.fingers().count() > 1)
            {
                unsigned long long time_encoded = (hand.id()&0xffffffff)<<8 | (DATA_PALM_POSITION&0xff);

                const Leap::Vector palm_pos = hand.palmPosition();

                float *f;
                unsigned char *dp;
                piw::data_nb_t d = ctx_.allocate_host(time_encoded,600,-600,0,BCTVTYPE_FLOAT,sizeof(float),&dp,3,&f);
                memset(f,0,3*sizeof(float));
                *dp = 0;

                f[0] = piw::normalise(600,-600,0,palm_pos.x);
                f[1] = piw::normalise(600,-600,0,palm_pos.y);
                f[2] = piw::normalise(600,-600,0,palm_pos.z);

                enqueue_fast(d,1);
            }
        }
    }
}
    virtual void onFrame        (const Leap::Controller&)
    {
        const Leap::Frame frame(m_Controller.frame(0));
        const Leap::Hand hand(frame.hands().rightmost());
        if (!hand.isValid())
        {
            m_LastNormalizedPos.reset();
            return;
        }

        const Leap::Vector pos(hand.palmPosition());
        m_LastNormalizedPos = frame.interactionBox().normalizePoint(pos);
    }
void LeapSample03App::draw()
{
    gl::clear( Color( .97, .93, .79 ) );
    Leap::PointableList pointables = leap.frame().pointables();
    Leap::InteractionBox iBox = leap.frame().interactionBox();

    for ( int p = 0; p < pointables.count(); p++ ) {
        Leap::Pointable pointable = pointables[p];
#if 1
        // ここから追加
        // 伸びている指、ツール以外は無視する
        if ( !pointable.isExtended() ) {
            continue;
        }
        // ここまで追加
#endif

        Leap::Vector normalizedPosition =
            iBox.normalizePoint( pointable.stabilizedTipPosition() );
        float x = normalizedPosition.x * windowWidth;
        float y = windowHeight - normalizedPosition.y * windowHeight;

        // ホバー状態
        if ( (pointable.touchDistance() > 0) &&
            (pointable.touchZone() != Leap::Pointable::Zone::ZONE_NONE) ) {
            gl::color(0, 1, 0, 1 - pointable.touchDistance());
        }
        // タッチ状態
        else if ( pointable.touchDistance() <= 0 ) {
            gl::color(1, 0, 0, -pointable.touchDistance());
        }
        // タッチ対象外
        else {
            gl::color(0, 0, 1, .05);
        }

        gl::drawSolidCircle( Vec2f( x, y ), 40 );
    }
}
void LeapMotionListener::onFrame( const Leap::Controller& controller )
{
	// get least frame
	frame = controller.frame( 0 );

	// get fingerList
	Leap::FingerList fingerList = frame.hand.fingers();

	// copy
	Leap::Finger *leapFinger = &fingerList[ 0 ];
	Finger *finger = ( Finger * )leapFinger;

}
int StateKen::eventShake(StateContext& context, const Leap::Controller& controller)
{
    std::cout << "けん\n" << std::endl;
    
    const Leap::Frame frame = controller.frame();
    const Leap::Hand hand = frame.hands()[0];
    
    Leap::Vector position = hand.palmPosition();
    
    JankenApp::getInstance()->setShakeStartPosition(position);
    
    int ret = context.changeState(StatePon::getInstance());
    
    return ret;
}
 virtual void onFrame(const Leap::Controller& controller) {
     Leap::Frame frame = controller.frame();
     const Leap::HandList& hands = frame.hands();
     if (hands.count() > 0) {
         Leap::Vector newTarget = hands[0].stabilizedPalmPosition();
         cout << "New Target: " << newTarget << endl;
         if (inMotion) {
             //TODO: must merge with currentTarget, to account for if the
             //target hand moved...for now, do nothing
         } else {
             inMotion = true;
             currentTarget = WorldVector(newTarget, leapPos);
         }
     }
 }
//Handle Leap Gesture processing.
//Trigger the corresponding effects in the particle field.
void GesturesDemo::processGestures() {
  Leap::Frame frame = controller.frame();

  if ( lastFrame == frame ) {
    return;
  }

  Leap::GestureList gestures =  lastFrame.isValid()       ?
                                frame.gestures(lastFrame) :
                                frame.gestures();

  lastFrame = frame;

  size_t numGestures = gestures.count();

  for (size_t i=0; i < numGestures; i++) {
    if (gestures[i].type() == Leap::Gesture::TYPE_SCREEN_TAP) {
      printf("screen screen tap gesture");
      Leap::ScreenTapGesture tap = gestures[i];
      ci::Vec3f tapLoc = normalizeCoords(tap.position());
      field.Repel(tap.id(), ci::Vec2f(tapLoc.x, tapLoc.y), 3.0);
    } else if (gestures[i].type() == Leap::Gesture::TYPE_KEY_TAP) {
      printf("screen key tap gesture");
      Leap::KeyTapGesture tap = gestures[i];
      ci::Vec3f tapLoc = normalizeCoords(tap.position());
      field.Repel(tap.id(), ci::Vec2f(tapLoc.x, tapLoc.y), -3.0);
    } else if (gestures[i].type() == Leap::Gesture::TYPE_SWIPE) {
      printf(" swipe  gesture");
      Leap::SwipeGesture swipe = gestures[i];
      Leap::Vector diff = 0.004f*(swipe.position() - swipe.startPosition());
      ci::Vec3f curSwipe(diff.x, -diff.y, diff.z);
      field.Translate(swipe.id(), curSwipe);
    } else if (gestures[i].type() == Leap::Gesture::TYPE_CIRCLE) {
      printf(" circle gesture");
      Leap::CircleGesture circle = gestures[i];
      float progress = circle.progress();
      if (progress >= 1.0f) {
        ci::Vec3f center = normalizeCoords(circle.center());
        ci::Vec3f normal(circle.normal().x, circle.normal().y, circle.normal().z);
        double curAngle = 6.5;
        if (normal.z < 0) {
          curAngle *= -1;
        }
        field.Rotate(circle.id(), ci::Vec2f(center.x, center.y), circle.radius()/250, curAngle);
      }
    }
  }
}
// Callback from Leapmotion code when a new frame is available.  It simply
// sets a flag so stepFrame() can pick up new controller data
void LLLMImpl::onFrame(const Leap::Controller& controller) 
{
	if (mLMConnected)
	{
		// Get the most recent frame and report some basic information
		const Leap::Frame frame = controller.frame();
		int64_t frame_id = frame.id();
		if (frame_id != mCurrentFrameID)
		{	// Just record the ID and set flag indicating data is available
			mCurrentFrameID = frame_id;
			mFrameAvailable = true;
		}

		if( mTool )
			mTool->onLeapFrame( frame);
	}
}
Example #19
0
 void onFrame(const Leap::Controller& ctrl) override
 {
     if(ctrl.isConnected())
     {
         Leap::GestureList gestures = ctrl.frame().gestures();
         /*
         if(gestures.count())
         {
             Gesture gesture = gestures[0];
             if(gestures[0].isValid())
             {
                 if(gestures[0].type() == Gesture::TYPE_CIRCLE)
                 {
                     ScreenTapGesture screentap = gestures[0];
                     t_atom data[4];
                     Leap::Vector vector = screentap.direction();
                     atom_setsym(data, gensym("direction"));
                     atom_setfloat(data+1, vector.yaw());
                     atom_setfloat(data+1, vector.roll());
                     atom_setfloat(data+1, vector.pitch());
                     outlet_anything(x->f_gesture, leap_sym_circle, 0, NULL);
                 }
                 else if(gesture.type() == Gesture::TYPE_SWIPE)
                 {
                     ;
                 }
                 else if(gesture.type() == Gesture::TYPE_KEY_TAP)
                 {
                     ;
                 }
                 else if(gesture.type() == Gesture::TYPE_SCREEN_TAP)
                 {
                     ;
                 }
                 else
                 {
                     ;
                 }
             }
         }*/
     }
 }
Example #20
0
void Quickstart::onFrame(const Leap::Controller &controller) {
    // returns the most recent frame. older frames can be accessed by passing in 
    // a "history" parameter to retrieve an older frame, up to about 60
    // (exact number subject to change)
    const Leap::Frame frame = controller.frame();

    // do nothing unless hands are detected
    if (frame.hands().empty())
        return;
    
    // retrieve first pointable object (finger or tool)
    // from the frame
    const Leap::PointableList pointables = frame.hands()[0].pointables();
    if (pointables.empty())
        return;
    const Leap::Pointable firstPointable = pointables[0];
    
    // print velocity on the X axis
    cout << "Pointable X velocity: " << firstPointable.tipVelocity()[0] << endl;
}
void Listener::onFrame( const Leap::Controller& controller ) 
{
	lock_guard<mutex> lock( *mMutex );
	if ( !mNewFrame ) {
		const Leap::Frame& controllerFrame	= controller.frame();
		const Leap::HandList& hands			= controllerFrame.hands();
		
		HandMap handMap;
		for ( const Leap::Hand& hand : hands ) {
			FingerMap fingerMap;
			ToolMap toolMap;
			const Leap::PointableList& pointables = hand.pointables();
			for ( const Leap::Pointable& pt : pointables ) {
				if ( pt.isValid() ) {
					Pointable pointable( pt );
					if ( pt.isFinger() ) {
						fingerMap[ pt.id() ] = Finger( pointable );
					} else if ( pt.isTool() ) {
						toolMap[ pt.id() ] = Tool( pointable );
					}
				}
			}
			
			float rotAngle			= (float)hand.rotationAngle( mFirstFrame.mFrame );
			Vec3f rotAxis			= toVec3f( hand.rotationAxis( mFirstFrame.mFrame ) );
			Matrix44f rotMatrix		= toMatrix44f( hand.rotationMatrix( mFirstFrame.mFrame ) );
			float scale				= (float)hand.scaleFactor( mFirstFrame.mFrame );
			Vec3f translation		= toVec3f( hand.translation( mFirstFrame.mFrame ) );
			
			handMap[ hand.id() ]	= Hand( hand, fingerMap, toolMap, rotAngle, rotAxis,
										   rotMatrix, scale, translation );
		}

		mFrame		= Frame( controllerFrame, handMap );
		if ( !mFirstFrameReceived ) {
			mFirstFrame			= Frame( controllerFrame, handMap );
			mFirstFrameReceived	= true;
		}
		mNewFrame	= true;
	}
}
Example #22
0
void BallGesture::recognizedControls(const Leap::Controller &controller, std::vector<ControlPtr> &controls) {
    Leap::Frame frame = controller.frame();
    
    // hands detected?
    if (frame.hands().isEmpty())
        return;
                
    for (int i = 0; i < frame.hands().count(); i++) {
        // gonna assume the user only has two hands. sometimes leap thinks otherwise.
        if (i > 1) break;
        
        Leap::Hand hand = frame.hands()[i];
        double radius = hand.sphereRadius(); // in mm

        if (! radius)
            continue;
                
        BallRadiusPtr bc = make_shared<BallRadius>(radius, i);
        ControlPtr cptr = dynamic_pointer_cast<Control>(bc);
        
        controls.push_back(cptr);
    }
}
void LMRecorder::onFrame(const Leap::Controller& c) {
	ScopedLock frameLock(frameMutex);
	ScopedLock closingLock(closingMutex);
	if (currentFrame !=NULL) {
		delete currentFrame;
		currentFrame = NULL;
	}
	currentFrame = new GestureFrame();
	
	clock_gettime(CLOCK_REALTIME, &t2);
	timestamp = (double)(t2.tv_sec - t1.tv_sec) + 1.e-9*(t2.tv_nsec - t1.tv_nsec);
	timestamp *= 1000;
	
	prepareData(c.frame(), currentFrame, timestamp);
	
	gestureStorageDriver->saveGestureFrame(*currentFrame);

	printf("F: %d T: %dms FPS: %.2f FPS_AVG: %.2f\n", count, (int)(timestamp), 1000.0/(timestamp-lastTime), 1000*count/timestamp);

	lastTime = timestamp;
	count++;

	notifyListeners();
}
void LeapMotionListener::onFrame(const Leap::Controller & controller)
{
    const Leap::Frame frame = controller.frame();

    Leap::HandList hands = frame.hands();
    for (Leap::HandList::const_iterator hl = hands.begin(); hl!=hands.end();hl++)
    {
        const Leap::Hand hand = *hl;
        QString handType = hand.isLeft() ? "Left hand" : "Right hand";
        qDebug()<<handType<<"id: "<<hand.id()<<"palm position: "
               <<hand.palmPosition().x<<hand.palmPosition().y<<hand.palmPosition().z;

        QFile f("share.dat");
        if(!f.open(QIODevice::WriteOnly | QIODevice::Text))
            return;
        QTextStream out(&f);
        out<<QString("%1 %2 %3").arg(hand.palmPosition().x)
          .arg(hand.palmPosition().y).arg(hand.palmPosition().z);

        f.close();

    }

}
Example #25
0
void ZirkLeap::onFrame(const Leap::Controller& controller) {
    if(controller.hasFocus()) {
        Leap::Frame frame = controller.frame();
        if (mPointableId >= 0) {
            ourProcessor->setSelectedSource(mEditor->getCBSelectedSource()-1);
            Leap::Pointable p = frame.pointable(mPointableId);
            if (!p.isValid() || !p.isExtended()) {
                mPointableId = -1;
                mLastPositionValid = false;
            } else {
                Leap::Vector pos = p.tipPosition();
                const float zPlane1 = 50;	// 5 cm
                const float zPlane2 = 100;	// 10 cm
                
                if (pos.z < zPlane2) {
                    if (mLastPositionValid) {
                        //Leap Motion mouvement are calculated from the last position in order to have something dynamic and ergonomic
                        Leap::Vector delta = pos- mLastPosition;
                        
                        float scale = 3;
                        if (pos.z > zPlane1) {
                            float s = 1 - (pos.z - zPlane1) / (zPlane2 - zPlane1);
                            scale *= s;
                            
                        }
                        
                        int src = ourProcessor->getSelectedSource();
                        float fX, fY;
                        ourProcessor->getSources()[src].getXY(fX, fY);
                        fX += delta.x * scale;
                        fY -= delta.y * scale;
                        
                        //clamp coordinates to circle
                        float fCurR = hypotf(fX, fY);
                        if ( fCurR > ZirkOscAudioProcessor::s_iDomeRadius){
                            float fExtraRatio = ZirkOscAudioProcessor::s_iDomeRadius / fCurR;
                            fX *= fExtraRatio;
                            fY *= fExtraRatio;
                        }
                        
                        mEditor->move(src, fX, fY);
                    } else {
                        //std::cout << "pointable last pos not valid" << std::endl;
                    }
                    mLastPosition = pos;
                    mLastPositionValid = true;
                } else {
                    //std::cout << "pointable not touching plane" << std::endl;
                    mLastPositionValid = false;
                }
            }
        }
        if (mPointableId < 0) {
            Leap::PointableList pl = frame.pointables().extended();
            if (pl.count() > 0) {
                mPointableId = pl[0].id();
                //std::cout << "got new pointable: " << mPointableId << std::endl;
            }
        }
    }
}
Example #26
0
void jester::LeapFrameListener::onFrame(const Leap::Controller &controller) {
	kLeapWrapper->processLeapFrame(controller.frame());
}
Example #27
0
int main()
{
	Leap::Controller controller;
	Leap::Frame frame;
	Leap::HandList hands;
	Leap::Hand h1;
	Leap::FingerList fingers;
	Leap::Finger index;
	Leap::Finger thumb;
	Leap::PointableList pointables;
	float indexX = 0, indexY = 0, indexZ = 0, thumbX = 0, thumbY = 0, thumbZ = 0, sum = 0, supersample[20];

	int i = 0;

	// Setup serial port connection and needed variables.
	HANDLE hSerial = CreateFile(L"COM6", GENERIC_WRITE | GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);

	if (hSerial != INVALID_HANDLE_VALUE)
	{
		printf("Port opened! \n");

		DCB dcbSerialParams;
		GetCommState(hSerial, &dcbSerialParams);

		dcbSerialParams.BaudRate = CBR_14400;
		dcbSerialParams.ByteSize = 8;
		dcbSerialParams.Parity = NOPARITY;
		dcbSerialParams.StopBits = ONESTOPBIT;

		SetCommState(hSerial, &dcbSerialParams);

		Sleep(1000);
	}

	else
	{
		if (GetLastError() == ERROR_FILE_NOT_FOUND)
		{
			printf("Serial port doesn't exist! \n");
		}

		printf("Error while setting up serial port! \n");
	}

	Controller[20].value = 9;	//Verification Byte sent to make sure everything else ends up in the right location
	FillByteSize();

	while (true)
	{
		UpdateControllerState();	//Updates all values on the controller
		WORD wButtons = g_Controllers[CONTROLLER1].state.Gamepad.wButtons;

		//Stores all of the values from the controller into the controller structure
		Controller[0].value = g_Controllers[CONTROLLER1].state.Gamepad.sThumbRX;
		Controller[1].value = g_Controllers[CONTROLLER1].state.Gamepad.sThumbRY;
		Controller[2].value = g_Controllers[CONTROLLER1].state.Gamepad.sThumbLX;
		Controller[3].value = g_Controllers[CONTROLLER1].state.Gamepad.sThumbLY;
		Controller[4].value = (g_Controllers[CONTROLLER1].state.Gamepad.bRightTrigger);
		Controller[5].value = (g_Controllers[CONTROLLER1].state.Gamepad.bLeftTrigger);
		Controller[6].value = (wButtons & XINPUT_GAMEPAD_RIGHT_THUMB);
		Controller[7].value = (wButtons & XINPUT_GAMEPAD_LEFT_THUMB);
		Controller[8].value = (wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER);
		Controller[9].value = (wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER);
		Controller[10].value = (wButtons & XINPUT_GAMEPAD_DPAD_UP);
		Controller[11].value = (wButtons & XINPUT_GAMEPAD_DPAD_DOWN);
		Controller[12].value = (wButtons & XINPUT_GAMEPAD_DPAD_LEFT);
		Controller[13].value = (wButtons & XINPUT_GAMEPAD_DPAD_RIGHT);
		Controller[14].value = (wButtons & XINPUT_GAMEPAD_A);
		Controller[15].value = (wButtons & XINPUT_GAMEPAD_B);
		Controller[16].value = (wButtons & XINPUT_GAMEPAD_Y);
		Controller[17].value = (wButtons & XINPUT_GAMEPAD_X);
		Controller[18].value = (wButtons & XINPUT_GAMEPAD_START);
		Controller[19].value = (wButtons & XINPUT_GAMEPAD_BACK);

		CheckDeadZone();

		if (controller.isConnected() == true)
		{
			sum = 0;
			frame = controller.frame();
			hands = frame.hands();
			h1 = hands[0];
			fingers = frame.fingers();
			thumb = fingers[0];
			index = fingers[1];
			pointables = frame.pointables();

			Leapvalues[0].value = h1.palmVelocity().x;
			Leapvalues[1].value = h1.palmVelocity().y;
			Leapvalues[2].value = h1.palmVelocity().z;
			Leapvalues[3].value = h1.direction().pitch()*Leap::RAD_TO_DEG;
			Leapvalues[4].value = h1.direction().yaw()*Leap::RAD_TO_DEG;

			indexX = index.tipPosition().x;
			indexY = index.tipPosition().y;
			indexZ = index.tipPosition().z;

			thumbX = thumb.tipPosition().x;
			thumbY = thumb.tipPosition().y;
			thumbZ = thumb.tipPosition().z;

			Leapvalues[5].value = sqrt(pow((indexX - thumbX), 2) + pow((indexY - thumbY), 2) + pow((indexZ - thumbZ), 2));

			leapConnected = true;
			CheckLeapDeadZone();
		}



		for (i = 6; i < NUMBER_OF_BUTTONS; i++)	//DO NOT SET TO <= NUMBER_OF_BUTTONS, NOT A MISTAKE. Verification bit should always keep its value
		{
			{
				Controller[i].value = AnalogToDigital(Controller[i].value);	//converts all of the button presses on the controller to a binary value
			}
		}

		//turns all of the numerical values into buffers that can be passed to the arduino
		for (i = 0; i <= NUMBER_OF_BUTTONS; i++)
		{
			_itoa_s(Controller[i].value, Controller[i].passedValue, 10);
		}

		for (i = 0; i < NUMBER_OF_LEAP_INPUTS; i++)
		{
			_itoa_s(Leapvalues[i].value, Leapvalues[i].passedValue, 10);
		}

		SendData(hSerial);

		std::cout << Controller[8].value << std::endl;
	}
	return 0;
}
Example #28
0
void LeapListener::onFrame(const Leap::Controller& controller) {
  // Get the most recent frame and report some basic information
  const Leap::Frame frame = controller.frame();
  /*std::cout << "Frame id: " << frame.id()
            << ", timestamp: " << frame.timestamp()
            << ", hands: " << frame.hands().count()
            << ", fingers: " << frame.fingers().count()
            << ", tools: " << frame.tools().count()
            << ", gestures: " << frame.gestures().count();
  */

  if (!frame.hands().isEmpty()) {
    // Get the first hand
    const Leap::Hand hand = frame.hands()[0];


    qDebug() << "Radius: " << hand.sphereRadius();

    // Grab
    if(hand.sphereRadius() < 50.0 && hand.translationProbability(controller.frame(1)) > 0.6){
        Leap::Vector v = hand.translation(controller.frame(1));
        v = 0.1 * v;
        glwidget_->camera_.translate(v.x, v.y, v.z);
        glwidget_->update();
    }

    qDebug() << "Hand pos" << hand.palmPosition().x << hand.palmPosition().y << hand.palmPosition().z;

    if(frame.fingers().count() > 200 && frame.hands().count() == 1){
        Leap::Vector trans = hand.translation(controller.frame(1));

        //int dir = trans.y > 0 ? 1 : -1;
        trans = 0.1 * trans;
        //glwidget_->camera_.translate(0, 0, dir*0.1);

        //Leap::Vector rot = hand.rotationAxis(controller.frame());

        float yaw = hand.rotationAngle(controller.frame(1), Leap::Vector(1, 0, 0));
        float pitch = hand.rotationAngle(controller.frame(1), Leap::Vector(1, 0, 0)); // works
        float roll = hand.rotationAngle(controller.frame(1), Leap::Vector(0, 0, 1));

        //qDebug() << yaw <<  pitch <<  roll;

        glwidget_->camera_.rotate3D(yaw, pitch, roll);

        //glwidget_->camera_.rotate2D(0.01 * trans.x, 0.01 * trans.y);

        glwidget_->update();
    }

/*
    // Check if the hand has any fingers
    const Leap::FingerList fingers = hand.fingers();
    if (!fingers.empty()) {
      // Calculate the hand's average finger tip position
      Leap::Vector avgPos;
      for (int i = 0; i < fingers.count(); ++i) {
        avgPos += fingers[i].tipPosition();
      }
      avgPos /= (float)fingers.count();
      std::cout << "Hand has " << fingers.count()
                << " fingers, average finger tip position" << avgPos<< std::endl;
    }

    // Get the hand's sphere radius and palm position
    std::cout << "Hand sphere radius: " << hand.sphereRadius()
              << " mm, palm position: " << hand.palmPosition() << std::endl;

    // Get the hand's normal vector and direction
    const Leap::Vector normal = hand.palmNormal();
    const Leap::Vector direction = hand.direction();

    // Calculate the hand's pitch, roll, and yaw angles
    std::cout << "Hand pitch: " << direction.pitch() * Leap::RAD_TO_DEG << " degrees, "
              << "roll: " << normal.roll() * Leap::RAD_TO_DEG << " degrees, "
              << "yaw: " << direction.yaw() * Leap::RAD_TO_DEG << " degrees"<< std::endl;
  }

  // Get gestures
  const Leap::GestureList gestures = frame.gestures();
  for (int g = 0; g < gestures.count(); ++g) {
    Leap::Gesture gesture = gestures[g];

    switch (gesture.type()) {
      case Leap::Gesture::TYPE_CIRCLE:
      {
        Leap::CircleGesture circle = gesture;
        std::string clockwiseness;

        if (circle.pointable().direction().angleTo(circle.normal()) <= M_PI/4) {
          clockwiseness = "clockwise";
        } else {
          clockwiseness = "counterclockwise";
        }

        // Calculate angle swept since last frame
        float sweptAngle = 0;
        if (circle.state() != Leap::Gesture::STATE_START) {
          Leap::CircleGesture previousUpdate = Leap::CircleGesture(controller.frame().gesture(circle.id()));
          sweptAngle = (circle.progress() - previousUpdate.progress()) * 2 * M_PI;
        }
        std::cout << "Circle id: " << gesture.id()
                  << ", state: " << gesture.state()
                  << ", progress: " << circle.progress()
                  << ", radius: " << circle.radius()
                  << ", angle " << sweptAngle * Leap::RAD_TO_DEG
                  <<  ", " << clockwiseness << std::endl;
        break;
      }
      case Leap::Gesture::TYPE_SWIPE:
      {
        Leap::SwipeGesture swipe = gesture;
        std::cout << "Swipe id: " << gesture.id()
          << ", state: " << gesture.state()
          << ", direction: " << swipe.direction()
          << ", speed: " << swipe.speed() << std::endl;
        break;
      }
      case Leap::Gesture::TYPE_KEY_TAP:
      {
        Leap::KeyTapGesture tap = gesture;
        std::cout << "Key Tap id: " << gesture.id()
          << ", state: " << gesture.state()
          << ", position: " << tap.position()
          << ", direction: " << tap.direction()<< std::endl;
        break;
      }
      case Leap::Gesture::TYPE_SCREEN_TAP:
      {
        Leap::ScreenTapGesture screentap = gesture;
        std::cout << "Screen Tap id: " << gesture.id()
        << ", state: " << gesture.state()
        << ", position: " << screentap.position()
        << ", direction: " << screentap.direction()<< std::endl;
        break;
      }
      default:
        std::cout << "Unknown gesture type.";
        break;
    }
    */
  }

}
Example #29
0
void SampleListener::onFrame(const Leap::Controller& controller) {
  // Get the most recent frame and report some basic information
  const Leap::Frame frame = controller.frame();
  const std::vector<Leap::Hand>& hands = frame.hands();
  const size_t numHands = hands.size();
  std::cout << "Frame id: " << frame.id()
            << ", timestamp: " << frame.timestamp()
            << ", hands: " << numHands << std::endl;

  if (numHands >= 1) {
    // Get the first hand
    const Leap::Hand& hand = hands[0];

    // Check if the hand has any fingers
    const std::vector<Leap::Finger>& fingers = hand.fingers();
    const size_t numFingers = fingers.size();
    if (numFingers >= 1) {
      // Calculate the hand's average finger tip position
      Leap::Vector pos(0, 0, 0);
      for (size_t i = 0; i < numFingers; ++i) {
        const Leap::Finger& finger = fingers[i];
        const Leap::Ray& tip = finger.tip();
        pos.x += tip.position.x;
        pos.y += tip.position.y;
        pos.z += tip.position.z;
      }
      pos = Leap::Vector(pos.x/numFingers, pos.y/numFingers, pos.z/numFingers);
      std::cout << "Hand has " << numFingers << " fingers with average tip position"
                << " (" << pos.x << ", " << pos.y << ", " << pos.z << ")" << std::endl;
    }

    // Check if the hand has a palm
    const Leap::Ray* palmRay = hand.palm();
    if (palmRay != NULL) {
      // Get the palm position and wrist direction
      const Leap::Vector palm = palmRay->position;
      const Leap::Vector wrist = palmRay->direction;
      std::cout << "Palm position: ("
                << palm.x << ", " << palm.y << ", " << palm.z << ")" << std::endl;

      // Check if the hand has a normal vector
      const Leap::Vector* normal = hand.normal();
      if (normal != NULL) {
        // Calculate the hand's pitch, roll, and yaw angles
        double pitchAngle = atan2(normal->z, normal->y) * 180/M_PI + 180;
        double rollAngle = atan2(normal->x, normal->y) * 180/M_PI + 180;
        double yawAngle = atan2(wrist.z, wrist.x) * 180/M_PI - 90;
        // Ensure the angles are between -180 and +180 degrees
        if (pitchAngle > 180) pitchAngle -= 360;
        if (rollAngle > 180) rollAngle -= 360;
        if (yawAngle > 180) yawAngle -= 360;
        std::cout << "Pitch: " << pitchAngle << " degrees,  "
                  << "roll: " << rollAngle << " degrees,  "
                  << "yaw: " << yawAngle << " degrees" << std::endl;
      }
    }

    // Check if the hand has a ball
    const Leap::Ball* ball = hand.ball();
    if (ball != NULL) {
      std::cout << "Hand curvature radius: " << ball->radius << " mm" << std::endl;
    }
  }
}
Example #30
0
int main()
{
	//Leap Motion Vairables
	Leap::Controller controller;
	Leap::Frame frame;
	Leap::HandList hands;
	Leap::Hand h1;
	Leap::FingerList fingers;
	Leap::Finger index;
	Leap::Finger thumb;
	Leap::PointableList pointables;
	float indexX = 0, indexY = 0, indexZ = 0, thumbX = 0, thumbY = 0, thumbZ = 0, sum = 0;
	unsigned long cycles = 0;

	// TCP Variables
	WSADATA wsaData;
	SOCKET connectSocket = INVALID_SOCKET;

	struct addrinfo* result = NULL;
	struct addrinfo* ptr = NULL;
	struct addrinfo  hints;

	char cSendBuf[512][512];
	char sSendBuf[512];

	int iResult;
	int recvBufLen = DEFAULT_BUFLEN;

	int i = 0;

	iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
	if (iResult != 0) {
		printf("WSAStartup failed with error: %d\n", iResult);
		return 1;
	}

	// Initialize all address info to 0 to start.
	SecureZeroMemory(&hints, sizeof(hints));
	hints.ai_family = AF_UNSPEC;     // Doesn't matter if we use IPV4 or IPV6
	hints.ai_socktype = SOCK_STREAM; // TCP Stream sockets
	hints.ai_protocol = IPPROTO_TCP;

	// Resolve the server address and port
	iResult = getaddrinfo("127.0.0.1", DEFAULT_PORT, &hints, &result);
	if (iResult != 0) {
		printf("getaddrinfo failed with error: %d\n", iResult);
		WSACleanup();
		return 1;
	}

	// Attempt to connect to an address until one succeeds
	for (ptr = result; ptr != NULL; ptr = ptr->ai_next) {

		// create a socket for connecting to the server
		connectSocket = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);

		if (connectSocket == INVALID_SOCKET) {
			printf("socket failed with error: %ld\n", WSAGetLastError());
			WSACleanup();
			return 1;
		}

		// Connect to the server
		iResult = connect(connectSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
		if (iResult == SOCKET_ERROR) {
			closesocket(connectSocket);
			connectSocket = INVALID_SOCKET;
			continue;
		}

		break;
	}

	// Deallocate the address info
	freeaddrinfo(result);

	if (connectSocket == INVALID_SOCKET) {
		printf("Unable to connect to server!\n");
		WSACleanup();
		return 1;
	}

	// Setup serial port connection and needed variables.
	SerialPort.Open(PORT_NUM, BAUD);

	Controller[20].value = 9;	//Verification Byte sent to make sure everything else ends up in the right location
	FillByteSize();

	while (true)
	{
		cycles++;
		UpdateControllerState();	//Updates all values on the controller
		WORD wButtons = g_Controllers[CONTROLLER1].state.Gamepad.wButtons;

		//Stores all of the values from the controller into the controller structure
		Controller[0].value = g_Controllers[CONTROLLER1].state.Gamepad.sThumbRX;
		Controller[1].value = g_Controllers[CONTROLLER1].state.Gamepad.sThumbRY;
		Controller[2].value = g_Controllers[CONTROLLER1].state.Gamepad.sThumbLX;
		Controller[3].value = g_Controllers[CONTROLLER1].state.Gamepad.sThumbLY;
		Controller[4].value = (g_Controllers[CONTROLLER1].state.Gamepad.bRightTrigger);
		Controller[5].value = (g_Controllers[CONTROLLER1].state.Gamepad.bLeftTrigger);
		Controller[6].value = (wButtons & XINPUT_GAMEPAD_RIGHT_THUMB);
		Controller[7].value = (wButtons & XINPUT_GAMEPAD_LEFT_THUMB);
		Controller[8].value = (wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER);
		Controller[9].value = (wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER);
		Controller[10].value = (wButtons & XINPUT_GAMEPAD_DPAD_UP);
		Controller[11].value = (wButtons & XINPUT_GAMEPAD_DPAD_DOWN);
		Controller[12].value = (wButtons & XINPUT_GAMEPAD_DPAD_LEFT);
		Controller[13].value = (wButtons & XINPUT_GAMEPAD_DPAD_RIGHT);
		Controller[14].value = (wButtons & XINPUT_GAMEPAD_A);
		Controller[15].value = (wButtons & XINPUT_GAMEPAD_B);
		Controller[16].value = (wButtons & XINPUT_GAMEPAD_Y);
		Controller[17].value = (wButtons & XINPUT_GAMEPAD_X);
		Controller[18].value = (wButtons & XINPUT_GAMEPAD_START);
		Controller[19].value = (wButtons & XINPUT_GAMEPAD_BACK);

		CheckDeadZone();

		if (controller.isConnected() == true)
		{ 
			sum = 0;
			frame = controller.frame();
			hands = frame.hands();
			h1 = hands[0];
			fingers = frame.fingers();
			thumb = fingers[0];
			index = fingers[1];
			pointables = frame.pointables();

			Leapvalues[0].value = h1.palmVelocity().x;
			Leapvalues[1].value = h1.palmVelocity().y;
			Leapvalues[2].value = h1.palmVelocity().z;

			Leapvalues[3].value = h1.direction().pitch()*Leap::RAD_TO_DEG;
			Leapvalues[4].value = h1.direction().yaw()*Leap::RAD_TO_DEG;
			Leapvalues[5].value = h1.direction().roll()*Leap::RAD_TO_DEG;

			indexX = index.tipPosition().x;
			indexY = index.tipPosition().y;
			indexZ = index.tipPosition().z;

			thumbX = thumb.tipPosition().x;
			thumbY = thumb.tipPosition().y;
			thumbZ = thumb.tipPosition().z;

			Leapvalues[6].value = sqrt(pow((indexX - thumbX), 2) + pow((indexY - thumbY), 2) + pow((indexZ - thumbZ), 2));

			leapConnected = true;
			CheckLeapDeadZone();

		}

		for (i = 6; i < NUMBER_OF_BUTTONS; i++)	//DO NOT SET TO <= NUMBER_OF_BUTTONS, NOT A MISTAKE. Verification bit should always keep its value
		{
			{
				Controller[i].value = AnalogToDigital(Controller[i].value);	//converts all of the button presses on the controller to a binary value
			}
		}

		//turns all of the numerical values into buffers that can be passed to the arduino
		for (i = 0; i <= NUMBER_OF_BUTTONS; i++)
		{
			_itoa_s(Controller[i].value, Controller[i].passedValue, 10);
		}

		/*
		for (i = 0; i < NUMBER_OF_BUTTONS; i++) {
			_itoa_s(Controller[i].value, cSendBuf[i], 10);
			cSendBuf[i][strlen(cSendBuf[i])] = '\0';

			iResult = send(connectSocket, cSendBuf[0], (int)strlen(cSendBuf[0]), 0);

			printf("String sent: %s\n", cSendBuf[0]);

			// Check for errors
			if (iResult == SOCKET_ERROR) {
				printf("send failed with error: %d\n", WSAGetLastError());
				closesocket(connectSocket);
				WSACleanup();
				return 1;
			}
		}

		// Try to send the packet
		iResult = send(connectSocket, "\n", (int)strlen("\n"), 0);

		//printf("String sent: %s\n", sendBuf);

		// Check for errors
		if (iResult == SOCKET_ERROR) {
			printf("send failed with error: %d\n", WSAGetLastError());
			closesocket(connectSocket);
			WSACleanup();
			return 1;
		}*/

		if (leapConnected = true)
		{
			for (i = 0; i < NUMBER_OF_LEAP_INPUTS; i++)
			{
				_itoa_s(Leapvalues[i].value, Leapvalues[i].passedValue, 10);
			}
		}

		/*Values recieved in this order:
		0) YAW
		1) PITCH
		2) ROLL
		3) ACCELERATION ON X AXIS
		4) ACCELERATION ON Y AXIS
		5) ACCELERATION ON Z AXIS
		6) SONAR SENSOR DISTANCE (IN METERS)
		*/
		if (SendData() == 1)
		{
			for (i = 0; i < 7; i++)
			{
				while (SerialPort.ReadDataWaiting() < 3)
				{
				}

				if (i > 2 && i < 6)
					SerialPort.ReadData(received[i], 5);

				else
					SerialPort.ReadData(received[i], 4);

				std::cout << received[i] << ' ';

				// Added this 6.25.14
				strcpy(sSendBuf, received[i]);
				sSendBuf[strlen(sSendBuf)] = '\0';
				iResult = send(connectSocket, sSendBuf, (int)strlen(sSendBuf), 0);

				printf("String sent: %s\n", sSendBuf);

				// Check for errors
				if (iResult == SOCKET_ERROR) {
					printf("send failed with error: %d\n", WSAGetLastError());
					closesocket(connectSocket);
					WSACleanup();
					return 1;
				}

				// Try to send the packet
				iResult = send(connectSocket, "\n", (int)strlen("\n"), 0);

				//printf("String sent: %s\n", sendBuf);

				// Check for errors
				if (iResult == SOCKET_ERROR) {
					printf("send failed with error: %d\n", WSAGetLastError());
					closesocket(connectSocket);
					WSACleanup();
					return 1;
				}
			}
		}
			
		
		
		//std::cout << recieved[0];
		printf("\t%d", cycles);
		printf("\n");
		//Sleep(500);  <<'\t' << recieved[1]

		
	}

	closesocket(connectSocket);
	WSACleanup();
	return 0;
}