Пример #1
0
func (this *Mesh) TriangleUvFromPoint(faceIndex int, f *vec3.T) verb.UV {
	tri := this.Faces[faceIndex]

	p0 := this.Points[tri[0]]
	p1 := this.Points[tri[1]]
	p2 := this.Points[tri[2]]

	uv0 := this.UVs[tri[0]]
	uv1 := this.UVs[tri[1]]
	uv2 := this.UVs[tri[2]]

	f0 := vec3.Sub(&p0, f)
	f1 := vec3.Sub(&p1, f)
	f2 := vec3.Sub(&p2, f)

	// calculate the areas and factors (order of parameters doesn't matter):
	p1.Sub(&p0)
	p2.Sub(&p0)
	aVec := vec3.Cross(&p1, &p2)
	a := aVec.Length()

	a0Vec := vec3.Cross(&f1, &f2)
	a1Vec := vec3.Cross(&f2, &f0)
	a2Vec := vec3.Cross(&f0, &f1)

	a0 := a0Vec.Length() / a
	a1 := a1Vec.Length() / a
	a2 := a2Vec.Length() / a

	// find the uv corresponding to point f (uv1/uv2/uv3 are associated to p1/p2/p3):
	return verb.UV{
		a0*uv0[0] + a1*uv1[0] + a2*uv2[0],
		a0*uv0[1] + a1*uv1[1] + a2*uv2[1],
	}
}
Пример #2
0
func (this Line) SameSide(p0, p1 vec3.T) bool {
	lineVec := vec3.Sub(&this[1], &this[0])
	p0Vec := vec3.Sub(&p0, &this[0])
	p1Vec := vec3.Sub(&p1, &this[0])

	cp0 := vec3.Cross(&p0Vec, &lineVec)
	cp1 := vec3.Cross(&p1Vec, &lineVec)

	return vec3.Dot(&cp0, &cp1) >= 0
}
Пример #3
0
// Vec3Diff returns the rotation quaternion between two vectors.
func Vec3Diff(a, b *vec3.T) T {
	cr := vec3.Cross(a, b)
	sr := math.Sqrt(2 * (1 + vec3.Dot(a, b)))
	oosr := 1 / sr

	q := T{cr[0] * oosr, cr[1] * oosr, cr[2] * oosr, sr * 0.5}
	return q.Normalized()
}
Пример #4
0
func (this Triangle) Plane() Plane {
	v0, v1, v2 := this[0], this[1], this[2]
	normal := vec3.Cross(v1.Sub(&v0), (v2.Sub(&v0)))

	invNormal := normal.Scaled(-1)
	offset := vec3.Dot(&invNormal, &v0)

	return Plane{normal, offset}
}
Пример #5
0
// Determine if three points form a straight line within a given tolerance for their 2 * squared area
//
//          * p2
//         / \
//        /   \
//       /     \
//      /       \
//     * p1 ---- * p3
//
// The area metric is 2 * the squared norm of the cross product of two edges, requiring no square roots and no divisions
//
// **params**
// + p1
// + p2
// + p3
// + The tolerance
//
// **returns**
// + Whether the triangle passes the test
//
func threePointsAreCollinear(p1, p2, p3 *vec3.T, tol float64) bool {
	// find the area of the triangle without using a square root
	p2mp1 := vec3.Sub(p2, p1)
	p3mp1 := vec3.Sub(p3, p1)
	norm := vec3.Cross(&p2mp1, &p3mp1)
	area := vec3.Dot(&norm, &norm)

	return area < tol
}
Пример #6
0
//
// Tessellate a NURBS surface on equal spaced intervals in the parametric domain
//
// **params**
// + NurbsSurfaceData object
// + number of divisions in the u direction
// + number of divisions in the v direction
//
// **returns**
// + MeshData object
//
func (this *NurbsSurface) tessellateNaive(divsU, divsV int) *Mesh {
	if divsU < 1 {
		divsU = 1
	}
	if divsV < 1 {
		divsV = 1
	}

	//degreeU, degreeV := this.DegreeU, this.DegreeV
	//controlPoints := this.ControlPoints
	knotsU, knotsV := this.knotsU, this.knotsV

	uSpan := knotsU[len(knotsU)-1] - knotsU[0]
	vSpan := knotsV[len(knotsV)-1] - knotsV[0]

	spanU := uSpan / float64(divsU)
	spanV := vSpan / float64(divsV)

	numPoints := (divsU + 1) * (divsV + 1)
	points := make([]vec3.T, numPoints)
	uvs := make([]UV, numPoints)
	normals := make([]vec3.T, 0, numPoints)

	var counter int
	for i := 0; i <= divsU; i++ {
		for j := 0; j <= divsV; j++ {
			uv := UV{float64(i) * spanU, float64(j) * spanV}
			uvs[counter] = uv

			derivs := this.Derivatives(uv, 1)
			pt := derivs[0][0]
			points[counter] = pt

			normal := vec3.Cross(&derivs[1][0], &derivs[0][1])
			normals = append(normals, *normal.Normalize())

			counter++
		}
	}

	faces := make([]Tri, 0, 2*divsU*divsV)

	for i := 0; i < divsU; i++ {
		for j := 0; j < divsV; j++ {
			ai := i*(divsV+1) + j
			bi := (i+1)*(divsV+1) + j
			ci := bi + 1
			di := ai + 1
			abc := Tri{ai, bi, ci}
			acd := Tri{ai, ci, di}

			faces = append(faces, abc, acd)
		}
	}

	return &Mesh{faces, points, normals, uvs}
}
Пример #7
0
//
// Get triangle normal
//
// **params**
// + array of length 3 arrays of numbers representing the points
// + length 3 array of point indices for the triangle
//
// **returns**
// + a normal vector represented by an array of length 3
//
func TriangleNormal(points []vec3.T, tri *verb.Tri) vec3.T {
	v0 := points[tri[0]]
	v1 := points[tri[1]]
	v2 := points[tri[2]]

	v1.Sub(&v0)
	v2.Sub(&v0)
	n := vec3.Cross(&v1, &v2)

	return *n.Normalize()
}
Пример #8
0
func (this *adaptiveRefinementNode) EvalSrf(uv UV) *SurfacePoint {
	derivs := this.srf.Derivatives(uv, 1)
	pt := derivs[0][0]
	norm := vec3.Cross(&derivs[0][1], &derivs[1][0])

	degen := true
	for _, compon := range norm {
		if math.Abs(compon) > this.tolerance {
			degen = false
			break
		}
	}

	if !degen {
		norm.Normalize()
	}

	return &SurfacePoint{uv, &pt, &norm, -1, degen}
}
Пример #9
0
// Cross returns the cross product of two vectors.
func Cross(a, b *T) T {
	a3 := a.Vec3DividedByW()
	b3 := b.Vec3DividedByW()
	c3 := vec3.Cross(&a3, &b3)
	return T{c3[0], c3[1], c3[2], 1}
}
Пример #10
0
// Compute the derivatives at a point on a NURBS surface
//
// **params**
// + NurbsSurfaceData object representing the surface
// + u parameter
// + v parameter
//
// **returns**
// + a Vector represented by an array of length (dim)
func (this *NurbsSurface) Normal(uv UV) vec3.T {
	derivs := this.Derivatives(uv, 1)
	return vec3.Cross(&derivs[1][0], &derivs[0][1])
}
Пример #11
0
//
// Divide a NURBS surface int equal spaced intervals in the parametric domain as AdaptiveRefinementNodes
//
// **params**
// + NurbsSurfaceData object
// + SurfaceDivideOptions object
//
// **returns**
// + MeshData object
//
func (this *NurbsSurface) adaptiveDivisions(options *adaptiveRefinementOptions) []*adaptiveRefinementNode {
	if options == nil {
		options = &defaultAdaptiveRefinementOptions
	}

	minU := (len(this.controlPoints) - 1) * 2
	minV := (len(this.controlPoints[0]) - 1) * 2

	var divsU, divsV int
	if options.MinDivsU > minU {
		divsU = options.MinDivsU
	} else {
		divsU = minU
	}
	if options.MinDivsU > minV {
		divsV = options.MinDivsV
	} else {
		divsV = minV
	}

	// get necessary intervals
	umax := this.knotsU[len(this.knotsU)-1]
	umin := this.knotsU[0]
	vmax := this.knotsV[len(this.knotsV)-1]
	vmin := this.knotsV[0]

	du := (umax - umin) / float64(divsU)
	dv := (vmax - vmin) / float64(divsV)

	pts := make([][]*SurfacePoint, divsV+1)

	// 1) evaluate all of the corners
	for i := range pts {
		ptrow := make([]*SurfacePoint, divsU+1)
		for j := range ptrow {
			uv := UV{umin + du*float64(j), vmin + dv*float64(i)}

			// todo: make this faster by specifying n,m
			ds := this.Derivatives(uv, 1)

			norm := vec3.Cross(&ds[0][1], &ds[1][0])
			norm.Normalize()

			degen := true
			for _, compon := range norm {
				if math.Abs(compon) > Tolerance {
					degen = false
					break
				}
			}
			ptrow[j] = &SurfacePoint{uv, &ds[0][0], &norm, -1, degen}
		}
		pts[i] = ptrow
	}

	divs := make([]*adaptiveRefinementNode, divsU*divsV)

	// 2) make all of the nodes
	var divsI int
	for i := 0; i < divsV; i++ {
		for j := 0; j < divsU; j++ {
			corners := [4]*SurfacePoint{
				pts[divsV-i-1][j],
				pts[divsV-i-1][j+1],
				pts[divsV-i][j+1],
				pts[divsV-i][j],
			}

			divs[divsI] = newAdaptiveRefinementNode(this, &corners, nil)
			divsI++
		}
	}

	if !options.Refine {
		return divs
	}

	// 3) assign all of the neighbors and divide
	for i := 0; i < divsV; i++ {
		for j := 0; j < divsU; j++ {
			ci := i*divsU + j
			n := north(ci, i, j, divsU, divsV, divs)
			e := east(ci, i, j, divsU, divsV, divs)
			s := south(ci, i, j, divsU, divsV, divs)
			w := west(ci, i, j, divsU, divsV, divs)

			divs[ci].Neighbors = [4]*adaptiveRefinementNode{s, e, n, w}
			divs[ci].Divide(options)
		}
	}

	return divs
}
Пример #12
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())
}