Esempio n. 1
0
/**
 * Create a set of points on the heightfield for a 2D polyline by draping the point onto
 * the surface.
 *
 * \param line	The 2D line to drape, in Earth coordinates.
 * \param fSpacing	The approximate spacing of the surface tessellation, used to
 *		decide how finely to tessellate the line.
 * \param fOffset	An offset to elevate each point in the resulting geometry,
 *		useful for keeping it visibly above the ground.
 * \param bInterp	True to interpolate between the vertices of the input
 *		line. This is generally desirable when the ground is much more finely
 *		spaced than the input line.
 * \param bCurve	True to interpret the vertices of the input line as
 *		control points of a curve.  The created geometry will consist of
 *		a draped line which passes through the control points.
 * \param bTrue		True to use the true elevation of the terrain, ignoring
 *		whatever scale factor is being used to exaggerate elevation for
 *		display.
 * \param output	Received the points.
 * \return The approximate length of the resulting 3D polyline.
 */
float vtHeightField3d::LineOnSurface(const DLine2 &line, float fSpacing, float fOffset,
	bool bInterp, bool bCurve, bool bTrue, FLine3 &output)
{
	uint i, j;
	FPoint3 v1, v2, v;

	float fTotalLength = 0.0f;
	int iVerts = 0;
	uint points = line.GetSize();
	if (bCurve)
	{
		DPoint2 p2, last(1E9,1E9);
		DPoint3 p3;

		int spline_points = 0;
		CubicSpline spline;
		for (i = 0; i < points; i++)
		{
			p2 = line[i];
			if (i > 1 && p2 == last)
				continue;
			p3.Set(p2.x, p2.y, 0);
			spline.AddPoint(p3);
			spline_points++;
			last = p2;
		}
		spline.Generate();

		// Estimate how many steps to subdivide this line into
		const double dLinearLength = line.Length();
		float fLinearLength, dummy;
		m_LocalCS.VectorEarthToLocal(DPoint2(dLinearLength, 0.0), fLinearLength, dummy);
		double full = (double) (spline_points-1);
		int iSteps = (uint) (fLinearLength / fSpacing);
		if (iSteps < 3)
			iSteps = 3;
		double dStep = full / iSteps;

		FPoint3 last_v;
		for (double f = 0; f <= full; f += dStep)
		{
			spline.Interpolate(f, &p3);

			m_LocalCS.EarthToLocal(p3.x, p3.y, v.x, v.z);
			FindAltitudeAtPoint(v, v.y, bTrue);
			v.y += fOffset;
			output.Append(v);
			iVerts++;

			// keep a running total of approximate ground length
			if (f > 0)
				fTotalLength += (v - last_v).Length();
			last_v = v;
		}
	}
	else
	{
		// not curved: straight line in earth coordinates
		FPoint3 last_v;
		for (i = 0; i < points; i++)
		{
			if (bInterp)
			{
				v1 = v2;
				m_LocalCS.EarthToLocal(line[i].x, line[i].y, v2.x, v2.z);
				if (i == 0)
					continue;

				// estimate how many steps to subdivide this segment into
				FPoint3 diff = v2 - v1;
				float fLen = diff.Length();
				uint iSteps = (uint) (fLen / fSpacing);
				if (iSteps < 1) iSteps = 1;

				for (j = (i == 1 ? 0:1); j <= iSteps; j++)
				{
					// simple linear interpolation of the ground coordinate
					v.Set(v1.x + diff.x / iSteps * j, 0.0f, v1.z + diff.z / iSteps * j);
					FindAltitudeAtPoint(v, v.y, bTrue);
					v.y += fOffset;
					output.Append(v);
					iVerts++;

					// keep a running total of approximate ground length
					if (j > 0)
						fTotalLength += (v - last_v).Length();
					last_v = v;
				}
			}
			else
			{
				m_LocalCS.EarthToLocal(line[i], v.x, v.z);
				FindAltitudeAtPoint(v, v.y, bTrue);
				v.y += fOffset;
				output.Append(v);
			}
		}
	}
	return fTotalLength;
}