ftp.nice.ch/pub/next/tools/screen/SpaceSaver.3.3.1.NIHS.bs.tar.gz#/SpaceSaver/Source/UserPath.m

This is UserPath.m in view mode; [Download] [Up]

/* 
 * UserPath.m by Bruce Blumberg, NeXT Computer, Inc.
 *
 * You may freely copy,distribute and re-use the code in this example.
 * NeXT disclaims any warranty of any kind, expressed or implied, as
 * to its fitness for any particular purpose
 *
 */

#import "UserPath.h"
#import <mach/mach_init.h>
#import <appkit/graphics.h>
#import <appkit/errors.h>
#import <math.h>
#import <libc.h>

static NXZone *upZone = NULL;

NXZone *userPathZone()
/* Creates a unique zone for use by all user paths */
{
	if (!upZone) upZone = NXCreateZone(vm_page_size, vm_page_size, 1);

	return upZone;
}

UserPath *newUserPath() // Creates a new User Path in the zone returned by userPathZone
{
	UserPath *up;

	up = (UserPath *) NXZoneMalloc(userPathZone(), sizeof(UserPath));
	up->max = 32;
	up->points = (float *) NXZoneMalloc(userPathZone(), sizeof(float) * up->max);
	up->ops = (char *) NXZoneMalloc(userPathZone(), (2 + (up->max / 2)) * sizeof(char));
	up->ping = NO;

	return up;
}

void freeUserPath(UserPath *up) // Frees User Path and its associated buffers
{
	free(up->points);
	free(up->ops);
	free(up);

	return;
}

void growUserPath(UserPath *up)
/*
 * Grows the associated buffers as necessary.  Buffer size doubles on each
 * call.  You never need to call grow directly as it is called as needed by the
 * methods and functions which add elements into the buffer
 */
{
 /* double the size of the internal buffers */
	up->max *= 2;
	up->points = (float *) NXZoneRealloc(userPathZone(), up->points, sizeof(float) * up->max);
	up->ops = (char *) NXZoneRealloc(userPathZone(), up->ops, (2 + (up->max / 2)) * sizeof(char));

	return;
}

void beginUserPath(UserPath *up, BOOL cache)
/*
 * Call this to start generating a user path.  The cache argument specifies if
 * you want the user path cached at the server (i.e. dps_ucache).  In either
 * case, the UserPath object will automatically calculate the bounding box for
 * the path and add the dps_setbbox operator.
 */
{
	up->numberOfPoints = up->numberOfOps = 0;
	up->cp.x = up->cp.y = 0;
	up->bbox[0] = up->bbox[1] = 1.0e6;
	up->bbox[2] = up->bbox[3] = -1.0e6;
	if (cache) up->ops[up->numberOfOps++] = dps_ucache;
	up->ops[up->numberOfOps++] = dps_setbbox;
	up->opForUserPath = 0;

	return;
}

void endUserPath(UserPath *up, int op)
/*
 * Call this to stop filling the path.  Note this does not send the userpath to
 * the server -- use sendUserPath.  The op argument should be one of the
 * following:
 *	dps_uappend, dps_ufill ,dps_ueofill, dps_ustroke, dps_ustrokepath,
 *	dps_inufill, dps_inueofill, dps_inustroke, dps_def, dps_put.
 * These are defined in <dpsclient/dpsNext.h.
 */
{
	up->opForUserPath = op;

	return;
}

