Ejemplo n.º 1
0
class Srf:
    '''Construct a NURB surface structure, and check the format.
    
 The NURB surface is represented by a 4 dimensional b-spline.

 INPUT:

    cntrl  - Control points, homogeneous coordinates (wx,wy,wz,w)
        For a surface [dim,nu,nv] matrix
            where nu  is along the u direction and
            nv  is along the v direction.
            dim is the dimension valid options are:
            2 .... (x,y)        2D cartesian coordinates
            3 .... (x,y,z)      3D cartesian coordinates   
            4 .... (wx,wy,wz,w) 4D homogeneous coordinates

    uknots - Knot sequence along the parametric u direction.
    vknots - Knot sequence along the paramteric v direction.

 NOTES:

    Its assumed that the input knot sequences span the
    interval [0.0,1.0] and are clamped to the control
    points at the end by a knot multiplicity equal to
    the spline order.'''
    def __init__(self, cntrl, uknots, vknots):
        self._bezier = None
        cntrl = numerix.asarray(cntrl, numerix.Float)
        (dim, nu, nv) = cntrl.shape
        if dim < 2 or dim > 4:
            raise NURBSError, 'Illegal control point format'
        elif dim < 4:
            self.cntrl = numerix.zeros((4, nu, nv), numerix.Float)
            self.cntrl[0:dim, :, :] = cntrl
            self.cntrl[-1, :, :] = numerix.ones((nu, nv), numerix.Float)
        else:
            self.cntrl = cntrl

        # Force the u knot sequence to be a vector in ascending order
        # and normalise between [0.0,1.0]
        uknots = numerix.sort(numerix.asarray(uknots, numerix.Float))
        nku = uknots.shape[0]
        uknots = (uknots - uknots[0]) / (uknots[-1] - uknots[0])
        if uknots[0] == uknots[-1]:
            raise NURBSError, 'Illegal uknots sequence'
        self.uknots = uknots

        # Force the v knot sequence to be a vector in ascending order
        # and normalise between [0.0,1.0]
        vknots = -numerix.sort(-numerix.asarray(vknots, numerix.Float))
        nkv = vknots.shape[0]
        vknots = (vknots - vknots[0]) / (vknots[-1] - vknots[0])
        if vknots[0] == vknots[-1]:
            raise NURBSError, 'Illegal vknots sequence'
        self.vknots = vknots

        # Spline Degree
        self.degree = [nku - nu - 1, nkv - nv - 1]
        if self.degree[0] < 0 or self.degree[1] < 0:
            raise NURBSError, 'NURBS order must be a positive integer'

    def trans(self, mat):
        "Apply the 4D transform matrix to the NURB control points."
        for v in range(self.cntrl.shape[2]):
            self.cntrl[:, :, v] = numerix.dot(mat, self.cntrl[:, :, v])

    def swapuv(self):
        "Swap u and v parameters."
        self.cntrl = numerix.transpose(self.cntrl, (0, 2, 1))
        temp = self.uknots[:]
        self.uknots = self.vknots[:]
        self.vknots = temp
        udegree, vdegree = self.degree
        self.degree[0] = vdegree
        self.degree[1] = udegree

    def reverse(self):
        "Reverse evaluation directions."
        coefs = self.cntrl[:, :, ::-1]
        self.cntrl = coefs[:, ::-1, :]
        self.uknots = 1. - self.uknots[::-1]
        self.vknots = 1. - self.vknots[::-1]

    def extractV(self, u):
        "Extract curve in v-direction at parameter u."
        if numerix.any(u < 0.) or numerix.any(u > 1.):
            raise NURBSError, 'Out of parameter range [0,1]'
        if u == 0.:
            cntrl = self.cntrl[:, 0, :]
            knots = self.vknots[:]
        elif u == 1.:
            cntrl = self.cntrl[:, -1, :]
            knots = self.vknots[:]
        else:
            uknots = numerix.repeat(
                numerix.asarray([u], numerix.Float),
                [self.degree[1] * (self.cntrl.shape[2] + 1)])
            coefs = numerix.transpose(self.cntrl, (0, 2, 1))
            coefs = numerix.resize(
                coefs, (4 * self.cntrl.shape[2], self.cntrl.shape[1]))
            coefs, knots = bspkntins(self.degree[0], coefs, self.uknots,
                                     uknots)
            coefs = numerix.resize(coefs,
                                   (4, self.cntrl.shape[2], coefs.shape[1]))
            cntrl = numerix.transpose(coefs, (0, 2, 1))
            i = 0
            j = knots[0]
            for k in knots[1:]:
                if k == u:
                    break
                elif k != j:
                    i += 1
                    j = k
        return Crv.Crv(cntrl[:, i, :], self.vknots[:])

    def extractU(self, v):
        "Extract curve in u-direction at parameter v."
        if numerix.any(v < 0.) or numerix.any(v > 1.):
            raise NURBSError, 'Out of parameter range [0,1]'
        if v == 0.:
            cntrl = self.cntrl[:, :, 0]
            knots = self.uknots[:]
        elif v == 1.:
            cntrl = self.cntrl[:, :, -1]
            knots = self.uknots[:]
        else:
            vknots = numerix.repeat(
                numerix.asarray([v], numerix.Float),
                [self.degree[0] * (self.cntrl.shape[1] + 1)])
            coefs = numerix.resize(
                self.cntrl, (4 * self.cntrl.shape[1], self.cntrl.shape[2]))
            coefs, knots = bspkntins(self.degree[1], coefs, self.vknots,
                                     vknots)
            cntrl = numerix.resize(coefs,
                                   (4, self.cntrl.shape[1], coefs.shape[1]))
            i = 0
            j = knots[0]
            for k in knots[1:]:
                if k == v:
                    break
                elif k != j:
                    i += 1
                    j = k
        return Crv.Crv(cntrl[:, :, i], self.uknots[:])

    def kntins(self, uknots, vknots=None):
        """Insert new knots into the surface
	uknots - knots to be inserted along u direction
	vknots - knots to be inserted along v direction
	NOTE: No knot multiplicity will be increased beyond the order of the spline"""
        if len(vknots):
            # Force the v knot sequence to be a vector in ascending order
            vknots = numerix.sort(numerix.asarray(vknots, numerix.Float))
            if numerix.any(vknots < 0.) or numerix.any(vknots > 1.):
                raise NURBSError, 'Illegal vknots sequence'
            coefs = numerix.resize(
                self.cntrl, (4 * self.cntrl.shape[1], self.cntrl.shape[2]))
            coefs, self.vknots = bspkntins(self.degree[1], coefs, self.vknots,
                                           vknots)
            self.cntrl = numerix.resize(
                coefs, (4, self.cntrl.shape[1], coefs.shape[1]))
        if len(uknots):
            # Force the u knot sequence to be a vector in ascending order
            uknots = numerix.sort(numerix.asarray(uknots, numerix.Float))
            if numerix.any(uknots < 0.) or numerix.any(uknots > 1.):
                raise NURBSError, 'Illegal uknots sequence'
            coefs = numerix.transpose(self.cntrl, (0, 2, 1))
            coefs = numerix.resize(
                coefs, (4 * self.cntrl.shape[2], self.cntrl.shape[1]))
            coefs, self.uknots = bspkntins(self.degree[0], coefs, self.uknots,
                                           uknots)
            coefs = numerix.resize(coefs,
                                   (4, self.cntrl.shape[2], coefs.shape[1]))
            self.cntrl = numerix.transpose(coefs, (0, 2, 1))

    def degelev(self, utimes, vtimes=None):
        """Degree elevate the surface.
	utimes - degree elevate utimes along u direction.
	vtimes - degree elevate vtimes along v direction."""
        if vtimes:
            if vtimes < 0:
                raise NURBSError, 'Degree must be positive'
            coefs = numerix.resize(
                self.cntrl, (4 * self.cntrl.shape[1], self.cntrl.shape[2]))
            coefs, vknots, nh = bspdegelev(self.degree[1], coefs, self.vknots,
                                           vtimes)
            coefs = coefs[:, :nh + 1]
            self.vknots = vknots[:nh + self.degree[1] + vtimes + 2]
            self.degree[1] += vtimes
            self.cntrl = numerix.resize(
                coefs, (4, self.cntrl.shape[1], coefs.shape[1]))
        if utimes:
            if utimes < 0:
                raise NURBSError, 'Degree must be positive'
            coefs = numerix.transpose(self.cntrl, (0, 2, 1))
            coefs = numerix.resize(
                coefs, (4 * self.cntrl.shape[2], self.cntrl.shape[1]))
            coefs, uknots, nh = bspdegelev(self.degree[0], coefs, self.uknots,
                                           utimes)
            coefs = coefs[:, :nh + 1]
            self.uknots = uknots[:nh + self.degree[0] + utimes + 2]
            self.degree[0] += utimes
            coefs = numerix.resize(coefs,
                                   (4, self.cntrl.shape[2], coefs.shape[1]))
            self.cntrl = numerix.transpose(coefs, (0, 2, 1))

    def bezier(self, update=None):
        "Decompose surface to bezier patches and return overlaping control points."
        if update or not self._bezier:
            cntrl = numerix.resize(
                self.cntrl, (4 * self.cntrl.shape[1], self.cntrl.shape[2]))
            cntrl = bspbezdecom(self.degree[1], cntrl, self.vknots)
            cntrl = numerix.resize(cntrl,
                                   (4, self.cntrl.shape[1], cntrl.shape[1]))
            temp1 = cntrl.shape[1]
            temp2 = cntrl.shape[2]
            cntrl = numerix.transpose(cntrl, (0, 2, 1))
            cntrl = numerix.resize(cntrl, (4 * temp2, temp1))
            cntrl = bspbezdecom(self.degree[0], cntrl, self.uknots)
            cntrl = numerix.resize(cntrl, (4, temp2, cntrl.shape[1]))
            self._bezier = numerix.transpose(cntrl, (0, 2, 1))
        return self._bezier

    def bounds(self):
        "Return the bounding box for the surface."
        w = self.cntrl[3, :, :]
        cx = numerix.sort(numerix.ravel(self.cntrl[0, :, :] / w))
        cy = numerix.sort(numerix.ravel(self.cntrl[1, :, :] / w))
        cz = numerix.sort(numerix.ravel(self.cntrl[2, :, :] / w))
        return numerix.asarray([cx[0], cy[0], cz[0], cx[-1], cy[-1], cz[-1]],
                               numerix.Float)

    def pnt3D(self, ut, vt=None):
        """Evaluate parametric point[s] and return 3D cartesian coordinate[s]
	If only ut is given then we will evaluate at scattered points.
	ut(0,:) represents the u direction.
	ut(1,:) represents the v direction.
	If both parameters are given then we will evaluate over a [u,v] grid."""
        val = self.pnt4D(ut, vt)
        if len(val.shape) < 3:
            return val[0:3, :] / numerix.resize(val[-1, :], (3, val.shape[1]))
        else:  #FIX!
            return val[0:3, :, :] / numerix.resize(
                val[-1, :, :], (3, val.shape[1], val.shape[2]))

    def pnt4D(self, ut, vt=None):
        """Evaluate parametric point[s] and return 4D homogeneous coordinates.
	If only ut is given then we will evaluate at scattered points.
	ut(0,:) represents the u direction.
	ut(1,:) represents the v direction.
	If both parameters are given then we will evaluate over a [u,v] grid."""
        ut = numerix.asarray(ut, numerix.Float)
        if numerix.any(ut < 0.) or numerix.any(ut > 1.):
            raise NURBSError, 'NURBS curve parameter out of range [0,1]'

        if vt:  #FIX!
            # Evaluate over a [u,v] grid
            vt = numerix.asarray(vt, numerix.Float)
            if numerix.any(vt < 0.) or numerix.any(vt > 1.):
                raise NURBSError, 'NURBS curve parameter out of range [0,1]'

            val = numerix.resize(
                self.cntrl, (4 * self.cntrl.shape[1], self.cntrl.shape[2]))
            val = bspeval(self.degree[1], val, self.vknots, vt)
            val = numerix.resize(val, (4, self.cntrl.shape[1], vt.shape[0]))

            val = numerix.transpose(val, (0, 2, 1))

            val = numerix.resize(self.cntrl,
                                 (4 * vt.shape[0], self.cntrl.shape[1]))
            val = bspeval(self.degree[0], val, self.uknots, ut)
            val = numerix.resize(val, (4, vt.shape[0], ut.shape[0]))

            return numerix.transpose(val, (0, 2, 1))

        # Evaluate at scattered points
        nt = ut.shape[1]
        uval = numerix.resize(self.cntrl,
                              (4 * self.cntrl.shape[1], self.cntrl.shape[2]))
        uval = bspeval(self.degree[1], uval, self.vknots, ut[1, :])
        uval = numerix.resize(uval, (4, self.cntrl.shape[1], nt))

        val = numerix.zeros((4, nt), numerix.Float)
        for v in range(nt):
            val[:, v] = bspeval(
                self.degree[0],
                numerix.resize(uval[:, :, v], (4, self.cntrl.shape[1])),
                self.uknots, (ut[0, v], ))[:, 0]
        return val

    def plot(self, n=50, iso=8):
        """A simple plotting function based on dislin for debugging purpose.
	n = number of subdivisions. iso = number of iso line to plot in each dir.
	TODO: plot ctrl poins and knots."""
        try:
            import dislin
        except ImportError, value:
            print 'dislin plotting library not available'
            return

        maxminx = numerix.sort(
            numerix.ravel(self.cntrl[0, :, :]) /
            numerix.ravel(self.cntrl[3, :, :]))
        minx = maxminx[0]
        maxx = maxminx[-1]
        if minx == maxx:
            minx -= 1.
            maxx += 1.

        maxminy = numerix.sort(
            numerix.ravel(self.cntrl[1, :, :]) /
            numerix.ravel(self.cntrl[3, :, :]))
        miny = maxminy[0]
        maxy = maxminy[-1]
        if miny == maxy:
            miny -= 1.
            maxy += 1.

        maxminz = numerix.sort(
            numerix.ravel(self.cntrl[2, :, :]) /
            numerix.ravel(self.cntrl[3, :, :]))
        minz = maxminz[0]
        maxz = maxminz[-1]
        if minz == maxz:
            minz -= 1.
            maxz += 1.

        dislin.metafl('cons')
        dislin.disini()
        dislin.hwfont()
        dislin.pagera()
        dislin.name('X-axis', 'X')
        dislin.name('Y-axis', 'Y')
        dislin.name('Z-axis', 'Z')
        dislin.graf3d(minx, maxx, 0, abs((maxx - minx) / 4.), miny, maxy, 0,
                      abs((maxy - miny) / 4.), minz, maxz, 0,
                      abs((maxz - minz) / 4.))

        dislin.color('yellow')
        pnts0 = self.pnt3D([
            numerix.arange(n + 1, typecode=numerix.Float) / n,
            numerix.zeros(n + 1, numerix.Float)
        ])
        pnts1 = self.pnt3D([
            numerix.arange(n + 1, typecode=numerix.Float) / n,
            numerix.ones(n + 1, numerix.Float)
        ])
        pnts2 = self.pnt3D([
            numerix.zeros(n + 1, numerix.Float),
            numerix.arange(n + 1, typecode=numerix.Float) / n
        ])
        pnts3 = self.pnt3D([
            numerix.ones(n + 1, numerix.Float),
            numerix.arange(n + 1, typecode=numerix.Float) / n
        ])
        dislin.curv3d(pnts0[0, :], pnts0[1, :], pnts0[2, :], n + 1)
        dislin.curv3d(pnts1[0, :], pnts1[1, :], pnts1[2, :], n + 1)
        dislin.curv3d(pnts2[0, :], pnts2[1, :], pnts2[2, :], n + 1)
        dislin.curv3d(pnts3[0, :], pnts3[1, :], pnts3[2, :], n + 1)

        dislin.color('red')
        step = 1. / iso
        for uv in numerix.arange(step, 1., step):
            pnts = self.pnt3D([
                numerix.arange(n + 1, typecode=numerix.Float) / n,
                numerix.zeros(n + 1, numerix.Float) + uv
            ])
            dislin.curv3d(pnts[0, :], pnts[1, :], pnts[2, :], n + 1)
            pnts = self.pnt3D([
                numerix.zeros(n + 1, numerix.Float) + uv,
                numerix.arange(n + 1, typecode=numerix.Float) / n
            ])
            dislin.curv3d(pnts[0, :], pnts[1, :], pnts[2, :], n + 1)

        dislin.disfin()
