void USplineComponent::UpdateSpline() { const int32 NumPoints = SplineInfo.Points.Num(); check(SplineRotInfo.Points.Num() == NumPoints && SplineScaleInfo.Points.Num() == NumPoints); // Ensure input keys are ascending in steps of 1.0 for (int32 Index = 0; Index < NumPoints; Index++) { const float InVal = static_cast<float>(Index); SplineInfo.Points[Index].InVal = InVal; SplineRotInfo.Points[Index].InVal = InVal; SplineScaleInfo.Points[Index].InVal = InVal; } // Nothing else to do if less than 2 points if (NumPoints < 2) { return; } // Ensure splines' looping status matches with that of the spline component if (bClosedLoop) { const float LoopKey = static_cast<float>(NumPoints); SplineInfo.SetLoopKey(LoopKey); SplineRotInfo.SetLoopKey(LoopKey); SplineScaleInfo.SetLoopKey(LoopKey); } else { SplineInfo.ClearLoopKey(); SplineRotInfo.ClearLoopKey(); SplineScaleInfo.ClearLoopKey(); } // Automatically set the tangents on any CurveAuto keys SplineInfo.AutoSetTangents(0.0f, bStationaryEndpoints); SplineRotInfo.AutoSetTangents(0.0f, bStationaryEndpoints); SplineScaleInfo.AutoSetTangents(0.0f, bStationaryEndpoints); // Now initialize the spline reparam table const int32 NumSegments = bClosedLoop ? NumPoints : NumPoints - 1; // Start by clearing it SplineReparamTable.Points.Reset(NumSegments * ReparamStepsPerSegment + 1); float AccumulatedLength = 0.0f; for (int32 SegmentIndex = 0; SegmentIndex < NumSegments; ++SegmentIndex) { for (int32 Step = 0; Step < ReparamStepsPerSegment; ++Step) { const float Param = static_cast<float>(Step) / ReparamStepsPerSegment; const float SegmentLength = (Step == 0) ? 0.0f : GetSegmentLength(SegmentIndex, Param); SplineReparamTable.Points.Emplace(SegmentLength + AccumulatedLength, SegmentIndex + Param, 0.0f, 0.0f, CIM_Linear); } AccumulatedLength += GetSegmentLength(SegmentIndex, 1.0f); } SplineReparamTable.Points.Emplace(AccumulatedLength, static_cast<float>(NumSegments), 0.0f, 0.0f, CIM_Linear); }
void USplineComponent::UpdateSpline() { const int32 NumPoints = SplineInfo.Points.Num(); check(!bClosedLoop || NumPoints == 0 || (NumPoints >= 2 && SplineInfo.Points[0].OutVal == SplineInfo.Points[NumPoints - 1].OutVal)); // Automatically set the tangents on any CurveAuto keys SplineInfo.AutoSetTangents(0.0f, bStationaryEndpoints); // Nothing else to do if less than 2 points if (NumPoints < 2) { return; } // Adjust auto tangents for first and last keys to take into account the looping if (bClosedLoop) { auto& FirstPoint = SplineInfo.Points[0]; auto& LastPoint = SplineInfo.Points[NumPoints - 1]; const auto& SecondPoint = SplineInfo.Points[1]; const auto& PenultimatePoint = SplineInfo.Points[NumPoints - 2]; if (FirstPoint.InterpMode == CIM_CurveAuto || FirstPoint.InterpMode == CIM_CurveAutoClamped) { FVector Tangent; ComputeCurveTangent( PenultimatePoint.InVal - LastPoint.InVal, PenultimatePoint.OutVal, FirstPoint.InVal, FirstPoint.OutVal, SecondPoint.InVal, SecondPoint.OutVal, 0.0f, FirstPoint.InterpMode == CIM_CurveAutoClamped, Tangent); FirstPoint.LeaveTangent = Tangent; FirstPoint.ArriveTangent = Tangent; LastPoint.LeaveTangent = Tangent; LastPoint.ArriveTangent = Tangent; } } const int32 NumSegments = NumPoints - 1; // Start by clearing it SplineReparamTable.Points.Reset(NumSegments * ReparamStepsPerSegment + 1); float AccumulatedLength = 0.0f; for (int32 SegmentIndex = 0; SegmentIndex < NumSegments; ++SegmentIndex) { for (int32 Step = 0; Step < ReparamStepsPerSegment; ++Step) { const float Param = static_cast<float>(Step) / ReparamStepsPerSegment; const float SegmentLength = (Step == 0) ? 0.0f : GetSegmentLength(SegmentIndex, Param); SplineReparamTable.AddPoint(SegmentLength + AccumulatedLength, SegmentIndex + Param); } AccumulatedLength += GetSegmentLength(SegmentIndex, 1.0f); } SplineReparamTable.AddPoint(AccumulatedLength, static_cast<float>(NumSegments)); }
unsigned int SVGMotionPath::GetSegmentIndexAtLength(SVGNumber len) { // FIXME: Return what index if input length > path length || input length < 0 ? // Returning last/first for now if (len < 0) return 0; if (m_vega_path && m_vega_line_segments > 0) { SVGNumber length_sum; unsigned int i = 0; length_sum = GetSegmentLength(i); while (len > length_sum && i < m_vega_line_segments) { i++; length_sum += GetSegmentLength(i); } if (i >= m_vega_line_segments) i = m_vega_line_segments-1; return i; } return 0; }
SVGNumber SVGMotionPath::GetAccumulatedSegmentLength(unsigned int idx) { if (m_vega_path && m_vega_line_segments > 0) { if (idx > m_vega_line_segments) idx = m_vega_line_segments; SVGNumber sum(0); for (unsigned int i = 0; i < idx; i++) { sum += GetSegmentLength(i); } return sum; } return 0; }
float USplineComponent::GetSegmentParamFromLength(const int32 Index, const float Length, const float SegmentLength) const { if (SegmentLength == 0.0f) { return 0.0f; } // Given a function P(x) which yields points along a spline with x = 0...1, we can define a function L(t) to be the // Euclidian length of the spline from P(0) to P(t): // // L(t) = integral of |dP/dt| dt // = integral of sqrt((dx/dt)^2 + (dy/dt)^2 + (dz/dt)^2) dt // // This method evaluates the inverse of this function, i.e. given a length d, it obtains a suitable value for t such that: // L(t) - d = 0 // // We use Newton-Raphson to iteratively converge on the result: // // t' = t - f(t) / (df/dt) // // where: t is an initial estimate of the result, obtained through basic linear interpolation, // f(t) is the function whose root we wish to find = L(t) - d, // (df/dt) = d(L(t))/dt = |dP/dt| const int32 NumPoints = SplineInfo.Points.Num(); const int32 LastPoint = NumPoints - 1; check(Index >= 0 && ((bClosedLoop && Index < NumPoints) || (!bClosedLoop && Index < LastPoint))); check(Length >= 0.0f && Length <= SegmentLength); check(Index == LastPoint || (static_cast<int32>(SplineInfo.Points[Index + 1].InVal) - static_cast<int32>(SplineInfo.Points[Index].InVal) == 1)); float Param = Length / SegmentLength; // initial estimate for t // two iterations of Newton-Raphson is enough for (int32 Iteration = 0; Iteration < 2; ++Iteration) { float TangentMagnitude = SplineInfo.EvalDerivative(Index + Param, FVector::ZeroVector).Size(); if (TangentMagnitude > 0.0f) { Param -= (GetSegmentLength(Index, Param) - Length) / TangentMagnitude; Param = FMath::Clamp(Param, 0.0f, 1.0f); } } return Param; }
OP_STATUS SVGMotionPath::CalculateCurrentDistanceAlongPath(PositionDescriptor& pos, SVGNumber& distance) { switch(pos.calcMode) { case SVGCALCMODE_PACED: { distance = pos.where * m_path_length; // Paced calculation mode ignores keyTimes and keyPoints return OpStatus::OK; } case SVGCALCMODE_SPLINE: case SVGCALCMODE_LINEAR: { SVGNumber c; if (pos.keyTimes == NULL || pos.keyPoints == NULL || pos.keyTimes->GetCount() == 0 || pos.keyPoints->GetCount() == 0) { unsigned int ic = m_path->GetCount(FALSE); // how many subintervals if(ic > 1) ic--; // avoid division-by-zero if(ic == 0) return OpSVGStatus::INVALID_ANIMATION; SVGNumber il = SVGNumber(1) / (SVGNumber(ic)); // how long are each SVGNumber q; unsigned int a; if (pos.where.Equal(1)) // special-treatment { q = 1; a = ic - 1; } else { SVGNumber r = pos.where % il; // how far along are we in the time subinterval q = r / il; // make that value relative (0-1) a = (unsigned int)(pos.where*ic).GetIntegerValue(); // which interval are we in } if (pos.calcMode == SVGCALCMODE_SPLINE) { q = CalculateKeySplines(pos, a, q); } SVGNumber p = GetSegmentLength(a); SVGNumber b = GetAccumulatedSegmentLength(a); c = b + q * p; // where are we in this interval } else { c = CalculateKeyTimes(pos) * m_vega_path_length; } distance = c / m_vega_path_length * m_path_length; return OpStatus::OK; } case SVGCALCMODE_DISCRETE: { unsigned int ic = m_path->GetCount(FALSE); // how many subintervals // avoid division-by-zero if(ic == 0) return OpSVGStatus::INVALID_ANIMATION; unsigned int a = (unsigned int)(pos.where * ic).GetIntegerValue(); SVGNumber b = GetAccumulatedSegmentLength(a); // how long are this interval relative to the total length SVGNumber c; if (pos.keyTimes == NULL || pos.keyPoints == NULL || pos.keyTimes->GetCount() == 0 || pos.keyPoints->GetCount() == 0) { c = b; } else { c = CalculateKeyTimes(pos) * m_vega_path_length; } SVGNumber next_where = SVGNumber(a + 1) / SVGNumber(ic); if (next_where > SVGNumber(1)) next_where = next_where - SVGNumber(1); pos.next_where = next_where; distance = c / m_vega_path_length * m_path_length; return OpStatus::OK; } default: break; } OP_ASSERT(!"Not reached"); return OpStatus::ERR; }
//Made from XC3S200_FT256 bit file //Code is based on code from http://panteltje.com/panteltje/raspberri_pi/ //And David Sullins BitInfo/BitFile code void parse_header(FILE *f) { //00 09 0F F0 0F F0 0F F0 0F F0 00 00 01 unsigned int XilinxID13[] = {0x00,0x09, 0x0F,0xF0, 0x0F,0xF0, 0x0F,0xF0, 0x0F,0xF0, 0x00,0x00,0x01}; unsigned int *HeaderBufferData; int segmentCheck = 0x61; //Start at a char(97) int segment = 0; int segmentLength = 0; int offset = 0; unsigned char tempChar; //First 13 bits, so far all Xilinx Bitstream files, start with XilinxID13 bytes //Seems to be identifier for bitfile creator int t, x; HeaderBufferData = (unsigned int*)malloc( sizeof(unsigned int) *13); for(t=0; t<13; t++) HeaderBufferData[t] = fgetc(f); if(0==memcmp(HeaderBufferData,XilinxID13,sizeof(HeaderBufferData)*13)) bitFileId = XILINX_BITFILE; else bitFileId = 0; //if(0==memcmp(HeaderBufferData,XilinxID13,sizeof(HeaderBufferData)*13)) bitFileId = Altera_BITFILE; else bitFileId = 0; //Future stuff free(HeaderBufferData); fprintf(stderr, "Bitfile type: %d\n",bitFileId); bitfileinfo.BitFile_Type = bitFileId; //---------------------------------------------------------------------- segmentLength = GetSegmentLength(segment,segmentCheck,f); segmentCheck++; fprintf(stderr, "Design Name: "); bitfileinfo.DesignName = (char*)malloc(sizeof(char)*segmentLength); for(x = 0; x < segmentLength; x++) { bitfileinfo.DesignName[x] = fgetc(f); } fprintf(stderr, "%s\n",bitfileinfo.DesignName); //---------------------------------------------------------------------- segmentLength = GetSegmentLength(segment,segmentCheck,f); segmentCheck++; fprintf(stderr, "Device: "); if(bitFileId==XILINX_BITFILE) { bitfileinfo.DeviceName = (char*)malloc(sizeof(char)*(segmentLength+2)); bitfileinfo.DeviceName[0] = 'x'; //Xilinx XC not stored in bit file bitfileinfo.DeviceName[1] = 'c'; offset=2; } else { bitfileinfo.DeviceName = (char*)malloc(sizeof(char)*segmentLength); offset=0; } for(x = 0; x < segmentLength; x++) { bitfileinfo.DeviceName[x+offset] = fgetc(f); } fprintf(stderr, "%s\n",bitfileinfo.DeviceName); //---------------------------------------------------------------------- segmentLength = GetSegmentLength(segment,segmentCheck,f); segmentCheck++; fprintf(stderr, "Date: "); for(x = 0; x < segmentLength; x++) { tempChar = fgetc(f); fprintf(stderr, "%c", tempChar); } fprintf(stderr, "\n"); //---------------------------------------------------------------------- segmentLength = GetSegmentLength(segment,segmentCheck,f); segmentCheck++; fprintf(stderr, "Time: "); for(x = 0; x < segmentLength; x++) { tempChar = fgetc(f); fprintf(stderr, "%c", tempChar); } fprintf(stderr, "\n"); //---------------------------------------------------------------------- segment = fgetc(f); if(segment != segmentCheck) fprintf(stderr, "Error in header segment: %d, should be %d\n",segment,segmentCheck); segmentLength = (fgetc(f) << 24) + (fgetc(f) << 16) + (fgetc(f) << 8) + fgetc(f); fprintf(stderr, "Bitstream Length: %0d bits\n", segmentLength * 8); bitfileinfo.Bitstream_Length = segmentLength; //That's it for now, bitfile header info is stored in bitfileinfo, FILE *f, needs to be kept until we program //This leaves us at 0xFF FF FF FF (Dummy Word) and the Sync Cmd 0xAA 99 55 66 (XILINX) }