int sendUserPath(UserPath *up)
/*
 * Call this to send the path down to the server.  If ping==YES (set via
 * debug:), the function will send an NXPing() after the Path.  In any event,
 * code is bracketed by a NX_DURING ... NX_HANDLER construct which will try to
 * catch postscript errors.  If ping==NO (the default) it is unlikely to catch
 * errors, with ping==YES it will.  Whether you can recover or not is another
 * matter.  sendUserPath returns 0 on success and -1 on failure.  If no previous
 * endUserPath: has been sent, will return -2 and will not send the path to the
 * server.
 */
{
	NXHandler exception;

	exception.code = 0;
	if (up->opForUserPath != 0) {
		NX_DURING
			DPSDoUserPath(up->points, up->numberOfPoints, dps_float, up->ops, up->numberOfOps, up->bbox, up->opForUserPath);
			if (up->ping) NXPing();
		NX_HANDLER
			exception = NXLocalHandler;
		NX_ENDHANDLER
		if (exception.code) {
			NXReportError(&exception);
			if (exception.code == dps_err_ps) return -1;
			}
		else return 0;
		}

	return -1;
}

void checkBoundingBox(UserPath *up, float x, float y)
/* Checks if bounding box needs to be enlarged based on x and y */
{
	if (x < up->bbox[0]) up->bbox[0] = x;
	if (y < up->bbox[1]) up->bbox[1] = y;
	if (x > up->bbox[2]) up->bbox[2] = x;
	if (y > up->bbox[3]) up->bbox[3] = y;

	return;
}

void addPts(UserPath *up, float x, float y)
/* adds x and y to user path.  Updates bounding box as necessary */
{
	if (!((up->numberOfPoints + 2) < up->max)) growUserPath(up);

	up->points[up->numberOfPoints++] = x;
	up->points[up->numberOfPoints++] = y;
	checkBoundingBox(up, x, y);

	return;
}

void addOp(UserPath *up, int op)
/*
 * adds operator to user path.  Operator should be one of the following:
 * 	dps_moveto, dps_rmoveto, dps_lineto, dps_rlineto, dps_curveto,
 *	dps_rcurveto, dps_arc, dps_arcn, dps_arct, dps_closepath.
 */
{
	up->ops[up->numberOfOps++] = op;

	return;
}

void add(UserPath *up, int op, float x, float y)
/*
 * adds operator and x and y to user path.  Operator should be one of the
 * operators above
 */
{
	if (!((up->numberOfPoints + 2) < up->max)) growUserPath(up);

	up->ops[up->numberOfOps++] = op;
	up->points[up->numberOfPoints++] = x;
	up->points[up->numberOfPoints++] = y;
	checkBoundingBox(up, x, y);

	return;
}

void UPmoveto(UserPath *up, float x, float y)
/* adds <x y moveto> to user path and updates bounding box */
{
	add(up, dps_moveto, x, y);
	up->cp.x = x;
	up->cp.y = y;

	return;
}

void UPrmoveto(UserPath *up, float x, float y)
/* adds <x y rmoveto> to user path and updates bounding box */
{
	if (!((up->numberOfPoints + 2) < up->max)) growUserPath(up);
	
	up->ops[up->numberOfOps++] = dps_rmoveto;
	up->points[up->numberOfPoints++] = x;
	up->points[up->numberOfPoints++] = y;
	up->cp.x += x;
	up->cp.y += y;
	checkBoundingBox(up, up->cp.x, up->cp.y);

	return;
}

void UPlineto(UserPath *up, float x, float y)
/* adds <x y lineto> to user path and updates bounding box */
{
	add(up, dps_lineto, x, y);
	up->cp.x = x;
	up->cp.y = y;
	
	return;
}

void UPrlineto(UserPath *up, float x, float y)
/* adds <x y rlineto> to user path and updates bounding box */
{
	if (!((up->numberOfPoints + 2) < up->max)) growUserPath(up);

	up->ops[up->numberOfOps++] = dps_rlineto;
	up->points[up->numberOfPoints++] = x;
	up->points[up->numberOfPoints++] = y;
	up->cp.x += x;
	up->cp.y += y;
	checkBoundingBox(up, up->cp.x, up->cp.y);

	return;
}

