Ejemplo n.º 1
0
// TODO: this serves a similar purpose to SplitLine above, but is more general. Also, SplitLine seems to be implemented more
// efficiently, might be nice to take some cues from it
void SimRender::SubdividePoints(std::vector<CVector2D>& points, float maxSegmentLength, bool closed)
{
	size_t numControlPoints = points.size();
	if (numControlPoints < 2)
		return;

	ENSURE(maxSegmentLength > 0);

	size_t endIndex = numControlPoints;
	if (!closed && numControlPoints > 2)
		endIndex--;

	std::vector<CVector2D> newPoints;

	for (size_t i = 0; i < endIndex; i++)
	{
		const CVector2D& curPoint = points[i];
		const CVector2D& nextPoint = points[(i+1) % numControlPoints];
		const CVector2D line(nextPoint - curPoint);
		CVector2D lineDirection = line.Normalized();

		// include control point i + a list of intermediate points between i and i + 1 (excluding i+1 itself)
		newPoints.push_back(curPoint);

		// calculate how many intermediate points are needed so that each segment is of length <= maxSegmentLength
		float lineLength = line.Length();
		size_t numSegments = (size_t) ceilf(lineLength / maxSegmentLength);
		float segmentLength = lineLength / numSegments;

		for (size_t s = 1; s < numSegments; ++s) // start at one, we already included curPoint
		{
			newPoints.push_back(curPoint + lineDirection * (s * segmentLength));
		}
	}

	points.swap(newPoints);
}
Ejemplo n.º 2
0
void SimRender::ConstructDashedLine(const std::vector<CVector2D>& keyPoints, SDashedLine& dashedLineOut, const float dashLength, const float blankLength)
{
	// sanity checks
	if (dashLength <= 0)
		return;

	if (blankLength <= 0)
		return;

	if (keyPoints.size() < 2)
		return;

	dashedLineOut.m_Points.clear();
	dashedLineOut.m_StartIndices.clear();

	// walk the line, counting the total length so far at each node point. When the length exceeds dashLength, cut the last segment at the
	// required length and continue for blankLength along the line to start a new dash segment.

	// TODO: we should probably extend this function to also allow for closed lines. I was thinking of slightly scaling the dash/blank length
	// so that it fits the length of the curve, but that requires knowing the length of the curve upfront which is sort of expensive to compute
	// (O(n) and lots of square roots).

	bool buildingDash = true; // true if we're building a dash, false if a blank
	float curDashLength = 0; // builds up the current dash/blank's length as we walk through the line nodes
	CVector2D dashLastPoint = keyPoints[0]; // last point of the current dash/blank being built.

	// register the first starting node of the first dash
	dashedLineOut.m_Points.push_back(keyPoints[0]);
	dashedLineOut.m_StartIndices.push_back(0);

	// index of the next key point on the path. Must always point to a node that is further along the path than dashLastPoint, so we can
	// properly take a direction vector along the path.
	size_t i = 0;

	while(i < keyPoints.size() - 1)
	{
		// get length of this segment
		CVector2D segmentVector = keyPoints[i + 1] - dashLastPoint; // vector from our current point along the path to nextNode
		float segmentLength = segmentVector.Length();

		float targetLength = (buildingDash ? dashLength : blankLength);
		if (curDashLength + segmentLength > targetLength)
		{
			// segment is longer than the dash length we still have to go, so we'll need to cut it; create a cut point along the segment
			// line that is of just the required length to complete the dash, then make it the base point for the next dash/blank.
			float cutLength = targetLength - curDashLength;
			CVector2D cutPoint = dashLastPoint + (segmentVector.Normalized() * cutLength);

			// start a new dash or blank in the next iteration
			curDashLength = 0;
			buildingDash = !buildingDash; // flip from dash to blank and vice-versa
			dashLastPoint = cutPoint;

			// don't increment i, we haven't fully traversed this segment yet so we still need to use the same point to take the
			// direction vector with in the next iteration

			// this cut point is either the end of the current dash or the beginning of a new dash; either way, we're gonna need it
			// in the points array.
			dashedLineOut.m_Points.push_back(cutPoint);

			if (buildingDash)
			{
				// if we're gonna be building a new dash, then cutPoint is now the base point of that new dash, so let's register its
				// index as a start index of a dash.
				dashedLineOut.m_StartIndices.push_back(dashedLineOut.m_Points.size() - 1);
			}

		}
		else
		{
			// the segment from lastDashPoint to keyPoints[i+1] doesn't suffice to complete the dash, so we need to add keyPoints[i+1]
			// to this dash's points and continue from there

			if (buildingDash)
				// still building the dash, add it to the output (we don't need to store the blanks)
				dashedLineOut.m_Points.push_back(keyPoints[i+1]);

			curDashLength += segmentLength;
			dashLastPoint = keyPoints[i+1];
			i++;

		}

	}

}