diff --git a/src/FootTrajectoryGeneration/FootTrajectoryGenerationStandard.cpp b/src/FootTrajectoryGeneration/FootTrajectoryGenerationStandard.cpp index f6d2cf93c4d2d39a3378cbab8fdb11a1e6d9d1ba..5180cc835135e3ec7d12b3ce2c5f2ac5b06a6bc8 100644 --- a/src/FootTrajectoryGeneration/FootTrajectoryGenerationStandard.cpp +++ b/src/FootTrajectoryGeneration/FootTrajectoryGenerationStandard.cpp @@ -172,7 +172,7 @@ int FootTrajectoryGenerationStandard::SetParameters(int PolynomeIndex, case Z_AXIS: m_PolynomeZ->SetParameters(TimeInterval,Position); - m_BsplinesZ->SetParameters(TimeInterval,Position,TimeInterval/3.0,Position*1.5); + m_BsplinesZ->SetParameters(TimeInterval,Position,TimeInterval/3.0,Position + m_StepHeight); break; case THETA_AXIS: @@ -213,13 +213,16 @@ int FootTrajectoryGenerationStandard::SetParametersWithInitPosInitSpeed(int Poly break; case Z_AXIS: - m_PolynomeZ->SetParametersWithInitPosInitSpeed(TimeInterval,FinalPosition,InitPosition,InitSpeed); + + m_PolynomeZ->SetParametersWithInitPosInitSpeed(TimeInterval,FinalPosition,InitPosition,InitSpeed); if ((FinalPosition - InitPosition)== m_StepHeight) m_BsplinesZ->SetParametersWithInitPos(InitPosition,TimeInterval,InitPosition,0.5*TimeInterval,InitPosition+m_StepHeight); - else if (FinalPosition >= InitPosition) - m_BsplinesZ->SetParametersWithInitPos(InitPosition,TimeInterval,FinalPosition,1.5*TimeInterval/5.0,InitPosition+abs(FinalPosition-InitPosition)*1.5); + else if (FinalPosition > InitPosition) + m_BsplinesZ->SetParametersWithInitPos(InitPosition,TimeInterval,FinalPosition,1.5*TimeInterval/5.0,FinalPosition+m_StepHeight);//+abs(FinalPosition-InitPosition)*1.5); + else if (FinalPosition == InitPosition) + m_BsplinesZ->SetParametersWithInitPos(InitPosition,TimeInterval,FinalPosition,0.5*TimeInterval,FinalPosition);//+abs(FinalPosition-InitPosition)*1.5); else if (FinalPosition < InitPosition) - m_BsplinesZ->SetParametersWithInitPos(InitPosition,TimeInterval,FinalPosition,4.0*TimeInterval/5.0,InitPosition+abs(FinalPosition-InitPosition)*0.2); + m_BsplinesZ->SetParametersWithInitPos(InitPosition,TimeInterval,FinalPosition,3.7*TimeInterval/5.0,FinalPosition+m_StepHeight);//abs(FinalPosition-InitPosition)*0.3); /*if (InitPosition == FinalPosition) m_PolynomeZ->SetParametersWithInitPosInitSpeed(TimeInterval,FinalPosition,InitPosition,InitSpeed); @@ -270,10 +273,12 @@ int FootTrajectoryGenerationStandard::SetParameters(int PolynomeIndex, double Ti //{ if ((FinalPosition - InitPosition)== m_StepHeight) m_BsplinesZ->SetParametersWithInitPos(InitPosition,TimeInterval,InitPosition,0.5*TimeInterval,InitPosition+m_StepHeight); - else if (FinalPosition >= InitPosition) - m_BsplinesZ->SetParametersWithInitPos(InitPosition,TimeInterval,FinalPosition,1.5*TimeInterval/5.0,InitPosition+abs(FinalPosition-InitPosition)*1.5); + else if (FinalPosition > InitPosition) + m_BsplinesZ->SetParametersWithInitPos(InitPosition,TimeInterval,FinalPosition,1.5*TimeInterval/5.0,FinalPosition+m_StepHeight);//InitPosition+abs(FinalPosition-InitPosition)*1.5); + else if (FinalPosition == InitPosition) + m_BsplinesZ->SetParametersWithInitPos(InitPosition,TimeInterval,FinalPosition,0.5*TimeInterval,FinalPosition);//InitPosition+abs(FinalPosition-InitPosition)*1.5); else if (FinalPosition < InitPosition) - m_BsplinesZ->SetParametersWithInitPos(InitPosition,TimeInterval,FinalPosition,4.0*TimeInterval/5.0,InitPosition+abs(FinalPosition-InitPosition)*0.2); + m_BsplinesZ->SetParametersWithInitPos(InitPosition,TimeInterval,FinalPosition,3.7*TimeInterval/5.0,FinalPosition+m_StepHeight);//+abs(FinalPosition-InitPosition)*0.3); // else if (FinalPosition == InitPosition) // m_PolynomeZ->SetParametersWithInitPosInitSpeed(TimeInterval,FinalPosition,InitPosition,InitSpeed); diff --git a/src/FootTrajectoryGeneration/LeftAndRightFootTrajectoryGenerationMultiple.cpp b/src/FootTrajectoryGeneration/LeftAndRightFootTrajectoryGenerationMultiple.cpp index 40b4aca5d12a081c31420aafe165feedbe57f2e1..e12e64617d0e30d824316251ad447566d4c0e649 100644 --- a/src/FootTrajectoryGeneration/LeftAndRightFootTrajectoryGenerationMultiple.cpp +++ b/src/FootTrajectoryGeneration/LeftAndRightFootTrajectoryGenerationMultiple.cpp @@ -125,14 +125,13 @@ void LeftAndRightFootTrajectoryGenerationMultiple::SetAnInterval(unsigned int In FootInitialPosition.y, FootInitialPosition.dy); - // Z axis. - aFTGM->SetParametersWithInitPosInitSpeed(IntervalIndex, - FootTrajectoryGenerationStandard::Z_AXIS, - 0.95*m_DeltaTj[IntervalIndex], - FootFinalPosition.z, - FootInitialPosition.z, - FootInitialPosition.dz); + FootTrajectoryGenerationStandard::Z_AXIS, + m_DeltaTj[IntervalIndex], + FootFinalPosition.z, + FootInitialPosition.z, + FootInitialPosition.dz); + // THETA aFTGM->SetParametersWithInitPosInitSpeed(IntervalIndex, @@ -160,9 +159,17 @@ void LeftAndRightFootTrajectoryGenerationMultiple::SetAnInterval(unsigned int In // Init the first interval. // X axis. - aFTGM->SetParametersWithInitPosInitSpeed(IntervalIndex, + if (FootFinalPosition.z < FootInitialPosition.z ) + aFTGM->SetParametersWithInitPosInitSpeed(IntervalIndex, + FootTrajectoryGenerationStandard::X_AXIS, + m_DeltaTj[IntervalIndex], + FootFinalPosition.x, + FootInitialPosition.x, + FootInitialPosition.dx); + else + aFTGM->SetParametersWithInitPosInitSpeed(IntervalIndex, FootTrajectoryGenerationStandard::X_AXIS, - 0.8*m_DeltaTj[IntervalIndex], + 0.75*m_DeltaTj[IntervalIndex], FootFinalPosition.x, FootInitialPosition.x, FootInitialPosition.dx); @@ -825,7 +832,6 @@ InitializeFromRelativeSteps(deque<RelativeFootPosition> &RelativeFootPositions, RightFootTmpFinalPos.domega2 = 0.0; RightFootTmpFinalPos.stepType = 1; LeftFootTmpFinalPos = LeftFootTmpInitPos; - //LeftFootTmpFinalPos.z = 0.0; LeftFootTmpFinalPos.dz = 0.0; LeftFootTmpFinalPos.stepType = -1; } @@ -894,6 +900,7 @@ InitializeFromRelativeSteps(deque<RelativeFootPosition> &RelativeFootPositions, LeftFootTmpInitPos, LeftFootTmpFinalPos); + ODEBUG("LeftInit: ( " << LeftFootTmpInitPos.x << " , " << LeftFootTmpInitPos.y << " , " << LeftFootTmpInitPos.z << " ) ( " @@ -915,6 +922,10 @@ InitializeFromRelativeSteps(deque<RelativeFootPosition> &RelativeFootPositions, RightFootTmpInitPos, RightFootTmpFinalPos); + if (SupportFoot==1) + RightFootTmpFinalPos.z = CurrentSupportFootPosition(2,2); + else + LeftFootTmpFinalPos.z = CurrentSupportFootPosition(2,2); ODEBUG("RightInit: ( " << RightFootTmpInitPos.x << " , " << RightFootTmpInitPos.y << " , " << RightFootTmpInitPos.z << " ) ( " @@ -928,8 +939,7 @@ InitializeFromRelativeSteps(deque<RelativeFootPosition> &RelativeFootPositions, << RightFootTmpFinalPos.dx << " , " << RightFootTmpFinalPos.dy << " , " << RightFootTmpFinalPos.dz << " ) " ); - - // Switch from single support to double support. + // Switch from single support to double support. IntervalIndex++; } @@ -994,12 +1004,12 @@ InitializeFromRelativeSteps(deque<RelativeFootPosition> &RelativeFootPositions, { for(unsigned int lk=0;lk<2;lk++) { - //LeftFootTmpFinalPos.z = 0;//CurrentSupportFootPosition(2,2); + LeftFootTmpFinalPos.z = CurrentSupportFootPosition(2,2); LeftFootTmpFinalPos.dz = 0; SetAnInterval(IntervalIndex,m_LeftFootTrajectory, LeftFootTmpFinalPos, LeftFootTmpFinalPos); - // RightFootTmpFinalPos.z = 0; + RightFootTmpFinalPos.z = CurrentSupportFootPosition(2,2); RightFootTmpFinalPos.dz = 0; SetAnInterval(IntervalIndex,m_RightFootTrajectory, RightFootTmpFinalPos, diff --git a/src/Mathematics/Bsplines.cpp b/src/Mathematics/Bsplines.cpp index 931eed345645a627ad3a31556fd92d81f3bf5ff1..449d5b16dbb616bf4539d55fb58f888d314a3051 100644 --- a/src/Mathematics/Bsplines.cpp +++ b/src/Mathematics/Bsplines.cpp @@ -416,11 +416,11 @@ void ZBsplines::ZGenerateControlPoints(double IP, double FT, double FP, double T control_points.push_back(A); myfile1 << A.x <<" "<< A.y<< endl; - A = {0.85*m_ToMP,m_MP}; + A = {0.75*m_ToMP,m_MP}; control_points.push_back(A); myfile1 << A.x <<" "<< A.y<< endl; - A = {1.15*m_ToMP,m_MP}; + A = {1.25*m_ToMP,m_MP}; control_points.push_back(A); myfile1 << A.x <<" "<< A.y<< endl; diff --git a/src/ZMPRefTrajectoryGeneration/AnalyticalMorisawaCompact.cpp b/src/ZMPRefTrajectoryGeneration/AnalyticalMorisawaCompact.cpp index 33caa46a614dd7bb671dbf0998ee57f361017718..e986cbdb1468a78a575fb618039b16e9159571c1 100644 --- a/src/ZMPRefTrajectoryGeneration/AnalyticalMorisawaCompact.cpp +++ b/src/ZMPRefTrajectoryGeneration/AnalyticalMorisawaCompact.cpp @@ -2298,23 +2298,18 @@ namespace PatternGeneratorJRL - if (RightFootAbsPos.z <= LeftFootAbsPos.z){ + /* if (RightFootAbsPos.z <= LeftFootAbsPos.z){ aCOMPos.z[1] = (m_InitialPoseCoMHeight + RightFootAbsPos.z - aCOMPos.z[0])/m_SamplingPeriod; aCOMPos.z[0] = m_InitialPoseCoMHeight + RightFootAbsPos.z; } else{ aCOMPos.z[1] = (m_InitialPoseCoMHeight + LeftFootAbsPos.z - aCOMPos.z[0])/m_SamplingPeriod; aCOMPos.z[0] = m_InitialPoseCoMHeight + LeftFootAbsPos.z; - } + }*/ - if (m_isStepStairOn == 0) - { - aCOMPos.z[0] = m_InitialPoseCoMHeight; - } - else{ - ComputeCoMz(t,aCOMPos.z[0]); - } + ComputeCoMz(t,aCOMPos.z[0], aCOMPos.z[1]); + FinalCoMPositions.push_back(aCOMPos); @@ -2329,41 +2324,82 @@ namespace PatternGeneratorJRL } - void AnalyticalMorisawaCompact::ComputeCoMz(double t, double &CoMz) + void AnalyticalMorisawaCompact::ComputeCoMz(double t, double &CoMz, double &CoMvelocity) { - int Index; + int Index,Index2; double moving_time = m_RelativeFootPositions[0].SStime + m_RelativeFootPositions[0].DStime; double deltaZ; - - + double CoMzpre = CoMz; + double variable=0.1,variableright = 0.9 ,variableleft = 0.0; + double variableright1 = 0.9 ,variableleft1 = 0.0; + // put first leg on the stairs with CoM going down variable % of step height if (t >= moving_time){ - /* Index = int((t-moving_time)/(moving_time*2)); - if (Index < (m_AbsoluteSupportFootPositions.size() - 1)/2){ - deltaZ = (m_AbsoluteSupportFootPositions[2*Index + 1].z - m_AbsoluteSupportFootPositions[2*Index].z ); - CoMz = t*deltaZ/(moving_time*2) + ( m_InitialPoseCoMHeight - (2*Index + 1)*moving_time*deltaZ/(moving_time*2) ) + m_AbsoluteSupportFootPositions[2*Index].z ; - */ - Index = int((t-moving_time)/(moving_time*2)); - if (Index < (m_AbsoluteSupportFootPositions.size() - 1)/2){ - deltaZ = (m_AbsoluteSupportFootPositions[2*Index + 1].z - m_AbsoluteSupportFootPositions[2*Index].z ); - if (deltaZ > 0 && t>=(2*Index+2)*moving_time && t<=(2*Index+2)*moving_time + m_RelativeFootPositions[2*Index+1].SStime) - CoMz = t*deltaZ/m_RelativeFootPositions[0].SStime + m_InitialPoseCoMHeight - (2*Index + 2)*moving_time*deltaZ/m_RelativeFootPositions[0].SStime + m_AbsoluteSupportFootPositions[2*Index].z ; - else if (deltaZ > 0 && t>(2*Index+2)*moving_time + m_RelativeFootPositions[2*Index+1].SStime) - CoMz = CoMz; - if (deltaZ < 0 && t>=(2*Index+1)*moving_time && t<=(2*Index+2)*moving_time ) - CoMz = t*deltaZ/moving_time + m_InitialPoseCoMHeight - (2*Index + 1)*moving_time*deltaZ/moving_time + m_AbsoluteSupportFootPositions[2*Index].z ; - else if (deltaZ > 0 && t>(2*Index+2)*moving_time + m_RelativeFootPositions[2*Index+1].SStime) - CoMz = CoMz; + Index2 = int(t/moving_time); + + + if (Index2 < m_AbsoluteSupportFootPositions.size()) + { + // climbing + if (m_AbsoluteSupportFootPositions[Index2].z > m_AbsoluteSupportFootPositions[Index2-1].z) + { + deltaZ = (-m_AbsoluteSupportFootPositions[Index2].z + m_AbsoluteSupportFootPositions[Index2-1].z ); + if (t <= Index2*moving_time + variableright*m_RelativeFootPositions[Index2].SStime && t >= Index2*moving_time + variableleft*m_RelativeFootPositions[Index2].SStime) + CoMz = (t-Index2*moving_time - variableleft*m_RelativeFootPositions[Index2].SStime)*variable*deltaZ/((variableright-variableleft)*m_RelativeFootPositions[Index2].SStime) + m_InitialPoseCoMHeight + m_AbsoluteSupportFootPositions[Index2-1].z ; + else if (t < Index2*moving_time + variableleft*m_RelativeFootPositions[Index2].SStime) + CoMz = m_InitialPoseCoMHeight + m_AbsoluteSupportFootPositions[Index2-1].z ; + else + CoMz = m_InitialPoseCoMHeight + m_AbsoluteSupportFootPositions[Index2-1].z + variable*deltaZ; + } + else if (m_AbsoluteSupportFootPositions[Index2].z == m_AbsoluteSupportFootPositions[Index2-1].z && m_RelativeFootPositions[Index2-1].sz > 0) + { + deltaZ = (m_AbsoluteSupportFootPositions[Index2].z - m_AbsoluteSupportFootPositions[Index2-2].z ); + if (t <= Index2*moving_time + variableright1*m_RelativeFootPositions[Index2].SStime && t >= Index2*moving_time + variableleft1*m_RelativeFootPositions[Index2].SStime) + CoMz = (t-Index2*moving_time - variableleft1*m_RelativeFootPositions[Index2].SStime)*(1+variable)*deltaZ/((variableright1-variableleft1)*m_RelativeFootPositions[Index2].SStime) + m_InitialPoseCoMHeight + m_AbsoluteSupportFootPositions[Index2-2].z - variable*deltaZ ; + else if (t < Index2*moving_time + variableleft1*m_RelativeFootPositions[Index2].SStime) + CoMz = m_InitialPoseCoMHeight + m_AbsoluteSupportFootPositions[Index2-2].z - variable*deltaZ; + else + CoMz = m_InitialPoseCoMHeight + m_AbsoluteSupportFootPositions[Index2].z; + } + + // going down et normal walk + if (m_AbsoluteSupportFootPositions[Index2].z <= m_AbsoluteSupportFootPositions[Index2-1].z && m_RelativeFootPositions[Index2-1].sz <= 0) + { + deltaZ = (m_AbsoluteSupportFootPositions[Index2].z - m_AbsoluteSupportFootPositions[Index2-1].z ); + if (t <= Index2*moving_time + 0.9*m_RelativeFootPositions[Index2].SStime ) + CoMz = (t-Index2*moving_time)*deltaZ/(0.9*m_RelativeFootPositions[Index2].SStime) + m_InitialPoseCoMHeight + m_AbsoluteSupportFootPositions[Index2-1].z ; + else + CoMz = m_InitialPoseCoMHeight + m_AbsoluteSupportFootPositions[Index2].z; } } + + else + CoMz = m_InitialPoseCoMHeight + m_AbsoluteSupportFootPositions.back().z; + + + + } else - CoMz = m_InitialPoseCoMHeight; + CoMz = m_InitialPoseCoMHeight ; + CoMvelocity = (CoMz -CoMzpre)/m_SamplingPeriod; } } + /*Index = int((t-moving_time)/(moving_time*2)); + if (Index < (m_AbsoluteSupportFootPositions.size() - 1)/2){ + deltaZ = (m_AbsoluteSupportFootPositions[2*Index + 1].z - m_AbsoluteSupportFootPositions[2*Index].z ); + if (deltaZ > 0 && t>=(2*Index+2)*moving_time && t<=(2*Index+2)*moving_time + m_RelativeFootPositions[2*Index+1].SStime) + CoMz = t*deltaZ/m_RelativeFootPositions[0].SStime + m_InitialPoseCoMHeight - (2*Index + 2)*moving_time*deltaZ/m_RelativeFootPositions[0].SStime + m_AbsoluteSupportFootPositions[2*Index].z ; + else if (deltaZ > 0 && t>(2*Index+2)*moving_time + m_RelativeFootPositions[2*Index+1].SStime) + CoMz = CoMz + m_AbsoluteSupportFootPositions[2*Index].z; + if (deltaZ < 0 && t>=(2*Index+1)*moving_time && t<=(2*Index+2)*moving_time ) + CoMz = t*deltaZ/moving_time + m_InitialPoseCoMHeight - (2*Index + 1)*moving_time*deltaZ/moving_time + m_AbsoluteSupportFootPositions[2*Index].z ; + else if (deltaZ > 0 && t>(2*Index+2)*moving_time + m_RelativeFootPositions[2*Index+1].SStime) + CoMz = CoMz + m_AbsoluteSupportFootPositions[2*Index].z; + }*/ diff --git a/src/ZMPRefTrajectoryGeneration/AnalyticalMorisawaCompact.hh b/src/ZMPRefTrajectoryGeneration/AnalyticalMorisawaCompact.hh index 0ddfe13c2acc20fe869dd38b35d833518fd8eb15..a5ced615ba6cc7ea6f1c281004bd9187571963cd 100644 --- a/src/ZMPRefTrajectoryGeneration/AnalyticalMorisawaCompact.hh +++ b/src/ZMPRefTrajectoryGeneration/AnalyticalMorisawaCompact.hh @@ -556,7 +556,7 @@ namespace PatternGeneratorJRL deque<FootAbsolutePosition> & FinalRightFootAbsolutePositions); - void ComputeCoMz(double t, double &CoMz); + void ComputeCoMz(double t, double &CoMz, double &CoMvelocity); /*! \brief LU decomposition of the Z matrix. */ MAL_MATRIX_TYPE(double) m_AF; diff --git a/tests/TestMorisawa2007.cpp b/tests/TestMorisawa2007.cpp index bb0d227c93fabcd7abd85cf1424e3a08d2165c80..c335e261872db318a871ca74817d4e8ddef9ff5c 100644 --- a/tests/TestMorisawa2007.cpp +++ b/tests/TestMorisawa2007.cpp @@ -351,13 +351,13 @@ protected: ostringstream oss(std::ostringstream::ate); if ( iteration == 0 ){ - oss.str("/tmp/Step_Stair_Down.pos"); + oss.str("/tmp/Step_Stair_Down_Seq.pos"); aFileName = oss.str(); aof.open(aFileName.c_str(),ofstream::out); aof.close(); } ///---- - oss.str("/tmp/Step_Stair_Down.pos"); + oss.str("/tmp/Step_Stair_Down_Seq.pos"); aFileName = oss.str(); aof.open(aFileName.c_str(),ofstream::app); aof.precision(8); @@ -373,12 +373,12 @@ protected: aof.close(); if ( iteration == 0 ){ - oss.str("/tmp/Step_Stair_Down.hip"); + oss.str("/tmp/Step_Stair_Down_Seq.hip"); aFileName = oss.str(); aof.open(aFileName.c_str(),ofstream::out); aof.close(); } - oss.str("/tmp/Step_Stair_Down.hip"); + oss.str("/tmp/Step_Stair_Down_Seq.hip"); aFileName = oss.str(); aof.open(aFileName.c_str(),ofstream::app); aof.precision(8); @@ -391,7 +391,7 @@ protected: aof.close(); if ( iteration == 0 ){ - oss.str("/tmp/Step_Stair_Down.zmp"); + oss.str("/tmp/Step_Stair_Down_Seq.zmp"); aFileName = oss.str(); aof.open(aFileName.c_str(),ofstream::out); aof.close(); @@ -402,7 +402,7 @@ protected: aSupportState = m_OneStep.LeftFootPosition ; else aSupportState = m_OneStep.RightFootPosition ; - oss.str("/tmp/Step_Stair_Down.zmp"); + oss.str("/tmp/Step_Stair_Down_Seq.zmp"); aFileName = oss.str(); aof.open(aFileName.c_str(),ofstream::app); aof.precision(8); @@ -498,16 +498,44 @@ protected: { istringstream strm2(":stepstairseq 0.0 -0.105 0.0 0.0\ - 0.3 0.19 -0.086 0.0\ - 0.0 -0.19 0.0 0.0\ - 0.3 0.19 0.086 0.0\ + 0.3 0.19 -0.15 0.0\ 0.0 -0.19 0.0 0.0\ - 0.3 0.19 0.0 0.0\ + 0.3 0.19 -0.15 0.0\ 0.0 -0.19 0.0 0.0\ - 0.3 0.19 0.0 0.0\ + 0.3 0.19 -0.15 0.0\ 0.0 -0.19 0.0 0.0\ "); aPGI.ParseCmd(strm2); + /*0.0 -0.105 0.0 0.0\ + 0.2 0.19 0.0 0.0\ + 0.2 -0.19 0.0 0.0\ + 0.2 0.19 0.0 0.0\ + 0.0 -0.19 0.0 0.0\ + + 0.2 0.19 0.0 0.0\ + 0.2 -0.19 0.0 0.0\ + 0.2 0.19 0.0 0.0\ + 0.2 -0.19 0.0 0.0\ + 0.1 0.19 0.0 0.0\ + 0.4 -0.19 0.086 0.0\ + 0.0 0.19 0.0 0.0\ + 0.4 -0.19 0.086 0.0\ + 0.0 0.19 0.0 0.0\ + 0.4 -0.19 0.086 0.0\ + 0.0 0.19 0.0 0.0\ + 0.2 -0.19 0.0 0.0\ + 0.2 0.19 0.0 0.0\ + 0.0 -0.19 0.0 0.0\ + 0.4 0.19 -0.086 0.0\ + 0.0 -0.19 0.0 0.0\ + 0.4 0.19 -0.086 0.0\ + 0.0 -0.19 0.0 0.0\ + 0.4 0.19 -0.086 0.0\ + 0.0 -0.19 0.0 0.0\ + 0.2 0.19 0.0 0.0\ + 0.2 -0.19 0.0 0.0\ + 0.2 0.19 0.0 0.0\ + 0.0 -0.19 0.0 0.0\*/ } }