mirror of
https://github.com/gnustep/libs-gui.git
synced 2025-04-25 11:01:31 +00:00
1454 lines
31 KiB
Mathematica
1454 lines
31 KiB
Mathematica
|
/*
|
||
|
NSBezierPath.m
|
||
|
|
||
|
The NSBezierPath class
|
||
|
|
||
|
Copyright (C) 1999 Free Software Foundation, Inc.
|
||
|
|
||
|
Author: Enrico Sersale <enrico@imago.ro>
|
||
|
Date: Dec 1999
|
||
|
|
||
|
This file is part of the GNUstep GUI Library.
|
||
|
|
||
|
This library is free software; you can redistribute it and/or
|
||
|
modify it under the terms of the GNU Library General Public
|
||
|
License as published by the Free Software Foundation; either
|
||
|
version 2 of the License, or (at your option) any later version.
|
||
|
|
||
|
This library is distributed in the hope that it will be useful,
|
||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
|
Library General Public License for more details.
|
||
|
|
||
|
You should have received a copy of the GNU Library General Public
|
||
|
License along with this library; see the file COPYING.LIB.
|
||
|
If not, write to the Free Software Foundation,
|
||
|
59 Temple Place - Suite 330, Boston, MA 02111 - 1307, USA.
|
||
|
*/
|
||
|
|
||
|
#include <gnustep/gui/config.h>
|
||
|
#include <AppKit/AppKit.h>
|
||
|
#include <math.h>
|
||
|
|
||
|
#ifndef PI
|
||
|
#define PI 3.1415926535897932384626433
|
||
|
#endif
|
||
|
|
||
|
typedef struct {
|
||
|
NSPoint p1;
|
||
|
NSPoint p2;
|
||
|
} Line;
|
||
|
|
||
|
typedef struct {
|
||
|
NSPoint p;
|
||
|
double t;
|
||
|
} pointOnCurve;
|
||
|
|
||
|
typedef enum {
|
||
|
INTERIOR,
|
||
|
EXTERIOR,
|
||
|
VERTEX,
|
||
|
ONBORDER
|
||
|
} pointPosition;
|
||
|
|
||
|
pointPosition inPath(NSBezierPath *aPath, NSPoint p);
|
||
|
BOOL onPathBorder(NSBezierPath *aPath, NSPoint p);
|
||
|
int ccw(NSPoint p0, NSPoint p1, NSPoint p2);
|
||
|
BOOL intersect(Line line1, Line line2);
|
||
|
BOOL intersectRect(NSRect rect, Line line);
|
||
|
void subdiv(int degree, float coeff[], float t, float bleft[], float bright[]);
|
||
|
NSPoint rotatePoint(NSPoint p, NSPoint centre, float angle);
|
||
|
|
||
|
@interface PathElement : NSObject
|
||
|
{
|
||
|
NSPoint p[3];
|
||
|
NSBezierPathElementType type;
|
||
|
}
|
||
|
|
||
|
+ (PathElement *)pathElement;
|
||
|
- (void)setType:(NSBezierPathElementType)t;
|
||
|
- (void)setPointAtIndex:(int)index toPoint:(NSPoint)aPoint;
|
||
|
- (NSBezierPathElementType)type;
|
||
|
- (NSPoint *)points;
|
||
|
|
||
|
@end
|
||
|
|
||
|
@implementation PathElement
|
||
|
|
||
|
+ (PathElement *)pathElement
|
||
|
{
|
||
|
return AUTORELEASE([[self alloc] init]);
|
||
|
}
|
||
|
|
||
|
- (void)setType:(NSBezierPathElementType)t
|
||
|
{
|
||
|
type = t;
|
||
|
}
|
||
|
|
||
|
- (void)setPointAtIndex:(int)index toPoint:(NSPoint)aPoint
|
||
|
{
|
||
|
p[index].x = aPoint.x;
|
||
|
p[index].y = aPoint.y;
|
||
|
}
|
||
|
|
||
|
- (NSBezierPathElementType)type
|
||
|
{
|
||
|
return type;
|
||
|
}
|
||
|
|
||
|
- (NSPoint *)points
|
||
|
{
|
||
|
return p;
|
||
|
}
|
||
|
|
||
|
@end
|
||
|
|
||
|
@interface NSBezierPath (PrivateMethods)
|
||
|
|
||
|
- (void)setCurrentPoint:(NSPoint)aPoint;
|
||
|
- (BOOL)isPathElement:(PathElement *)elm1 onPathElement:(PathElement *)elm2;
|
||
|
- (NSMutableArray *)pathElements;
|
||
|
- (PathElement *)moveToElement;
|
||
|
- (PathElement *)lastElement;
|
||
|
- (int)indexOfElement:(PathElement *)element;
|
||
|
- (PathElement *)elementPrecedingElement:(PathElement *)element;
|
||
|
- (void)calculateDraftPolygon;
|
||
|
- (NSPoint *)draftPolygon;
|
||
|
- (int)pcount;
|
||
|
- (NSBezierPath *)pathWithOvalInRect:(NSRect)aRect;
|
||
|
- (void)movePathToPoint:(NSPoint)p;
|
||
|
- (void)rotateByAngle:(float)angle center:(NSPoint)center;
|
||
|
- (pointOnCurve)pointOnPathSegmentOfElement:(PathElement *)elm
|
||
|
nearestToPoint:(NSPoint)p;
|
||
|
- (PathElement *)pathElementSubdividingPathAtPoint:(NSPoint)p
|
||
|
pathSegmentOwner:(PathElement *)owner;
|
||
|
|
||
|
@end
|
||
|
|
||
|
|
||
|
@implementation NSBezierPath
|
||
|
|
||
|
+ (NSBezierPath *)bezierPath
|
||
|
{
|
||
|
return AUTORELEASE([[self alloc] init]);
|
||
|
}
|
||
|
|
||
|
+ (NSBezierPath *)bezierPathWithRect:(NSRect)aRect
|
||
|
{
|
||
|
NSBezierPath *path;
|
||
|
NSPoint p;
|
||
|
|
||
|
path = [NSBezierPath bezierPath];
|
||
|
[path moveToPoint: aRect.origin];
|
||
|
p.x = aRect.origin.x + aRect.size.width;
|
||
|
p.y = aRect.origin.y;
|
||
|
[path lineToPoint: p];
|
||
|
p.x = aRect.origin.x + aRect.size.width;
|
||
|
p.y = aRect.origin.y + aRect.size.height;
|
||
|
[path lineToPoint: p];
|
||
|
p.x = aRect.origin.x;
|
||
|
p.y = aRect.origin.y + aRect.size.height;
|
||
|
[path lineToPoint: p];
|
||
|
[path closePath];
|
||
|
|
||
|
return path;
|
||
|
}
|
||
|
|
||
|
- (id)init
|
||
|
{
|
||
|
self = [super init];
|
||
|
if(self) {
|
||
|
pathElements = [[NSMutableArray alloc] initWithCapacity: 1];
|
||
|
subPaths = [[NSMutableArray alloc] initWithCapacity: 1];
|
||
|
windingRule = NSWindingRuleNonZero;
|
||
|
}
|
||
|
return self;
|
||
|
}
|
||
|
|
||
|
- (void)dealloc
|
||
|
{
|
||
|
[pathElements release];
|
||
|
[subPaths release];
|
||
|
[super dealloc];
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Contructing paths
|
||
|
//
|
||
|
- (void)moveToPoint:(NSPoint)aPoint
|
||
|
{
|
||
|
PathElement *elm = [PathElement pathElement];
|
||
|
[elm setType: NSBezierPathElementMoveTo];
|
||
|
[elm setPointAtIndex: 0 toPoint: aPoint];
|
||
|
[pathElements addObject: elm];
|
||
|
[self setCurrentPoint: aPoint];
|
||
|
[self calculateDraftPolygon];
|
||
|
}
|
||
|
|
||
|
- (void)lineToPoint:(NSPoint)aPoint
|
||
|
{
|
||
|
PathElement *elm = [PathElement pathElement];
|
||
|
[elm setType: NSBezierPathElementLineTo];
|
||
|
[elm setPointAtIndex: 0 toPoint: aPoint];
|
||
|
[pathElements addObject: elm];
|
||
|
[self setCurrentPoint: aPoint];
|
||
|
[self calculateDraftPolygon];
|
||
|
}
|
||
|
|
||
|
- (void)curveToPoint:(NSPoint)aPoint
|
||
|
controlPoint1:(NSPoint)controlPoint1
|
||
|
controlPoint2:(NSPoint)controlPoint2
|
||
|
{
|
||
|
PathElement *elm = [PathElement pathElement];
|
||
|
[elm setType: NSBezierPathElementCurveTo];
|
||
|
[elm setPointAtIndex: 0 toPoint: controlPoint1];
|
||
|
[elm setPointAtIndex: 1 toPoint: controlPoint2];
|
||
|
[elm setPointAtIndex: 2 toPoint: aPoint];
|
||
|
[pathElements addObject: elm];
|
||
|
[self setCurrentPoint: aPoint];
|
||
|
[self calculateDraftPolygon];
|
||
|
}
|
||
|
|
||
|
- (void)closePath
|
||
|
{
|
||
|
PathElement *elm, *elm1, *elm2;
|
||
|
NSPoint p;
|
||
|
|
||
|
elm1 = [self moveToElement];
|
||
|
elm2 = [self lastElement];
|
||
|
if(![self isPathElement: elm2 onPathElement: elm1]) {
|
||
|
p = [elm1 points][0];
|
||
|
[self lineToPoint: p];
|
||
|
}
|
||
|
elm = [PathElement pathElement];
|
||
|
[elm setType: NSBezierPathElementClose];
|
||
|
[pathElements addObject: elm];
|
||
|
}
|
||
|
|
||
|
- (void)reset
|
||
|
{
|
||
|
[pathElements removeAllObjects];
|
||
|
[subPaths removeAllObjects];
|
||
|
}
|
||
|
|
||
|
- (void)relativeMoveToPoint:(NSPoint)aPoint
|
||
|
{
|
||
|
NSBezierPath *path;
|
||
|
NSPoint p;
|
||
|
|
||
|
p.x = currentPoint.x + aPoint.x;
|
||
|
p.y = currentPoint.y + aPoint.y;
|
||
|
path = [NSBezierPath bezierPath];
|
||
|
[path moveToPoint: p];
|
||
|
[subPaths addObject: path];
|
||
|
[self setCurrentPoint: p];
|
||
|
}
|
||
|
|
||
|
- (void)relativeLineToPoint:(NSPoint)aPoint
|
||
|
{
|
||
|
NSPoint p;
|
||
|
|
||
|
if(![pathElements count]) {
|
||
|
[NSException raise: NSGenericException
|
||
|
format: @"attempt to append illegal path component"];
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
p.x = currentPoint.x + aPoint.x;
|
||
|
p.y = currentPoint.y + aPoint.y;
|
||
|
[self lineToPoint: p];
|
||
|
}
|
||
|
|
||
|
- (void)relativeCurveToPoint:(NSPoint)aPoint
|
||
|
controlPoint1:(NSPoint)controlPoint1
|
||
|
controlPoint2:(NSPoint)controlPoint2
|
||
|
{
|
||
|
NSPoint p, cp1, cp2;
|
||
|
|
||
|
if(![pathElements count]) {
|
||
|
[NSException raise: NSGenericException
|
||
|
format: @"attempt to append illegal path component"];
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
p.x = currentPoint.x + aPoint.x;
|
||
|
p.y = currentPoint.y + aPoint.y;
|
||
|
cp1.x = currentPoint.x + controlPoint1.x;
|
||
|
cp1.y = currentPoint.y + controlPoint1.y;
|
||
|
cp2.x = currentPoint.x + controlPoint2.x;
|
||
|
cp2.y = currentPoint.y + controlPoint2.y;
|
||
|
[self curveToPoint: p controlPoint1: cp1 controlPoint2: cp2];
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Appending paths and some common shapes
|
||
|
//
|
||
|
- (void)appendBezierPath:(NSBezierPath *)aPath
|
||
|
{
|
||
|
NSArray *pathelems;
|
||
|
PathElement *last, *elm;
|
||
|
NSBezierPathElementType t1, t2;
|
||
|
NSPoint p, *p1, *p2;
|
||
|
int i;
|
||
|
|
||
|
if(![pathElements count]) {
|
||
|
[subPaths addObject: aPath];
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
last = [self lastElement];
|
||
|
t1 = [last type];
|
||
|
elm = [aPath lastElement];
|
||
|
t2 = [elm type];
|
||
|
|
||
|
if(t1 == NSBezierPathElementClose || t2 == NSBezierPathElementClose) {
|
||
|
[subPaths addObject: aPath];
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
p1 = [last points];
|
||
|
if(t1 == NSBezierPathElementCurveTo)
|
||
|
p = NSMakePoint(p1[2].x, p1[2].y);
|
||
|
else
|
||
|
p = NSMakePoint(p1[0].x, p1[0].y);
|
||
|
|
||
|
elm = [aPath moveToElement];
|
||
|
p2 = [elm points];
|
||
|
|
||
|
if((p.x != p2[0].x) || (p.y != p2[0].y)) {
|
||
|
[subPaths addObject: aPath];
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
pathelems = [aPath pathElements];
|
||
|
for(i = 1; i < [pathelems count]; i++) {
|
||
|
elm = [pathelems objectAtIndex: i];
|
||
|
t2 = [elm type];
|
||
|
p2 = [elm points];
|
||
|
if(t2 == NSBezierPathElementCurveTo)
|
||
|
[self curveToPoint: p2[2] controlPoint1: p2[0] controlPoint2: p2[1]];
|
||
|
else
|
||
|
[self lineToPoint: p2[0]];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
- (void)appendBezierPathWithPoints:(NSPoint *)points count:(int)count
|
||
|
{
|
||
|
int i, c;
|
||
|
|
||
|
if([[self lastElement] type] == NSBezierPathElementClose)
|
||
|
return;
|
||
|
|
||
|
if(![pathElements count]) {
|
||
|
[self moveToPoint: points[0]];
|
||
|
c = 1;
|
||
|
} else {
|
||
|
c = 0;
|
||
|
}
|
||
|
for(i = c; i < count; i++)
|
||
|
[self lineToPoint: points[i]];
|
||
|
}
|
||
|
|
||
|
- (void)appendBezierPathWithOvalInRect:(NSRect)aRect
|
||
|
{
|
||
|
NSBezierPath *path = [self pathWithOvalInRect: aRect];
|
||
|
[subPaths addObject: path];
|
||
|
}
|
||
|
|
||
|
- (void)appendBezierPathWithArcWithCenter:(NSPoint)center
|
||
|
radius:(float)radius
|
||
|
startAngle:(float)startAngle
|
||
|
endAngle:(float)endAngle
|
||
|
{
|
||
|
NSRect r;
|
||
|
NSBezierPath *path, *npath;
|
||
|
NSMutableArray *pelements;
|
||
|
PathElement *elm;
|
||
|
float tmpangle, diffangle, strtangrd, endangrd;
|
||
|
NSPoint p, *pts;
|
||
|
int index;
|
||
|
|
||
|
if(startAngle < 0)
|
||
|
startAngle = 360 + startAngle;
|
||
|
|
||
|
if(endAngle < 0)
|
||
|
endAngle = 360 + endAngle;
|
||
|
|
||
|
if(endAngle < startAngle) {
|
||
|
tmpangle = endAngle;
|
||
|
endAngle = startAngle;
|
||
|
startAngle = tmpangle;
|
||
|
}
|
||
|
|
||
|
strtangrd = PI * startAngle / 180;
|
||
|
endangrd = PI * endAngle / 180;
|
||
|
|
||
|
r = NSMakeRect(center.x - radius, center.y - radius, radius * 2, radius * 2);
|
||
|
path = [self pathWithOvalInRect: r];
|
||
|
[path rotateByAngle: -90 center: center];
|
||
|
[path rotateByAngle: startAngle center: center];
|
||
|
|
||
|
npath = [NSBezierPath bezierPath];
|
||
|
elm = [path moveToElement];
|
||
|
p = [elm points][0];
|
||
|
[npath moveToPoint: p];
|
||
|
|
||
|
pelements = [path pathElements];
|
||
|
diffangle = endAngle - startAngle;
|
||
|
index = 1;
|
||
|
while(diffangle >= 90) {
|
||
|
elm = [pelements objectAtIndex: index];
|
||
|
pts = [elm points];
|
||
|
[npath curveToPoint: pts[2] controlPoint1: pts[0] controlPoint2: pts[1]];
|
||
|
diffangle -= 90;
|
||
|
index++;
|
||
|
}
|
||
|
if(diffangle == 0) {
|
||
|
[self appendBezierPath: npath];
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
p = NSMakePoint(center.x + radius * cos(endangrd),
|
||
|
center.y + radius * sin(endangrd));
|
||
|
elm = [path pathElementSubdividingPathAtPoint: p
|
||
|
pathSegmentOwner: [pelements objectAtIndex: index]];
|
||
|
pts = [elm points];
|
||
|
[npath curveToPoint: pts[2] controlPoint1: pts[0] controlPoint2: pts[1]];
|
||
|
[self appendBezierPath: npath];
|
||
|
}
|
||
|
|
||
|
- (void)appendBezierPathWithGlyph:(NSGlyph)aGlyph inFont:(NSFont *)fontObj
|
||
|
{
|
||
|
|
||
|
|
||
|
|
||
|
}
|
||
|
|
||
|
- (void)appendBezierPathWithGlyphs:(NSGlyph *)glyphs
|
||
|
count:(int)count
|
||
|
inFont:(NSFont *)fontObj
|
||
|
{
|
||
|
|
||
|
}
|
||
|
|
||
|
- (void)appendBezierPathWithPackedGlyphs:(const char *)packedGlyphs
|
||
|
{
|
||
|
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Setting attributes
|
||
|
//
|
||
|
- (void)setWindingRule:(NSWindingRule)aWindingRule
|
||
|
{
|
||
|
windingRule = aWindingRule;
|
||
|
}
|
||
|
|
||
|
- (NSWindingRule)windingRule
|
||
|
{
|
||
|
return windingRule;
|
||
|
}
|
||
|
|
||
|
+ (void)setLineCapStyle:(int)style
|
||
|
{
|
||
|
[[NSGraphicsContext currentContext] DPSsetlinecap: style];
|
||
|
}
|
||
|
|
||
|
+ (void)setLineJoinStyle:(int)style
|
||
|
{
|
||
|
[[NSGraphicsContext currentContext] DPSsetlinejoin: style];
|
||
|
}
|
||
|
|
||
|
+ (void)setLineWidth:(float)width
|
||
|
{
|
||
|
[[NSGraphicsContext currentContext] DPSsetlinewidth: width];
|
||
|
}
|
||
|
|
||
|
+ (void)setMiterLimit:(float)limit
|
||
|
{
|
||
|
[[NSGraphicsContext currentContext] DPSsetmiterlimit: limit];
|
||
|
}
|
||
|
|
||
|
+ (void)setFlatness:(float)flatness
|
||
|
{
|
||
|
[[NSGraphicsContext currentContext] DPSsetflat: flatness];
|
||
|
}
|
||
|
|
||
|
+ (void)setHalftonePhase:(float)x : (float)y
|
||
|
{
|
||
|
[[NSGraphicsContext currentContext] DPSsethalftonephase: x : y];
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Drawing paths
|
||
|
//
|
||
|
- (void)stroke
|
||
|
{
|
||
|
PathElement *elm;
|
||
|
NSBezierPathElementType t;
|
||
|
NSPoint *pts;
|
||
|
int i;
|
||
|
|
||
|
for(i = 0; i < [pathElements count]; i++) {
|
||
|
elm = [pathElements objectAtIndex: i];
|
||
|
pts = [elm points];
|
||
|
t = [elm type];
|
||
|
switch(t) {
|
||
|
case NSBezierPathElementMoveTo:
|
||
|
PSmoveto(pts[0].x, pts[0].y);
|
||
|
break;
|
||
|
case NSBezierPathElementLineTo:
|
||
|
PSlineto(pts[0].x, pts[0].y);
|
||
|
break;
|
||
|
case NSBezierPathElementCurveTo:
|
||
|
PScurveto(pts[0].x, pts[0].y, pts[1].x, pts[1].y, pts[2].x, pts[2].y);
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
PSstroke();
|
||
|
|
||
|
for(i = 0; i < [subPaths count]; i++)
|
||
|
[[subPaths objectAtIndex: i] stroke];
|
||
|
}
|
||
|
|
||
|
- (void)fill
|
||
|
{
|
||
|
PathElement *elm;
|
||
|
NSBezierPathElementType t;
|
||
|
NSPoint *pts;
|
||
|
int i;
|
||
|
|
||
|
for(i = 0; i < [pathElements count]; i++) {
|
||
|
elm = [pathElements objectAtIndex: i];
|
||
|
pts = [elm points];
|
||
|
t = [elm type];
|
||
|
switch(t) {
|
||
|
case NSBezierPathElementMoveTo:
|
||
|
PSmoveto(pts[0].x, pts[0].y);
|
||
|
break;
|
||
|
case NSBezierPathElementLineTo:
|
||
|
PSlineto(pts[0].x, pts[0].y);
|
||
|
break;
|
||
|
case NSBezierPathElementCurveTo:
|
||
|
PScurveto(pts[0].x, pts[0].y, pts[1].x, pts[1].y, pts[2].x, pts[2].y);
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if(windingRule == NSWindingRuleNonZero)
|
||
|
PSfill();
|
||
|
else
|
||
|
PSeofill();
|
||
|
|
||
|
for(i = 0; i < [subPaths count]; i++)
|
||
|
[[subPaths objectAtIndex: i] fill];
|
||
|
}
|
||
|
|
||
|
+ (void)fillRect:(NSRect)aRect
|
||
|
{
|
||
|
NSBezierPath *path = [NSBezierPath bezierPathWithRect: aRect];
|
||
|
[path fill];
|
||
|
}
|
||
|
|
||
|
+ (void)strokeRect:(NSRect)aRect
|
||
|
{
|
||
|
NSBezierPath *path = [NSBezierPath bezierPathWithRect: aRect];
|
||
|
[path stroke];
|
||
|
}
|
||
|
|
||
|
+ (void)strokeLineFromPoint:(NSPoint)point1 toPoint:(NSPoint)point2
|
||
|
{
|
||
|
NSBezierPath *path = [NSBezierPath bezierPath];
|
||
|
[path moveToPoint: point1];
|
||
|
[path lineToPoint: point2];
|
||
|
[path stroke];
|
||
|
}
|
||
|
|
||
|
+ (void)drawPackedGlyphs:(const char *)packedGlyphs atPoint:(NSPoint)aPoint
|
||
|
{
|
||
|
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Clipping paths
|
||
|
//
|
||
|
- (void)addClip
|
||
|
{
|
||
|
|
||
|
}
|
||
|
|
||
|
- (void)setClip
|
||
|
{
|
||
|
|
||
|
}
|
||
|
|
||
|
+ (void)clipRect:(NSRect)aRect
|
||
|
{
|
||
|
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Hit detection
|
||
|
//
|
||
|
- (BOOL)isHitByPoint:(NSPoint)aPoint
|
||
|
{
|
||
|
if(inPath(self, aPoint) == INTERIOR)
|
||
|
return YES;
|
||
|
|
||
|
return NO;
|
||
|
}
|
||
|
|
||
|
- (BOOL)isHitByRect:(NSRect)aRect
|
||
|
{
|
||
|
NSPoint p;
|
||
|
|
||
|
p.x = aRect.origin.x;
|
||
|
p.y = aRect.origin.y;
|
||
|
if([self isHitByPoint: p])
|
||
|
return YES;
|
||
|
p.x = aRect.origin.x + aRect.size.width;
|
||
|
p.y = aRect.origin.y;
|
||
|
if([self isHitByPoint: p])
|
||
|
return YES;
|
||
|
p.x = aRect.origin.x + aRect.size.width;
|
||
|
p.y = aRect.origin.y + aRect.size.height;
|
||
|
if([self isHitByPoint: p])
|
||
|
return YES;
|
||
|
p.x = aRect.origin.x;
|
||
|
p.y = aRect.origin.y + aRect.size.height;
|
||
|
if([self isHitByPoint: p])
|
||
|
return YES;
|
||
|
|
||
|
return NO;
|
||
|
}
|
||
|
|
||
|
- (BOOL)isHitByPath:(NSBezierPath *)aBezierPath
|
||
|
{
|
||
|
NSPoint p, *pts;
|
||
|
int i;
|
||
|
|
||
|
pts = [aBezierPath draftPolygon];
|
||
|
for(i = 0; i < [aBezierPath pcount]; i++) {
|
||
|
p.x = pts[i].x;
|
||
|
p.y = pts[i].y;
|
||
|
if([self isHitByPoint: p])
|
||
|
return YES;
|
||
|
}
|
||
|
|
||
|
return NO;
|
||
|
}
|
||
|
|
||
|
- (BOOL)isStrokeHitByPoint:(NSPoint)aPoint
|
||
|
{
|
||
|
return onPathBorder(self, aPoint);
|
||
|
}
|
||
|
|
||
|
- (BOOL)isStrokeHitByRect:(NSRect)aRect
|
||
|
{
|
||
|
Line line;
|
||
|
int i;
|
||
|
|
||
|
for(i = 1; i < pcount; i++) {
|
||
|
line.p1.x = draftPolygon[i-1].x;
|
||
|
line.p1.y = draftPolygon[i-1].y;
|
||
|
line.p2.x = draftPolygon[i].x;
|
||
|
line.p2.y = draftPolygon[i].y;
|
||
|
if(intersectRect(aRect, line))
|
||
|
return YES;
|
||
|
}
|
||
|
|
||
|
return NO;
|
||
|
}
|
||
|
|
||
|
- (BOOL)isStrokeHitByPath:(NSBezierPath *)aBezierPath
|
||
|
{
|
||
|
return [self isHitByPath: aBezierPath];
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Querying paths
|
||
|
//
|
||
|
- (NSRect)bounds
|
||
|
{
|
||
|
PathElement *elm;
|
||
|
NSBezierPathElementType t;
|
||
|
NSPoint *pts, *pp;
|
||
|
float maxx, minx, maxy, miny;
|
||
|
int i, count = 0;
|
||
|
|
||
|
for(i = 0; i < [pathElements count]; i++) {
|
||
|
elm = [pathElements objectAtIndex: i];
|
||
|
pts = [elm points];
|
||
|
t = [elm type];
|
||
|
if(t == NSBezierPathElementMoveTo || t == NSBezierPathElementLineTo) {
|
||
|
pp[count].x = pts[0].x;
|
||
|
pp[count].y = pts[0].y;
|
||
|
count++;
|
||
|
} else if(t == NSBezierPathElementCurveTo) {
|
||
|
pp[count].x = pts[2].x;
|
||
|
pp[count].y = pts[2].y;
|
||
|
count++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
maxx = minx = pp[0].x;
|
||
|
maxy = miny = pp[0].x;
|
||
|
for(i = 0; i < count; i++) {
|
||
|
if(pp[i].x > maxx)
|
||
|
maxx = pp[i].x;
|
||
|
if(pp[i].x < minx)
|
||
|
minx = pp[i].x;
|
||
|
if(pp[i].y > maxy)
|
||
|
maxy = pp[i].y;
|
||
|
if(pp[i].y < minx)
|
||
|
minx = pp[i].y;
|
||
|
}
|
||
|
|
||
|
return NSMakeRect(minx, miny, maxx - minx, maxy - miny);
|
||
|
}
|
||
|
|
||
|
- (NSRect)controlPointBounds
|
||
|
{
|
||
|
PathElement *elm;
|
||
|
NSBezierPathElementType t;
|
||
|
NSPoint *pts, *pp;
|
||
|
float maxx, minx, maxy, miny;
|
||
|
int i, count = 0;
|
||
|
|
||
|
for(i = 0; i < [pathElements count]; i++) {
|
||
|
elm = [pathElements objectAtIndex: i];
|
||
|
pts = [elm points];
|
||
|
t = [elm type];
|
||
|
if(t == NSBezierPathElementMoveTo || t == NSBezierPathElementLineTo) {
|
||
|
pp[count].x = pts[0].x;
|
||
|
pp[count].y = pts[0].y;
|
||
|
count++;
|
||
|
} else if(t == NSBezierPathElementCurveTo) {
|
||
|
pp[count].x = pts[0].x;
|
||
|
pp[count].y = pts[0].y;
|
||
|
count++;
|
||
|
pp[count].x = pts[1].x;
|
||
|
pp[count].y = pts[1].y;
|
||
|
count++;
|
||
|
pp[count].x = pts[2].x;
|
||
|
pp[count].y = pts[2].y;
|
||
|
count++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
maxx = minx = pp[0].x;
|
||
|
maxy = miny = pp[0].x;
|
||
|
for(i = 0; i < count; i++) {
|
||
|
if(pp[i].x > maxx)
|
||
|
maxx = pp[i].x;
|
||
|
if(pp[i].x < minx)
|
||
|
minx = pp[i].x;
|
||
|
if(pp[i].y > maxy)
|
||
|
maxy = pp[i].y;
|
||
|
if(pp[i].y < minx)
|
||
|
minx = pp[i].y;
|
||
|
}
|
||
|
|
||
|
return NSMakeRect(minx, miny, maxx - minx, maxy - miny);
|
||
|
}
|
||
|
|
||
|
- (NSPoint)currentPoint
|
||
|
{
|
||
|
return currentPoint;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Accessing elements of a path
|
||
|
//
|
||
|
- (int)elementCount
|
||
|
{
|
||
|
return [pathElements count];
|
||
|
}
|
||
|
|
||
|
- (NSBezierPathElementType)elementTypeAtIndex:(int)index
|
||
|
{
|
||
|
return [(PathElement *)[pathElements objectAtIndex: index] type];
|
||
|
}
|
||
|
|
||
|
- (NSBezierPathElementType)elementTypeAtIndex:(int)index
|
||
|
associatedPoints:(NSPoint *)points
|
||
|
{
|
||
|
PathElement *elm = [pathElements objectAtIndex: index];
|
||
|
points = [elm points];
|
||
|
return [elm type];
|
||
|
}
|
||
|
|
||
|
- (void)removeLastElement
|
||
|
{
|
||
|
[pathElements removeObjectAtIndex: [pathElements count]-1];
|
||
|
}
|
||
|
|
||
|
- (int)pointCount
|
||
|
{
|
||
|
NSBezierPathElementType t;
|
||
|
int i, count = 0;
|
||
|
|
||
|
for(i = 0; i < [pathElements count]; i++) {
|
||
|
t = [(PathElement *)[pathElements objectAtIndex: i] type];
|
||
|
if(t == NSBezierPathElementMoveTo || t == NSBezierPathElementLineTo)
|
||
|
count++;
|
||
|
else if(t == NSBezierPathElementCurveTo)
|
||
|
count += 3;
|
||
|
}
|
||
|
|
||
|
return count;
|
||
|
}
|
||
|
|
||
|
- (NSPoint)pointAtIndex:(int)index
|
||
|
{
|
||
|
PathElement *elm;
|
||
|
NSBezierPathElementType t;
|
||
|
NSPoint p, *pts;
|
||
|
int i, j, count = 0;
|
||
|
|
||
|
for(i = 0; i < [pathElements count]; i++) {
|
||
|
elm = [pathElements objectAtIndex: i];
|
||
|
pts = [elm points];
|
||
|
t = [elm type];
|
||
|
|
||
|
if(t == NSBezierPathElementMoveTo || t == NSBezierPathElementLineTo) {
|
||
|
count++;
|
||
|
if(count == index) {
|
||
|
p.x = pts[0].x;
|
||
|
p.y = pts[0].y;
|
||
|
break;
|
||
|
}
|
||
|
} else if(t == NSBezierPathElementCurveTo) {
|
||
|
for(j = 0; j <= 3; j++) {
|
||
|
count++;
|
||
|
if(count == index) {
|
||
|
p.x = pts[j].x;
|
||
|
p.y = pts[j].y;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return p;
|
||
|
}
|
||
|
|
||
|
- (void)setPointAtIndex:(int)index toPoint:(NSPoint)aPoint
|
||
|
{
|
||
|
PathElement *elm;
|
||
|
int eindex, fpointind, localind;
|
||
|
|
||
|
eindex = [self pathElementIndexForPointIndex: index];
|
||
|
elm = [pathElements objectAtIndex: eindex];
|
||
|
fpointind = [self pointIndexForPathElementIndex: eindex];
|
||
|
localind = index - fpointind;
|
||
|
[elm setPointAtIndex: localind toPoint: aPoint];
|
||
|
[self calculateDraftPolygon];
|
||
|
}
|
||
|
|
||
|
- (int)pointIndexForPathElementIndex:(int)index
|
||
|
{
|
||
|
PathElement *elm;
|
||
|
NSBezierPathElementType t;
|
||
|
NSPoint *pts;
|
||
|
int i, j, pindex = -1;
|
||
|
|
||
|
for(i = 0; i <= index; i++) {
|
||
|
elm = [pathElements objectAtIndex: i];
|
||
|
pts = [elm points];
|
||
|
t = [elm type];
|
||
|
|
||
|
if(t == NSBezierPathElementMoveTo || t == NSBezierPathElementLineTo) {
|
||
|
pindex++;
|
||
|
} else if(t == NSBezierPathElementCurveTo) {
|
||
|
if(i < index)
|
||
|
for(j = 0; j <= 3; j++)
|
||
|
pindex++;
|
||
|
else
|
||
|
pindex++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return pindex;
|
||
|
}
|
||
|
|
||
|
- (int)pathElementIndexForPointIndex:(int)index
|
||
|
{
|
||
|
PathElement *elm;
|
||
|
NSBezierPathElementType t;
|
||
|
NSPoint *pts;
|
||
|
int pindex = 0, j, elemindex = 0;
|
||
|
|
||
|
while(elemindex < [pathElements count]) {
|
||
|
elm = [pathElements objectAtIndex: elemindex];
|
||
|
pts = [elm points];
|
||
|
t = [elm type];
|
||
|
|
||
|
if(t == NSBezierPathElementMoveTo || t == NSBezierPathElementLineTo) {
|
||
|
pindex++;
|
||
|
elemindex++;
|
||
|
if(pindex == index)
|
||
|
break;
|
||
|
} else if(t == NSBezierPathElementCurveTo) {
|
||
|
elemindex++;
|
||
|
for(j = 0; j <= 3; j++) {
|
||
|
pindex++;
|
||
|
if(pindex == index)
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return elemindex;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Caching paths
|
||
|
//
|
||
|
- (BOOL)cachesBezierPath
|
||
|
{
|
||
|
return cachesBezierPath;
|
||
|
}
|
||
|
|
||
|
- (void)setCachesBezierPath:(BOOL)flag
|
||
|
{
|
||
|
cachesBezierPath = flag;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// NSCoding protocol
|
||
|
//
|
||
|
- (void)encodeWithCoder:(NSCoder*)aCoder
|
||
|
{
|
||
|
[super encodeWithCoder: aCoder];
|
||
|
}
|
||
|
|
||
|
- (id)initWithCoder:(NSCoder*)aCoder
|
||
|
{
|
||
|
[super initWithCoder: aCoder];
|
||
|
return self;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// NSCopying Protocol
|
||
|
//
|
||
|
- (id)copyWithZone:(NSZone*)zone
|
||
|
{
|
||
|
return self;
|
||
|
}
|
||
|
|
||
|
@end
|
||
|
|
||
|
|
||
|
@implementation NSBezierPath (PrivateMethods)
|
||
|
|
||
|
- (void)setCurrentPoint:(NSPoint)aPoint
|
||
|
{
|
||
|
currentPoint.x = aPoint.x;
|
||
|
currentPoint.y = aPoint.y;
|
||
|
}
|
||
|
|
||
|
- (BOOL)isPathElement:(PathElement *)elm1 onPathElement:(PathElement *)elm2
|
||
|
{
|
||
|
NSPoint p1, p2;
|
||
|
NSBezierPathElementType t;
|
||
|
|
||
|
t = [elm1 type];
|
||
|
if(t == NSBezierPathElementMoveTo || t == NSBezierPathElementLineTo) {
|
||
|
p1.x = [elm1 points][0].x;
|
||
|
p1.y = [elm1 points][0].y;
|
||
|
} else if(t == NSBezierPathElementCurveTo) {
|
||
|
p1.x = [elm1 points][2].x;
|
||
|
p1.y = [elm1 points][2].y;
|
||
|
} else {
|
||
|
return NO;
|
||
|
}
|
||
|
|
||
|
t = [elm2 type];
|
||
|
if(t == NSBezierPathElementMoveTo || t == NSBezierPathElementLineTo) {
|
||
|
p2.x = [elm2 points][0].x;
|
||
|
p2.y = [elm2 points][0].y;
|
||
|
} else if(t == NSBezierPathElementCurveTo) {
|
||
|
p2.x = [elm2 points][2].x;
|
||
|
p2.y = [elm2 points][2].y;
|
||
|
} else {
|
||
|
return NO;
|
||
|
}
|
||
|
|
||
|
if(p1.x == p2.x && p1.y == p2.y)
|
||
|
return YES;
|
||
|
|
||
|
return NO;
|
||
|
}
|
||
|
|
||
|
- (NSMutableArray *)pathElements
|
||
|
{
|
||
|
return pathElements;
|
||
|
}
|
||
|
|
||
|
- (PathElement *)moveToElement
|
||
|
{
|
||
|
return [pathElements objectAtIndex: 0];
|
||
|
}
|
||
|
|
||
|
- (PathElement *)lastElement
|
||
|
{
|
||
|
return [pathElements objectAtIndex: [pathElements count] -1];
|
||
|
}
|
||
|
|
||
|
- (int)indexOfElement:(PathElement *)element
|
||
|
{
|
||
|
PathElement *elm;
|
||
|
int i;
|
||
|
|
||
|
for(i = 0; i < [pathElements count]; i++) {
|
||
|
elm = [pathElements objectAtIndex: i];
|
||
|
if(elm == element)
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return i;
|
||
|
}
|
||
|
|
||
|
- (PathElement *)elementPrecedingElement:(PathElement *)element
|
||
|
{
|
||
|
PathElement *prevelm;
|
||
|
int index;
|
||
|
|
||
|
index = [self indexOfElement: element];
|
||
|
if(index == 0)
|
||
|
prevelm = [pathElements objectAtIndex: [pathElements count] -1];
|
||
|
else
|
||
|
prevelm = [pathElements objectAtIndex: index -1];
|
||
|
|
||
|
|
||
|
// ATTENZIONE !!!!!
|
||
|
// COSA FARE SE IL PATH E' APERTO ??????????????
|
||
|
// ATTENZIONE !!!!!
|
||
|
// E SE E' DI TYPO CLOSEPATH ???????????????
|
||
|
|
||
|
|
||
|
return prevelm;
|
||
|
}
|
||
|
|
||
|
- (void)calculateDraftPolygon
|
||
|
{
|
||
|
PathElement *elm;
|
||
|
NSBezierPathElementType bpt;
|
||
|
NSPoint p, *pts;
|
||
|
double x, y, t, k = 0.025;
|
||
|
int i;
|
||
|
|
||
|
pcount = 0;
|
||
|
for(i = 0; i < [pathElements count]; i++) {
|
||
|
elm = [pathElements objectAtIndex: i];
|
||
|
bpt = [elm type];
|
||
|
pts = [elm points];
|
||
|
|
||
|
if(bpt == NSBezierPathElementMoveTo || bpt == NSBezierPathElementLineTo) {
|
||
|
draftPolygon[pcount].x = pts[0].x;
|
||
|
draftPolygon[pcount].y = pts[0].y;
|
||
|
pcount++;
|
||
|
} else if(bpt == NSBezierPathElementCurveTo) {
|
||
|
if(pcount) {
|
||
|
p.x = draftPolygon[pcount -1].x;
|
||
|
p.y = draftPolygon[pcount -1].y;
|
||
|
} else {
|
||
|
p.x = pts[0].x;
|
||
|
p.y = pts[0].y;
|
||
|
}
|
||
|
for(t = k; t <= 1+k; t += k) {
|
||
|
x = (p.x+t*(-p.x*3+t*(3*p.x-p.x*t)))
|
||
|
+t*(3*pts[0].x+t*(-6*pts[0].x+pts[0].x*3*t))
|
||
|
+t*t*(pts[1].x*3-pts[1].x*3*t)+pts[2].x*t*t*t;
|
||
|
y = (p.y+t*(-p.y*3+t*(3*p.y-p.y*t)))
|
||
|
+t*(3*pts[0].y+t*(-6*pts[0].y+pts[0].y*3*t))
|
||
|
+t*t*(pts[1].y*3-pts[1].y*3*t)+pts[2].y*t*t*t;
|
||
|
|
||
|
draftPolygon[pcount].x = x;
|
||
|
draftPolygon[pcount].y = y;
|
||
|
pcount++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
- (NSPoint *)draftPolygon
|
||
|
{
|
||
|
return draftPolygon;
|
||
|
}
|
||
|
|
||
|
- (int)pcount
|
||
|
{
|
||
|
return pcount;
|
||
|
}
|
||
|
|
||
|
- (NSBezierPath *)pathWithOvalInRect:(NSRect)aRect
|
||
|
{
|
||
|
NSBezierPath *path;
|
||
|
NSPoint p, p1, p2;
|
||
|
double originx = aRect.origin.x;
|
||
|
double originy = aRect.origin.y;
|
||
|
double width = aRect.size.width;
|
||
|
double height = aRect.size.height;
|
||
|
double hdiff = width / 2 * 0.5522847498;
|
||
|
double vdiff = height / 2 * 0.5522847498;
|
||
|
|
||
|
path = [NSBezierPath bezierPath];
|
||
|
p = NSMakePoint(originx + width / 2, originy + height);
|
||
|
[path moveToPoint: p];
|
||
|
|
||
|
p = NSMakePoint(originx, originy + height / 2);
|
||
|
p1 = NSMakePoint(originx + width / 2 - hdiff, originy + height);
|
||
|
p2 = NSMakePoint(originx, originy + height / 2 + vdiff);
|
||
|
[path curveToPoint: p controlPoint1: p1 controlPoint2: p2];
|
||
|
|
||
|
p = NSMakePoint(originx + width / 2, originy);
|
||
|
p1 = NSMakePoint(originx, originy + height / 2 - vdiff);
|
||
|
p2 = NSMakePoint(originx + width / 2 - hdiff, originy);
|
||
|
[path curveToPoint: p controlPoint1: p1 controlPoint2: p2];
|
||
|
|
||
|
p = NSMakePoint(originx + width, originy + height / 2);
|
||
|
p1 = NSMakePoint(originx + width / 2 + hdiff, originy);
|
||
|
p2 = NSMakePoint(originx + width, originy + height / 2 - vdiff);
|
||
|
[path curveToPoint: p controlPoint1: p1 controlPoint2: p2];
|
||
|
|
||
|
p = NSMakePoint(originx + width / 2, originy + height);
|
||
|
p1 = NSMakePoint(originx + width, originy + height / 2 + vdiff);
|
||
|
p2 = NSMakePoint(originx + width / 2 + hdiff, originy + height);
|
||
|
[path curveToPoint: p controlPoint1: p1 controlPoint2: p2];
|
||
|
|
||
|
return path;
|
||
|
}
|
||
|
|
||
|
- (void)movePathToPoint:(NSPoint)p
|
||
|
{
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
}
|
||
|
|
||
|
- (void)rotateByAngle:(float)angle center:(NSPoint)center
|
||
|
{
|
||
|
PathElement *elm;
|
||
|
NSBezierPathElementType t;
|
||
|
NSPoint p, *pts;
|
||
|
int i;
|
||
|
|
||
|
for(i = 0; i < [pathElements count]; i++) {
|
||
|
elm = [pathElements objectAtIndex: i];
|
||
|
pts = [elm points];
|
||
|
t = [elm type];
|
||
|
if(t == NSBezierPathElementCurveTo) {
|
||
|
p = rotatePoint(pts[0], center, angle);
|
||
|
[elm setPointAtIndex: 0 toPoint: p];
|
||
|
p = rotatePoint(pts[1], center, angle);
|
||
|
[elm setPointAtIndex: 1 toPoint: p];
|
||
|
p = rotatePoint(pts[2], center, angle);
|
||
|
[elm setPointAtIndex: 2 toPoint: p];
|
||
|
} else if(t == NSBezierPathElementMoveTo || t == NSBezierPathElementLineTo) {
|
||
|
p = rotatePoint(pts[0], center, angle);
|
||
|
[elm setPointAtIndex: 0 toPoint: p];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
- (pointOnCurve)pointOnPathSegmentOfElement:(PathElement *)elm
|
||
|
nearestToPoint:(NSPoint)p
|
||
|
{
|
||
|
pointOnCurve pc;
|
||
|
PathElement *prevelm;
|
||
|
NSPoint *pp1, *pp2, cpp[4];
|
||
|
double x, y, d, dmin = 10000, t, k = 0.001;
|
||
|
|
||
|
prevelm = [self elementPrecedingElement: elm];
|
||
|
if([prevelm type] == NSBezierPathElementClose)
|
||
|
prevelm = [self elementPrecedingElement: prevelm];
|
||
|
|
||
|
pp1 = [prevelm points];
|
||
|
pp2 = [elm points];
|
||
|
|
||
|
if([prevelm type] == NSBezierPathElementCurveTo) {
|
||
|
cpp[0].x = pp1[2].x;
|
||
|
cpp[0].y = pp1[2].y;
|
||
|
} else {
|
||
|
cpp[0].x = pp1[0].x;
|
||
|
cpp[0].y = pp1[0].y;
|
||
|
}
|
||
|
|
||
|
if([elm type] == NSBezierPathElementCurveTo) {
|
||
|
cpp[1].x = pp2[0].x;
|
||
|
cpp[1].y = pp2[0].y;
|
||
|
cpp[2].x = pp2[1].x;
|
||
|
cpp[2].y = pp2[1].y;
|
||
|
cpp[3].x = pp2[2].x;
|
||
|
cpp[3].y = pp2[2].y;
|
||
|
} else {
|
||
|
cpp[1].x = cpp[0].x;
|
||
|
cpp[1].y = cpp[0].y;
|
||
|
cpp[2].x = pp2[0].x;
|
||
|
cpp[2].y = pp2[0].y;
|
||
|
cpp[3].x = pp2[0].x;
|
||
|
cpp[3].y = pp2[0].y;
|
||
|
}
|
||
|
|
||
|
for(t = k; t <= 1+k; t += k) {
|
||
|
x = (cpp[0].x+t*(-cpp[0].x*3+t*(3*cpp[0].x-cpp[0].x*t)))
|
||
|
+t*(3*cpp[1].x+t*(-6*cpp[1].x+cpp[1].x*3*t))
|
||
|
+t*t*(cpp[2].x*3-cpp[2].x*3*t)+cpp[3].x*t*t*t;
|
||
|
y = (cpp[0].y+t*(-cpp[0].y*3+t*(3*cpp[0].y-cpp[0].y*t)))
|
||
|
+t*(3*cpp[1].y+t*(-6*cpp[1].y+cpp[1].y*3*t))
|
||
|
+t*t*(cpp[2].y*3-cpp[2].y*3*t)+cpp[3].y*t*t*t;
|
||
|
|
||
|
d = pow(pow(x - p.x, 2) + pow(y - p.y, 2), 0.5);
|
||
|
if(d < dmin) {
|
||
|
dmin = d;
|
||
|
pc.p = NSMakePoint(x, y);
|
||
|
pc.t = t - k;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return pc;
|
||
|
}
|
||
|
|
||
|
- (PathElement *)pathElementSubdividingPathAtPoint:(NSPoint)p
|
||
|
pathSegmentOwner:(PathElement *)owner
|
||
|
{
|
||
|
PathElement *prevelm, *elm;
|
||
|
NSPoint *ownerpts, *prevpts;
|
||
|
pointOnCurve pc;
|
||
|
float coeffx[4], coeffy[4], bleftx[4], blefty[4], brightx[4], brighty[4];
|
||
|
|
||
|
prevelm = [self elementPrecedingElement: owner];
|
||
|
if([prevelm type] == NSBezierPathElementClose)
|
||
|
prevelm = [self elementPrecedingElement: prevelm];
|
||
|
prevpts = [prevelm points];
|
||
|
ownerpts = [owner points];
|
||
|
pc = [self pointOnPathSegmentOfElement: owner nearestToPoint: p];
|
||
|
|
||
|
if([prevelm type] == NSBezierPathElementCurveTo) {
|
||
|
coeffx[0] = prevpts[2].x;
|
||
|
coeffy[0] = prevpts[2].y;
|
||
|
} else {
|
||
|
coeffx[0] = prevpts[0].x;
|
||
|
coeffy[0] = prevpts[0].y;
|
||
|
}
|
||
|
if([owner type] == NSBezierPathElementCurveTo) {
|
||
|
coeffx[1] = ownerpts[0].x;
|
||
|
coeffy[1] = ownerpts[0].y;
|
||
|
coeffx[2] = ownerpts[1].x;
|
||
|
coeffy[2] = ownerpts[1].y;
|
||
|
coeffx[3] = ownerpts[2].x;
|
||
|
coeffy[3] = ownerpts[2].y;
|
||
|
} else {
|
||
|
coeffx[1] = ownerpts[0].x;
|
||
|
coeffy[1] = ownerpts[0].y;
|
||
|
coeffx[2] = ownerpts[0].x;
|
||
|
coeffy[2] = ownerpts[0].y;
|
||
|
coeffx[3] = ownerpts[0].x;
|
||
|
coeffy[3] = ownerpts[0].y;
|
||
|
}
|
||
|
|
||
|
subdiv(3, coeffx, pc.t, bleftx, brightx);
|
||
|
subdiv(3, coeffy, pc.t, blefty, brighty);
|
||
|
|
||
|
elm = [PathElement pathElement];
|
||
|
[elm setType: NSBezierPathElementCurveTo];
|
||
|
[elm setPointAtIndex: 0 toPoint: NSMakePoint(bleftx[2], blefty[2])];
|
||
|
[elm setPointAtIndex: 1 toPoint: NSMakePoint(bleftx[1], blefty[1])];
|
||
|
[elm setPointAtIndex: 2 toPoint: p];
|
||
|
|
||
|
[owner setType: NSBezierPathElementCurveTo];
|
||
|
[owner setPointAtIndex: 0 toPoint: NSMakePoint(brightx[1], brighty[1])];
|
||
|
[owner setPointAtIndex: 1 toPoint: NSMakePoint(brightx[2], brighty[2])];
|
||
|
|
||
|
return elm;
|
||
|
}
|
||
|
|
||
|
@end
|
||
|
|
||
|
//
|
||
|
// Functions
|
||
|
//
|
||
|
pointPosition inPath(NSBezierPath *aPath, NSPoint p)
|
||
|
{
|
||
|
NSPoint *pts;
|
||
|
int xs[PMAX], ys[PMAX];
|
||
|
double x;
|
||
|
int i, i1, pcount;
|
||
|
int Rcross = 0;
|
||
|
int Lcross = 0;
|
||
|
|
||
|
pts = [aPath draftPolygon];
|
||
|
pcount = [aPath pcount];
|
||
|
for(i = 0; i < pcount; i++) {
|
||
|
xs[i] = (int)pts[i].x - p.x;
|
||
|
ys[i] = (int)pts[i].y - p.y;
|
||
|
}
|
||
|
|
||
|
for(i = 0; i < pcount; i++) {
|
||
|
if(xs[i] == 0 && ys[i] == 0)
|
||
|
return VERTEX;
|
||
|
|
||
|
i1 = (i + pcount - 1) % pcount;
|
||
|
if((ys[i] > 0) != (ys[i1] > 0)) {
|
||
|
x = (xs[i] * (double)ys[i1] - xs[i1] * (double)ys[i])
|
||
|
/ (double)(ys[i1] - ys[i]);
|
||
|
if(x > 0)
|
||
|
Rcross++;
|
||
|
}
|
||
|
if((ys[i] < 0 ) != (ys[i1] < 0)) {
|
||
|
x = (xs[i] * ys[i1] - xs[i1] * ys[i])
|
||
|
/ (double)(ys[i1] - ys[i]);
|
||
|
if(x < 0)
|
||
|
Lcross++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if((Rcross % 2) != (Lcross % 2))
|
||
|
return ONBORDER;
|
||
|
if((Rcross % 2) == 1)
|
||
|
return INTERIOR;
|
||
|
else
|
||
|
return EXTERIOR;
|
||
|
}
|
||
|
|
||
|
BOOL onPathBorder(NSBezierPath *aPath, NSPoint p)
|
||
|
{
|
||
|
if(inPath(aPath, p) == ONBORDER)
|
||
|
return YES;
|
||
|
|
||
|
return NO;
|
||
|
}
|
||
|
|
||
|
int ccw(NSPoint p0, NSPoint p1, NSPoint p2)
|
||
|
{
|
||
|
int dx1, dx2, dy1, dy2;
|
||
|
|
||
|
dx1 = p1.x - p0.x;
|
||
|
dy1 = p1.y - p0.y;
|
||
|
dx2 = p2.x - p0.x;
|
||
|
dy2 = p2.y - p0.y;
|
||
|
|
||
|
if(dx1*dy2 > dy1*dx2)
|
||
|
return +1;
|
||
|
if(dx1*dy2 < dy1*dx2)
|
||
|
return -1;
|
||
|
if((dx1*dx2 < 0) || (dy1*dy2 < 0))
|
||
|
return -1;
|
||
|
if((dx1*dx1 + dy1*dy1) < (dx2*dx2 + dy2*dy2))
|
||
|
return +1;
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
BOOL intersect(Line line1, Line line2)
|
||
|
{
|
||
|
return ((ccw(line1.p1, line1.p2, line2.p1)
|
||
|
* ccw(line1.p1, line1.p2, line2.p2)) <= 0)
|
||
|
&& ((ccw(line2.p1, line2.p2, line1.p1)
|
||
|
* ccw(line2.p1, line2.p2, line1.p2)) <= 0);
|
||
|
}
|
||
|
|
||
|
BOOL intersectRect(NSRect rect, Line line)
|
||
|
{
|
||
|
Line line1, line2, line3, line4;
|
||
|
NSPoint topLeft, bottomRight;
|
||
|
double tmp;
|
||
|
|
||
|
line1.p1.x = rect.origin.x;
|
||
|
line1.p1.y = rect.origin.y + rect.size.height;
|
||
|
line1.p2.x = rect.origin.x + rect.size.width;
|
||
|
line1.p2.y = rect.origin.y + rect.size.height;
|
||
|
|
||
|
line2.p1.x = line1.p2.x;
|
||
|
line2.p1.y = line1.p2.y;
|
||
|
line2.p2.x = line2.p1.x;
|
||
|
line2.p2.y = rect.origin.y;
|
||
|
|
||
|
line3.p1.x = line2.p2.x;
|
||
|
line3.p1.y = line2.p2.y;
|
||
|
line3.p2.x = rect.origin.x;
|
||
|
line3.p2.y = rect.origin.y;
|
||
|
|
||
|
line4.p1.x = line3.p2.x;
|
||
|
line4.p1.y = line3.p2.y;
|
||
|
line4.p2.x = line1.p1.x;
|
||
|
line4.p2.y = line1.p1.y;
|
||
|
|
||
|
if(intersect(line1, line) || intersect(line2, line)
|
||
|
|| intersect(line3, line) || intersect(line4, line))
|
||
|
return YES;
|
||
|
|
||
|
topLeft.x = rect.origin.x;
|
||
|
topLeft.y = rect.origin.y + rect.size.height;
|
||
|
bottomRight.x = rect.origin.x + rect.size.width;
|
||
|
bottomRight.y = rect.origin.y;
|
||
|
|
||
|
if(bottomRight.x < topLeft.x) {
|
||
|
tmp = bottomRight.x;
|
||
|
bottomRight.x = topLeft.x;
|
||
|
topLeft.x = tmp;
|
||
|
}
|
||
|
if(bottomRight.y < topLeft.y) {
|
||
|
tmp = bottomRight.y;
|
||
|
bottomRight.y = topLeft.y;
|
||
|
topLeft.y = tmp;
|
||
|
}
|
||
|
|
||
|
return (line.p1.x >= topLeft.x && line.p1.x <= bottomRight.x
|
||
|
&& line.p1.y >= topLeft.y && line.p1.y <= bottomRight.y);
|
||
|
}
|
||
|
|
||
|
void subdiv(int degree, float coeff[], float t, float bleft[], float bright[])
|
||
|
{
|
||
|
int r, i;
|
||
|
float t1;
|
||
|
|
||
|
t1 = 1.0 - t;
|
||
|
|
||
|
// use Casteljeau to find the right Bezier polygon
|
||
|
for (i = 0; i <= degree; i++)
|
||
|
bright[i] = coeff[i];
|
||
|
|
||
|
for (r = 1; r <= degree; r++)
|
||
|
for (i = 0; i <= degree - r; i++)
|
||
|
bright[i] = t1 * bright[i] + t * bright[i + 1];
|
||
|
|
||
|
// to find the left Bezier polygon (inverse order)
|
||
|
t = 1.0 - t;
|
||
|
t1 = 1.0 - t;
|
||
|
|
||
|
for (i = 0; i <= degree; i++)
|
||
|
bleft[degree - i] = coeff[i];
|
||
|
|
||
|
for (r = 1; r <= degree; r++)
|
||
|
for (i = 0; i <= degree - r; i++)
|
||
|
bleft[i] = t1 * bleft[i] + t * bleft[i + 1];
|
||
|
}
|
||
|
|
||
|
NSPoint rotatePoint(NSPoint p, NSPoint centre, float angle)
|
||
|
{
|
||
|
NSPoint rp;
|
||
|
float rdangle = PI * angle / 180;
|
||
|
float dx, dy;
|
||
|
|
||
|
dx = p.x - centre.x;
|
||
|
dy = p.y - centre.y;
|
||
|
|
||
|
rp.x = (dx * cos(rdangle)) - (dy * sin(rdangle)) + centre.x;
|
||
|
rp.y = (dx * sin(rdangle)) + (dy * cos(rdangle)) + centre.y;
|
||
|
|
||
|
return rp;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|