/// <inheritdoc /> public override List <Vertex> GenerateVertexList(int resolutionU, int resolutionV) { // Generate the vertices of two end caps, and a shaft in between: List <Vertex> startCapList = startCap.GenerateVertexList(resolutionU, resolutionU / 4); List <Vertex> endCapList = endCap.GenerateVertexList(resolutionU, resolutionU / 4); // Using a slice, remove the first and last ring of vertices of the shaft, which overlap with the last // rings of the startCap and endCap respectively. Later we will stitch the shaft and end caps together with // triangles between them, during the GenerateIndexList() step. Slice <Vertex> shaftSlice = new Slice <Vertex>( shaft.GenerateVertexList(resolutionU, resolutionV), resolutionU, Cylinder.CalculateVertexCount(resolutionU, resolutionV) - 2 * resolutionU); // Recalculate the surface normal between the cylinder and the start cap: for (int i = 0; i < (resolutionU - 1); i++) { dvec3 surfacePosition = startCapList[(resolutionU / 4 - 1) * resolutionU + i + 1].Position; dvec3 du = surfacePosition - startCapList[(resolutionU / 4 - 1) * resolutionU + i + 1 + 1].Position; dvec3 dv = surfacePosition - shaftSlice[i].Position; // Calculate the position of the rings of vertices: dvec3 surfaceNormal = dvec3.Cross(du.Normalized, dv.Normalized); startCapList[(resolutionU / 4 - 1) * resolutionU + i + 1] = new Vertex((vec3)surfacePosition, (vec3)surfaceNormal); } // Stitch the end of the triangles: dvec3 surfacePosition2 = startCapList[(resolutionU / 4 - 1) * resolutionU + resolutionU].Position; dvec3 du2 = surfacePosition2 - startCapList[(resolutionU / 4 - 1) * resolutionU + 1].Position; dvec3 dv2 = surfacePosition2 - shaftSlice[resolutionU].Position; // Calculate the position of the rings of vertices: dvec3 surfaceNormal2 = dvec3.Cross(du2.Normalized, dv2.Normalized); startCapList[(resolutionU / 4 - 1) * resolutionU + resolutionU] = new Vertex((vec3)surfacePosition2, (vec3)surfaceNormal2); return(startCapList.Concat(shaftSlice).Concat(endCapList).ToList()); }
/// <summary> /// Construct a new <c>Capsule</c> around a central curve, the <c>centerCurve</c>. /// The radius at each point on the central axis is defined by a one-dimensional function <c>radius</c>. /// /// The surface is parametrized with the coordinates \f$u, \phi\f$, with \f$u\f (along the length of the /// shaft) and \f$\phi \in [0, 2 \pi]\f$ along the radial coordinate. A <c>Capsule</c> consists of a /// cylindrical shaft with two hemisphere end caps. $\f$u \in [-\frac{1}{2} \pi, 0]\f$ marks the region /// in parametrized coordinates of the hemisphere at the start point of the cylinder, /// $\f$u \in [0, 1]\f$ marks the region in parametrized coordinates of the central shaft, /// and $\f$u \in [1, 1 + \frac{1}{2} \pi]\f$ marks the region in parametrized coordinates of the hemisphere /// at the end point of the cylinder. The <c>heightMap</c> is a two-dimensional function defined on these /// coordinates on the domain given above. /// </summary> /// <param name="centerCurve"> /// <inheritdoc cref="Capsule.CenterCurve"/> /// </param> /// <param name="heightMap"> /// The radius at each point on the surface. A <c>Capsule</c> is generated around a central curve, with each /// point on the surface at a certain distance from the curve defined by <c>heightMap</c>. <c>heightMap</c> /// is therefore a two-dimensional function $h(u, \phi)$ that outputs a distance from the curve at each of /// the surface's parametric coordinates. /// </param> public Capsule(Curve centerCurve, ContinuousMap <Vector2, float> heightMap) { Vector3 startTangent = -centerCurve.GetTangentAt(0.0f); Vector3 startNormal = centerCurve.GetNormalAt(0.0f); Vector3 endTangent = centerCurve.GetTangentAt(1.0f); Vector3 endNormal = centerCurve.GetNormalAt(1.0f); this.shaft = new Cylinder(centerCurve, heightMap); this.startCap = new Hemisphere( new ShiftedMap2D <float>(new Vector2(0.0f, -0.5f * (float)Math.PI), heightMap), centerCurve.GetStartPosition(), startTangent, startNormal, -Vector3.Cross(startTangent, startNormal) ); this.endCap = new Hemisphere( new ShiftedMap2D <float>(new Vector2(0.0f, 1.0f + 0.5f * (float)Math.PI), new Vector2(1.0f, -1.0f), heightMap), centerCurve.GetEndPosition(), endTangent, endNormal, -Vector3.Cross(endTangent, endNormal) ); }
/// <summary> /// Construct a new <c>Capsule</c> around a central curve, the <c>centerCurve</c>. /// The radius at each point on the central axis is defined by a one-dimensional function <c>radius</c>. /// /// The surface is parametrized with the coordinates \f$u, \phi\f$, with \f$u\f (along the length of the /// shaft) and \f$\phi \in [0, 2 \pi]\f$ along the radial coordinate. A <c>Capsule</c> consists of a /// cylindrical shaft with two hemisphere end caps. $\f$u \in [-\frac{1}{2} \pi, 0]\f$ marks the region /// in parametrized coordinates of the hemisphere at the start point of the cylinder, /// $\f$u \in [0, 1]\f$ marks the region in parametrized coordinates of the central shaft, /// and $\f$u \in [1, 1 + \frac{1}{2} \pi]\f$ marks the region in parametrized coordinates of the hemisphere /// at the end point of the cylinder. The <c>heightMap</c> is a two-dimensional function defined on these /// coordinates on the domain given above. /// </summary> /// <param name="centerCurve"> /// <inheritdoc cref="Capsule.CenterCurve"/> /// </param> /// <param name="heightMap"> /// The radius at each point on the surface. A <c>Capsule</c> is generated around a central curve, with each /// point on the surface at a certain distance from the curve defined by <c>heightMap</c>. <c>heightMap</c> /// is therefore a two-dimensional function $h(u, \phi)$ that outputs a distance from the curve at each of /// the surface's parametric coordinates. /// </param> public Capsule(Curve centerCurve, ContinuousMap <dvec2, double> heightMap) { dvec3 startTangent = -centerCurve.GetTangentAt(0.0); dvec3 startNormal = centerCurve.GetNormalAt(0.0); dvec3 endTangent = centerCurve.GetTangentAt(1.0); dvec3 endNormal = centerCurve.GetNormalAt(1.0); this.shaft = new Cylinder(centerCurve, heightMap); this.startCap = new Hemisphere( new ShiftedMap2D <double>(new dvec2(0.0, -0.5 * Math.PI), heightMap), centerCurve.GetStartPosition(), startTangent, startNormal, -dvec3.Cross(startTangent, startNormal) ); this.endCap = new Hemisphere( new ShiftedMap2D <double>(new dvec2(0.0, 1.0 + 0.5 * Math.PI), new dvec2(1.0, -1.0), heightMap), centerCurve.GetEndPosition(), endTangent, endNormal, -dvec3.Cross(endTangent, endNormal) ); }