ftp.nice.ch/peanuts/GeneralData/Documents/adobe/DPS.Purple.Text.tar.gz#/NX_Text/rotateprocs.c

This is rotateprocs.c in view mode; [Download] [Up]

/*
 * (a)  (C) 1990 by Adobe Systems Incorporated. All rights reserved.
 *
 * (b)  If this Sample Code is distributed as part of the Display PostScript
 *	System Software Development Kit from Adobe Systems Incorporated,
 *	then this copy is designated as Development Software and its use is
 *	subject to the terms of the License Agreement attached to such Kit.
 *
 * (c)  If this Sample Code is distributed independently, then the following
 *	terms apply:
 *
 * (d)  This file may be freely copied and redistributed as long as:
 *	1) Parts (a), (d), (e) and (f) continue to be included in the file,
 *	2) If the file has been modified in any way, a notice of such
 *      modification is conspicuously indicated.
 *
 * (e)  PostScript, Display PostScript, and Adobe are registered trademarks of
 *	Adobe Systems Incorporated.
 * 
 * (f) THE INFORMATION BELOW IS FURNISHED AS IS, IS SUBJECT TO
 *	CHANGE WITHOUT NOTICE, AND SHOULD NOT BE CONSTRUED
 *	AS A COMMITMENT BY ADOBE SYSTEMS INCORPORATED.
 *	ADOBE SYSTEMS INCORPORATED ASSUMES NO RESPONSIBILITY
 *	OR LIABILITY FOR ANY ERRORS OR INACCURACIES, MAKES NO
 *	WARRANTY OF ANY KIND (EXPRESS, IMPLIED OR STATUTORY)
 *	WITH RESPECT TO THIS INFORMATION, AND EXPRESSLY
 *	DISCLAIMS ANY AND ALL WARRANTIES OF MERCHANTABILITY, 
 *	FITNESS FOR PARTICULAR PURPOSES AND NONINFRINGEMENT
 *	OF THIRD PARTY RIGHTS.
 */

/*
 *	rotateprocs.c
 *
 *	This file contains procedure that perform operations
 *	on rotated rectangles and points.
 *
 *	Note: the angle in the procedures below should be expressed
 *	in radians and not degrees.
 *
 *	Version:	2.0
 *	Author:	Ken Fromm
 *	History:
 *			03-07-91		Added this comment.
 */

#import <appkit/graphics.h>
#import <appkit/nextstd.h>
#import <math.h>

/*
*	Takes the point passed in, rotates it around the point
*	at the angle given and returns the new point.
*	The new point replaces the old one and its address
*	is returned as the return value.
*/
NXPoint *RotatePoint(NXPoint *aPoint, NXPoint *cPoint, float angle)
{
	float		d, dx, dy;

	float		ang;

	if (aPoint && cPoint && angle != 0)
	{
		dx = aPoint->x - cPoint->x;
		dy = aPoint->y - cPoint->y;

		*aPoint = *cPoint;
		d = sqrt(dx * dx + dy * dy);
		if (d != 0.0)
		{
			ang = angle + (float) atan2(dy, dx);
			aPoint->x += d * cos(ang);
			aPoint->y += d * sin(ang);
		}
	}

	return aPoint;
}

/*
*	Checks whether the point passed in lies in the rectangle
*	rotated about its lower left vertice at the angle provided.
*	Returns either YES or NO. Assumes an unflipped 
*	coordinate system.
*/
BOOL MouseInRotatedRect(NXPoint *aPoint, NXRect *aRect, float angle)
{
	NXPoint		pt;

	if (aRect && aPoint)
	{
		pt = *aPoint;
		RotatePoint(&pt, &aRect->origin, -angle);

		return NXMouseInRect(&pt, aRect, NO);
	}
	else
		return NO;
}