void UPcurveto(UserPath *up, float x1, float y1, float x2, float y2, float x3, float y3)
/* adds <x1 y1 x2 y2 curveto> to user path and updates bounding box */
{
	addPts(up, x1, y1);
	addPts(up, x2, y2);
	add(up, dps_curveto, x3, y3);
	up->cp.x = x3;
	up->cp.y = y3;

	return;
}

void UPrcurveto(UserPath *up, float dx1, float dy1, float dx2, float dy2, float dx3, float dy3)
/* adds <x1 y1 x2 y2 rcurveto> to user path and updates bounding box */
{
	if (!((up->numberOfPoints + 6) < up->max)) growUserPath(up);

	up->ops[up->numberOfOps++] = dps_rcurveto;
	up->points[up->numberOfPoints++] = dx1;
	up->points[up->numberOfPoints++] = dy1;
	up->points[up->numberOfPoints++] = dx2;
	up->points[up->numberOfPoints++] = dy2;
	up->points[up->numberOfPoints++] = dx3;
	up->points[up->numberOfPoints++] = dy3;
	checkBoundingBox(up, up->cp.x + dx1, up->cp.y + dy1);
	checkBoundingBox(up, up->cp.x + dx2, up->cp.y + dy2);
	checkBoundingBox(up, up->cp.x + dx3, up->cp.y + dy3);
	up->cp.x = dx3;
	up->cp.y = dy3;

	return;
}

void UParc(UserPath *up, float x, float y, float r, float ang1, float ang2)
/* adds <x y r ang1 ang2 arc> to user path and updates bounding box */
{
	if (!((up->numberOfPoints + 5) < up->max)) growUserPath(up);

	up->ops[up->numberOfOps++] = dps_arc;
	up->points[up->numberOfPoints++] = x;
	up->points[up->numberOfPoints++] = y;
	up->points[up->numberOfPoints++] = r;
	up->points[up->numberOfPoints++] = ang1;
	up->points[up->numberOfPoints++] = ang2;
	checkBoundingBox(up, x + r, y + r);
	checkBoundingBox(up, x - r, y - r);
	up->cp.x = x + cos(ang2 / 57.3) * r;
	up->cp.y = y + sin(ang2 / 57.3) * r;

	return;
}

void UParcn(UserPath *up, float x, float y, float r, float ang1, float ang2)
/* adds <x y r ang1 ang2 arcn> to user path and updates bounding box */
{
	if (!((up->numberOfPoints + 5) < up->max)) growUserPath(up);

	up->ops[up->numberOfOps++] = dps_arcn;
	up->points[up->numberOfPoints++] = x;
	up->points[up->numberOfPoints++] = y;
	up->points[up->numberOfPoints++] = r;
	up->points[up->numberOfPoints++] = ang1;
	up->points[up->numberOfPoints++] = ang2;
	checkBoundingBox(up, x + r, y + r);
	checkBoundingBox(up, x - r, y - r);
	up->cp.x = x + cos(ang2 / 57.3) * r;
	up->cp.y = y + sin(ang2 / 57.3) * r;

	return;
}

void UParct(UserPath *up, float x1, float y1, float x2, float y2, float r)
/* adds <x1 y1 x2 y2 r arct> to user path and updates bounding box */
{
	if (!((up->numberOfPoints + 5) < up->max)) growUserPath(up);

	up->ops[up->numberOfOps++] = dps_arcn;
	up->points[up->numberOfPoints++] = x1;
	up->points[up->numberOfPoints++] = y1;
	up->points[up->numberOfPoints++] = x2;
	up->points[up->numberOfPoints++] = y2;
	up->points[up->numberOfPoints++] = r;
	checkBoundingBox(up, x1, y1);
	checkBoundingBox(up, x2, y2);
	up->cp.x = x2;
	up->cp.y = y2;

	return;
}

void closePath(UserPath *up)
/* adds <closepath> to user path and updates bounding box */
{
	up->ops[up->numberOfOps++] = dps_closepath;

	return;
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.