Пример #1
0
// Construct a NurbsSurface by lofting between a collection of curves
//
// **params**
// + A collection of curves
//
// **returns**
// + A new NurbsSurface
func loftedSurface(curves []*verb.NurbsCurve, _degreeV *int) *verb.NurbsSurface {
	curves = verb.UnifyCurveKnotVectors(curves)

	// degree
	degreeU := curves[0].Degree()

	var degreeV int
	if _degreeV == nil {
		degreeV = 3
	} else {
		degreeV = *_degreeV
	}

	if degreeV > len(curves)-1 {
		degreeV = len(curves) - 1
	}

	// knots
	knotsU := curves[0].Knots()
	var knotsV KnotVec

	crvCtrlPts := make([][]vec3.T, len(curves))
	for i := range crvCtrlPts {
		crvCtrlPts[i] = curves[i].ControlPoints()
	}

	controlPoints := make([][]vec3.T, len(crvCtrlPts[0]))
	weights := make([][]float64, len(controlPoints))
	for i := range crvCtrlPts[0] {
		// extract the ith control pt of each curve
		points := make([]vec3.T, len(crvCtrlPts))
		for j, ctrlPts := range crvCtrlPts {
			points[j] = ctrlPts[i]
		}

		// construct an interpolating curve using this list
		_, controlPoints[i], weights[i], knotsV =
			interpCurve(points, degreeV, nil, nil)
		// computing knotsV is redundant
	}

	return verb.NewNurbsSurfaceUnchecked(degreeU, degreeV, controlPoints, weights, knotsU, knotsV)
}
Пример #2
0
// Generate the control points, weights, and knots of a surface defined by 4 points
//
// **params**
// + first point in counter-clockwise form
// + second point in counter-clockwise form
// + third point in counter-clockwise form
// + forth point in counter-clockwise form
//
// **returns**
// + NurbsSurfaceData object
func FourPointSurface(p1, p2, p3, p4 *vec3.T, _degree *int) *verb.NurbsSurface {
	var degree int
	if _degree == nil {
		degree = 3
	} else {
		degree = *_degree
	}
	degreeFloat := float64(degree)

	pts := make([][]vec3.T, degree+1)
	for i := range pts {
		iFloat := float64(i)

		row := make([]vec3.T, degree+1)
		for j := range row {
			l := 1 - iFloat/degreeFloat
			p1p2 := vec3.Interpolate(p1, p2, l)
			p4p3 := vec3.Interpolate(p4, p3, l)

			row[j] = vec3.Interpolate(&p1p2, &p4p3, 1-float64(j)/degreeFloat)
		}

		pts[i] = row
	}

	// build uniform weights
	weightRow := make([]float64, degree+1)
	for i := range weightRow {
		weightRow[i] = 1
	}
	weights := make([][]float64, degree+1)
	for i := range weights {
		weights[i] = weightRow
	}

	knots := make([]float64, 2*(degree+1))
	for i := degree + 1; i < len(knots); i++ {
		knots[i] = 1
	}

	return verb.NewNurbsSurfaceUnchecked(degree, degree, pts, weights, knots, knots)
}
Пример #3
0
// Generate the control points, weights, and knots of a revolved surface
// (Corresponds to Algorithm A7.1 from Piegl & Tiller)
//
// **params**
// + center of the rotation axis
// + axis of the rotation axis
// + angle to revolve around axis
// + degree of the generatrix
// + control points of the generatrix
// + weights of the generatrix
//
// **returns**
// + an object with the following properties: controlPoints, weights, knots, degree
func RevolvedSurface(profile *verb.NurbsCurve, center *vec3.T, axis *vec3.T, theta float64) *verb.NurbsSurface {
	prof_controlPoints := profile.ControlPoints()
	prof_weights := profile.Weights()

	var narcs int
	var knotsU []float64

	switch {
	case theta <= math.Pi/2:
		{ // less than 90
			narcs = 1
			knotsU = make([]float64, 6+2*(narcs-1))
		}
	case theta <= math.Pi:
		{ // between 90 and 180
			narcs = 2
			knotsU = make([]float64, 6+2*(narcs-1))
			knotsU[3], knotsU[4] = 0.5, 0.5
		}
	case theta <= 3*math.Pi/2:
		{ // between 180 and 270
			narcs = 3
			knotsU = make([]float64, 6+2*(narcs-1))
			knotsU[3], knotsU[4] = 1/3, 1/3
			knotsU[5], knotsU[6] = 2/3, 2/3
		}
	default:
		{ // between 270 and 360
			narcs = 4
			knotsU = make([]float64, 6+2*(narcs-1))
			knotsU[3], knotsU[4] = 1/4, 1/4
			knotsU[5], knotsU[6] = 1/2, 1/2
			knotsU[7], knotsU[8] = 3/4, 3/4
		}
	}

	dtheta := theta / float64(narcs) // divide the interval into several points
	j := 3 + 2*(narcs-1)

	// initialize the start and end knots
	// keep in mind that we only return the knot vector for thes
	for i := 0; i < 3; i++ {
		knotsU[j+i] = 1
	}

	// do some initialization
	wm := math.Cos(dtheta / 2)
	sines, cosines := make([]float64, narcs+1), make([]float64, narcs+1)

	controlPoints := make([][]vec3.T, 2*narcs+1)
	for i := range controlPoints {
		controlPoints[i] = make([]vec3.T, len(prof_controlPoints))
	}

	weights := make([][]float64, 2*narcs+1)
	for i := range weights {
		weights[i] = make([]float64, len(prof_controlPoints))
	}

	// initialize the sines and cosines
	var angle float64
	for i := 1; i <= narcs; i++ {
		angle += dtheta
		cosines[i] = math.Cos(angle)
		sines[i] = math.Sin(angle)
	}

	// for each pt in the generatrix
	// i.e. for each row of the 2d knot vectors
	for j := range prof_controlPoints {
		// get the closest point of the generatrix point on the axis
		O := rayClosestPoint(prof_controlPoints[j], center, axis)
		// X is the vector from the axis to generatrix control pt
		X := vec3.Sub(&prof_controlPoints[j], &O)
		// radius at that height
		r := X.Length()
		// Y is perpendicular to X and axis, and complete the coordinate system
		Y := vec3.Cross(axis, &X)

		if r > internal.Epsilon {
			X.Scale(1 / r)
			Y.Scale(1 / r)
		}

		// the first row of controlPoints and weights is just the generatrix
		controlPoints[0][j] = prof_controlPoints[j]
		P0 := prof_controlPoints[j]
		weights[0][j] = prof_weights[j]

		// store T0 as the Y vector
		var T0 = Y
		var index int

		// proceed around the circle
		for i := 1; i <= narcs; i++ {
			// O + r * cos(theta) * X + r * sin(theta) * Y
			// rotated generatrix pt
			var P2 vec3.T
			if r == 0 {
				P2 = O
			} else {
				xCompon := X.Scaled(r * cosines[i])
				yCompon := Y.Scaled(r * sines[i])
				offset := xCompon.Add(&yCompon)
				P2 = vec3.Add(&O, offset)
			}

			controlPoints[index+2][j] = P2
			weights[index+2][j] = prof_weights[j]

			// construct the vector tangent to the rotation
			temp0 := Y.Scaled(cosines[i])
			temp1 := X.Scaled(sines[i])
			T2 := temp0.Sub(&temp1)

			// construct the next control pt
			if r == 0 {
				controlPoints[index+1][j] = O
			} else {
				T0Norm := T0.Normalized()
				T2Norm := T2.Normalized()
				inters := intersect.Rays(&P0, &T0Norm, &P2, &T2Norm)

				T0Scaled := T0.Scaled(inters.U0)
				P1 := T0Scaled.Add(&P0)

				controlPoints[index+1][j] = *P1
			}

			weights[index+1][j] = wm * prof_weights[j]

			index += 2

			if i < narcs {
				P0 = P2
				T0 = *T2
			}
		}
	}

	return verb.NewNurbsSurfaceUnchecked(2, profile.Degree(), controlPoints, weights, knotsU, profile.Knots())
}