Ejemplo n.º 2
0
#!/usr/bin/env python
import dislin

ctit = 'Symbols'

dislin.setpag('da4p')
dislin.metafl('cons')

dislin.disini()
dislin.pagera()
dislin.complx()
dislin.paghdr('H. Michels  (', ')', 2, 0)

dislin.height(60)
nl = dislin.nlmess(ctit)
dislin.messag(ctit, (2100 - nl) / 2, 200)

dislin.height(50)
dislin.hsymbl(120)

ny = 150

for i in range(0, 22):
    if (i % 4) == 0:
        ny = ny + 400
        nxp = 550
    else:
        nxp = nxp + 350

    nl = dislin.nlnumb(i, -1)
    dislin.number(i, -1, nxp - nl / 2, ny + 150)
Ejemplo n.º 3
0
class Crv:
    '''Construct a NURB curve and check the format.
    
 The NURB curve is represented by a 4 dimensional b-spline.

 INPUT:

    cntrl  - Control points, homogeneous coordinates (wx,wy,wz,w)
            [dim,nu] matrix
            dim is the dimension valid options are:
            2 .... (x,y)        2D cartesian coordinates
            3 .... (x,y,z)      3D cartesian coordinates   
            4 .... (wx,wy,wz,w) 4D homogeneous coordinates

    uknots - Knot sequence along the parametric u direction.

 NOTES:

    Its assumed that the input knot sequences span the
    interval [0.0,1.0] and are clamped to the control
    points at the end by a knot multiplicity equal to
    the spline order.'''

    def __init__(self, cntrl, uknots):
        self._bezier = None
        # Force the u knot sequence to be a vector in ascending order
        # and normalise between [0.0,1.0]
        uknots = np.sort(np.asarray(uknots, np.float))
        nku = uknots.shape[0]
        uknots = (uknots - uknots[0])/(uknots[-1] - uknots[0])
        if uknots[0] == uknots[-1]:
            raise NURBSError, 'Illegal uknots sequence'
        self.uknots = uknots
        cntrl = np.asarray(cntrl, np.float)
        (dim, nu) = cntrl.shape
        if dim < 2 or dim > 4:
            raise NURBSError, 'Illegal control point format'
        elif dim < 4:
            self.cntrl = np.zeros((4, nu), np.float)
            self.cntrl[0:dim,:] = cntrl
            self.cntrl[-1,:] = np.ones((nu,))
        else:
            self.cntrl = cntrl
        # Spline degree
        self.degree = nku - nu - 1
        if self.degree < 0:
            raise NURBSError, 'NURBS order must be a positive integer'

    def trans(self, mat):
        "Apply the 4D transform matrix to the NURB control points."
        self.cntrl = np.dot(mat, self.cntrl)

    def reverse(self):
        "Reverse evaluation direction"
        self.cntrl = self.cntrl[:,::-1]
        self.uknots = 1 - self.uknots[::-1]
        
    def kntins(self, uknots):
        """Insert new knots into the curve
	NOTE: No knot multiplicity will be increased beyond the order of the spline"""
        if len(uknots):
            uknots = np.sort(np.asarray(uknots, np.float))
            if np.less(uknots, 0.) or np.greater(uknots, 1.):
                raise NURBSError, 'NURBS curve parameter out of range [0,1]'
            self.cntrl, self.uknots = bspkntins(self.degree, self.cntrl, self.uknots, uknots)

    def degelev(self, degree):
        "Degree elevate the curve"
        if degree < 0:
            raise NURBSError, 'degree must be a positive number'
        if degree > 0:
            cntrl, uknots, nh = bspdegelev(self.degree, self.cntrl, self.uknots, degree)
            self.cntrl = cntrl[:,:nh + 1]
            self.uknots = uknots[:nh + self.degree + degree + 2]
            self.degree += degree

    def bezier(self, update = None):
        "Decompose curve to bezier segments and return overlaping control points"
        if update or not self._bezier:
            self._bezier = bspbezdecom(self.degree, self.cntrl, self.uknots)
        return self._bezier

    def bounds(self):
        "Return the boundingbox for the curve"
        ww = np.resize(self.cntrl[-1,:], (3, self.cntrl.shape[1]))
        cntrl = np.sort(self.cntrl[0:3,:]/ww)
        return np.asarray([cntrl[0,0], cntrl[1,0], cntrl[2,0],
                                cntrl[0,-1], cntrl[1,-1], cntrl[2,-1]], np.float)
                                
    def pnt3D(self, ut):
        "Evaluate parametric point[s] and return 3D cartesian coordinate[s]"
        val = self.pnt4D(ut)
        return val[0:3,:]/np.resize(val[-1,:], (3, val.shape[1]))

    def pnt4D(self, ut):
        "Evaluate parametric point[s] and return 4D homogeneous coordinates"
        ut = np.asarray(ut, np.float)
        if np.less(ut, 0.) or np.greater(ut, 1.):
            raise NURBSError, 'NURBS curve parameter out of range [0,1]'
        return bspeval(self.degree, self.cntrl, self.uknots, ut)
                
    def plot(self, n = 25):
        """A simple plotting function for debugging purpose
	n = number of subdivisions.
	Depends on the dislin plotting library."""
        try:
            import dislin
        except ImportError, value:
            print 'dislin plotting library not available'
            return

        pnts = self.pnt3D(np.arange(n + 1, typecode = np.float)/n)
        knots = self.pnt3D(self.uknots)

        maxminx = np.sort(self.cntrl[0,:]/self.cntrl[3,:])
        minx = maxminx[0]
        maxx = maxminx[-1]
        if minx == maxx:
            minx -= 1.
            maxx += 1.
        maxminy = np.sort(self.cntrl[1,:]/self.cntrl[3,:])
        miny = maxminy[0]
        maxy = maxminy[-1]
        if miny == maxy:
            miny -= 1.
            maxy += 1.
        maxminz = np.sort(self.cntrl[2,:]/self.cntrl[3,:])
        minz = maxminz[0]
        maxz = maxminz[-1]
        if minz == maxz:
            minz -= 1.
            maxz += 1.
            
        dislin.metafl('cons')
        dislin.disini()
        dislin.hwfont()
        dislin.pagera()
        dislin.name('X-axis', 'X')
        dislin.name('Y-axis', 'Y')
        dislin.name('Z-axis', 'Z')
        dislin.graf3d(minx, maxx, 0 , abs((maxx-minx)/4.),
                      miny, maxy, 0 , abs((maxy-miny)/4.),
                      minz, maxz, 0 , abs((maxz-minz)/4.))
        dislin.color('yellow')
        dislin.curv3d(pnts[0,:], pnts[1,:], pnts[2,:], n+1)
        dislin.color('red')
        dislin.dashm()
        dislin.curv3d(self.cntrl[0,:]/self.cntrl[3,:], self.cntrl[1,:]/self.cntrl[3,:],
                      self.cntrl[2,:]/self.cntrl[3,:], self.cntrl.shape[1])
        dislin.color('white')
        dislin.incmrk(-1)
        dislin.marker(8)
        dislin.curv3d(knots[0,:], knots[1,:], knots[2,:], knots.shape[1])
        dislin.disfin()