/*
*	This procedure takes the unrotated rectangle, bRect,
*	rotates it around the point, cPoint, at the angle, angle,
*	and places the new bounding box that encloses the
*	rotated rectangle in the rectangle aRect. The address
*	of the new rectangle is returned as the return value.
*
*	Figuring the new width and height is relatively
*	straight-forward. Just take the sin and cos of  the
*	old width and height.
*
*	Figuring the new origin is a bit different. The vertices
*	for the lower x and lower y coordinates are chosen
*	based on the angle to rotate. Their positions in the rotated
*	spaced are calculated and subtracted from the center point.
*/
NXRect *RotateRectBounds(NXRect *aRect, const NXRect *bRect, NXPoint *cPoint, float angle)
{
	float			dx, dy, dxx, dxy, dyx, dyy;

	double		cosa, sina;
	
	if (aRect  && bRect && cPoint)
	{
		if (angle != 0)
		{
			cosa = cos(angle);
			sina = sin(angle);

			dyx = dxx = bRect->origin.x - cPoint->x;
			dyy = dxy = bRect->origin.y - cPoint->y;

			if (cosa > 0)
			{
				if (sina > 0)
					dxy += bRect->size.height;
				else
					dyx += bRect->size.width;		
			}
			else
			{
				if (sina > 0)
				{
					dxx += bRect->size.width;
					dyy = dxy = dxy + bRect->size.height;
				}
				else
				{
					dyx = dxx = dxx + bRect->size.width;
					dyy += bRect->size.height; 
				}
			}

			aRect->origin = *cPoint;

			dx = sqrt(dxx * dxx + dxy * dxy);
			if (dx != 0.0)
				aRect->origin.x += (float) dx * cos(angle + atan2(dxy, dxx));
			dy = sqrt(dyx * dyx + dyy * dyy);
			if (dy != 0.0)
				aRect->origin.y += (float) dy * sin(angle + atan2(dyy, dyx));

			aRect->size.width = (float) (ABS(bRect->size.width * cosa) +
						ABS(bRect->size.height * sina));
			aRect->size.height = (float) (ABS(bRect->size.width * cos(M_PI_2 - angle)) +
						ABS(bRect->size.height * sin(M_PI_2 - angle)));
		}
		else
			*aRect = *bRect;
	}

	return aRect;
}

/*
*	This procedure calculates the minimum hypotense
*	for a width and a height. The width and height are
*	meant to be from different triangles sharing the same
*	angles.
*/
static double DistanceToEdge(float x, float y, float angle)
{
	float			dx, dy;

	double		cosa, sina;

	cosa = cos(angle);
	if (cosa != 0.0)
		dx = ABS(x / cosa);
	else
		dx = y;

	sina = sin(angle);
	if (sina != 0.0)
		dy = ABS(y / sina);
	else
		dy = x;

	return MIN(dx, dy);
}

/*
*	This procedure takes two rectangles and an angle.
*	It checks if the second rectangle rotated about its origin
*	at the given angle intersects the first rectangle. The
*	first rectangle is unrotated. 
*
*	It checks for intersection by comparing the distance between
*	the centers to the sum of the distance from the centers to the
*	edges. If the distance between the centers is less than the
*	sum of the distance to the edges, the rectangles intersect.
*/
BOOL IntersectsRotatedRect(NXRect *aRect, NXRect *bRect, float angle)
{
	BOOL	intersect = NO;

	float		d, dx, dy, da, db;

	float		ang;
	
	NXPoint	bCenter;

	if (aRect && bRect)
	{
		if (angle != 0.0)
		{
			bCenter.x = bRect->origin.x + bRect->size.width/2;
			bCenter.y = bRect->origin.y + bRect->size.height/2;
			RotatePoint(&bCenter, &bRect->origin, angle);

			dx = bCenter.x - (aRect->origin.x + aRect->size.width/2);
			dy = bCenter.y - (aRect->origin.y + aRect->size.height/2);
			d = sqrt(dx*dx + dy*dy);
			if (d)
			{
				ang = (float) atan2(dy, dx);
				da = DistanceToEdge(aRect->size.width/2, aRect->size.height/2, ang);
				ang = ang + M_PI_2 - angle;
				db = DistanceToEdge(bRect->size.width/2, bRect->size.height/2, ang);

				intersect = (d <= da + db);
			}
			else
				intersect = YES;
		}
		else
			intersect = NXIntersectsRect(aRect, bRect);
	}

	return intersect;
}

/*
*	This procedure takes two points and constrains the first
*	point to the nearest 15% interval.
*/
void ConstrainPointToAngle(NXPoint *aPoint, NXPoint *cPoint, float angle)
{
	float		d, dx, dy, a;

	dx = aPoint->x - cPoint->x;
	dy = aPoint->y - cPoint->y;
	d = sqrt(dx*dx + dy*dy);

	if (d != 0.0)
	{
		a = rint(atan2(dy, dx) / angle) * angle;
		aPoint->x = (float) cPoint->x + d * cos(a);
		aPoint->y = (float) cPoint->y + d * sin(a);
	}
}

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