1/*
2copyright 2004 Alexander Malmberg <alexander@malmberg.org>
3*/
4
5#include "Testing.h"
6
7#include <Foundation/NSAutoreleasePool.h>
8#include <AppKit/NSBezierPath.h>
9
10#include <math.h>
11
12
13#define nextafterf(x,y) next(x,y)
14
15static float next(float x,float y)
16{
17	if (y<x)
18		return x-(x?0.00001:0.000005);
19//		return x-(x?0.0001:0.00001);
20	else if (y>x)
21		return x+(x?0.00001:0.000005);
22//		return x+(x?0.0001:0.00001);
23	else
24		return y;
25}
26
27
28//#define DRAW
29
30#ifdef DRAW
31
32#include <AppKit/NSApplication.h>
33#include <AppKit/NSGraphics.h>
34#include <AppKit/NSView.h>
35#include <AppKit/NSWindow.h>
36#include <AppKit/PSOperators.h>
37
38@interface MyView : NSView
39-(void) clear;
40-(void) drawPath: (NSBezierPath *)p;
41-(void) drawPoint: (NSPoint)p count: (int)c;
42-(void) pause;
43@end
44
45#define MOVE \
46	{ \
47		double x0,y0,x1,y1; \
48		double w=800,h=800; \
49		\
50		x0=76.980; \
51		x1=76.981; \
52		y0=-0.0005; \
53		y1=0.0005; \
54		\
55		ww=w/(x1-x0); \
56		hh=h/(y1-y0); \
57		PSscale(ww,hh); \
58		PStranslate(-x0,-y0); \
59	}
60
61@implementation MyView
62-(void) clear
63{
64	[self lockFocus];
65	PSsetrgbcolor(1,1,1);
66	NSRectFill([self bounds]);
67	[self unlockFocus];
68	[[self window] flushWindow];
69}
70-(void) drawPath: (NSBezierPath *)p
71{
72	double ww,hh;
73	[self lockFocus];
74	MOVE
75	PSsetrgbcolor(0.8,0.4,0.4);
76	[p fill];
77	PSsetrgbcolor(0.3,1.0,0.3);
78	PSsetalpha(0.5);
79	[[p bezierPathByFlatteningPath] fill];
80	[self unlockFocus];
81	[[self window] flushWindow];
82}
83-(void) drawPoint: (NSPoint)p count: (int)c
84{
85#define NC 3
86static float colors[NC][3]={
87{1,0,0},
88{0,1,0},
89{0,0,1},
90};
91	double ww,hh;
92	c%=NC;
93	if (c<0)
94		c+=NC;
95	[self lockFocus];
96	MOVE
97	PSsetrgbcolor(colors[c][0],colors[c][1],colors[c][2]);
98	PSrectfill(p.x-4/ww,p.y-4/hh,8/ww,8/hh);
99	[self unlockFocus];
100	[[self window] flushWindow];
101#undef NC
102}
103-(void) pause
104{
105	char buf[128];
106	gets(buf);
107}
108@end
109
110MyView *view;
111
112#endif
113
114
115
116int main(int argc, char **argv)
117{
118	CREATE_AUTORELEASE_POOL(arp);
119	NSBezierPath *p=[[NSBezierPath alloc] init];
120	int i;
121	const char *str;
122	int X=-1000;
123
124
125#ifdef DRAW
126	{
127		NSWindow *w;
128
129		[NSApplication sharedApplication];
130		w=[[NSWindow alloc] initWithContentRect: NSMakeRect(50,50,800,800)
131			styleMask: NSTitledWindowMask
132			backing: NSBackingStoreRetained
133			defer: YES];
134
135		view=[[MyView alloc] init];
136		[w setContentView: view];
137		[w orderFront: nil];
138	}
139#endif
140
141#ifdef DRAW
142#define DP(e,x,y) [view drawPoint: NSMakePoint(x,y)  count: e];
143#define CLEAR [view clear];
144#define PAUSE [view pause];
145#define DRAWPATH [view drawPath: p];
146#else
147#define DP(e,x,y)
148#define CLEAR
149#define PAUSE
150#define DRAWPATH
151#endif
152
153#define T(e,x,y) \
154	{ \
155		int i,r; \
156		DP(e,x,y) \
157		r=[p windingCountAtPoint: NSMakePoint(x,y)]; \
158		for (i=5;i;i--) \
159		{ \
160			if ([p windingCountAtPoint: NSMakePoint(x,y)]!=r) \
161				break; \
162		} \
163		if (i) \
164		{ \
165			pass(NO, \
166				"path '%s', %15.8e %15.8e, expected %i, got inconsistant results", \
167				str,(double)x,(double)y, \
168				e); \
169		} \
170		else \
171		{ \
172			pass(r == e, \
173				"path '%s', %15.8e %15.8e, expected %i, got %i", \
174				str,(double)x,(double)y, \
175				e,r); \
176		} \
177	}
178
179#define CHECK_AROUND(x,y, p00,p10,p20, p01,p11,p21, p02,p12,p22) \
180	if (p00!=X) T(p00,nextafterf(x,-1000),nextafterf(y, 1000)) \
181	if (p10!=X) T(p10,           x       ,nextafterf(y, 1000)) \
182	if (p20!=X) T(p20,nextafterf(x, 1000),nextafterf(y, 1000)) \
183	\
184	if (p01!=X) T(p01,nextafterf(x,-1000),           y       ) \
185	if (p11!=X) T(p11,           x       ,           y       ) \
186	if (p21!=X) T(p21,nextafterf(x, 1000),           y       ) \
187	\
188	if (p02!=X) T(p02,nextafterf(x,-1000),nextafterf(y,-1000)) \
189	if (p12!=X) T(p12,           x       ,nextafterf(y,-1000)) \
190	if (p22!=X) T(p22,nextafterf(x, 1000),nextafterf(y,-1000))
191
192#if 1
193	str="empty";
194	T(0,0,0)
195
196
197	for (i=0;i<3;i++)
198	{
199		[p removeAllPoints];
200		[p moveToPoint: NSMakePoint(100,100)];
201		[p lineToPoint: NSMakePoint(100,200)];
202		[p lineToPoint: NSMakePoint(200,200)];
203		[p lineToPoint: NSMakePoint(200,100)];
204
205		if (i==0)
206		{
207			str="(u) rect";
208		}
209		else if (i==1)
210		{
211			[p closePath];
212			str="(c) rect";
213		}
214		else
215		{
216			[p lineToPoint: NSMakePoint(100,100)];
217			[p closePath];
218			str="(d) rect";
219		}
220
221		/* Obvious stuff. */
222		T(0,0,0)
223		T(1,150,150)
224
225		/* Check around each corner. */
226		CHECK_AROUND(100,100,
227			0,X,1,
228			0,X,X,
229			0,0,0)
230
231		CHECK_AROUND(200,100,
232			1,X,0,
233			X,X,0,
234			0,0,0)
235
236		CHECK_AROUND(200,200,
237			0,0,0,
238			X,X,0,
239			1,X,0)
240
241		CHECK_AROUND(100,200,
242			0,0,0,
243			0,X,X,
244			0,X,1)
245
246		if (!i)
247			[p closePath];
248	}
249
250
251	for (i=0;i<3;i++)
252	{
253		[p removeAllPoints];
254		[p moveToPoint: NSMakePoint(0,-100)];
255		[p lineToPoint: NSMakePoint(-100,0)];
256		[p lineToPoint: NSMakePoint(0,100)];
257		[p lineToPoint: NSMakePoint(100,0)];
258
259		if (i==0)
260		{
261			str="(u) tilted rect";
262		}
263		else if (i==1)
264		{
265			[p closePath];
266			str="(c) tilted rect";
267		}
268		else
269		{
270			[p lineToPoint: NSMakePoint(0,-100)];
271			[p closePath];
272			str="(d) tilted rect";
273		}
274
275		/* Obvious stuff. */
276		T(1,0,0)
277		T(0,200,200)
278
279		/* Check around each corner. */
280		CHECK_AROUND(0,-100,
281			1,1,1,
282			0,X,0,
283			0,0,0)
284
285		CHECK_AROUND(0,100,
286			0,0,0,
287			0,X,0,
288			1,1,1)
289
290		CHECK_AROUND(-100,0,
291			0,0,1,
292			0,X,1,
293			0,0,1)
294
295		CHECK_AROUND(100,0,
296			1,0,0,
297			1,X,0,
298			1,0,0)
299
300		/* Check some points on the edges. */
301		CHECK_AROUND(50,50,
302			X,0,0,
303			1,X,0,
304			1,1,X)
305
306		CHECK_AROUND(-50,50,
307			0,0,X,
308			0,X,1,
309			X,1,1)
310
311		CHECK_AROUND(-50,-50,
312			X,1,1,
313			0,X,1,
314			0,0,X)
315
316		CHECK_AROUND(50,-50,
317			1,1,X,
318			1,X,0,
319			X,0,0)
320	}
321
322	for (i=0;i<3;i++)
323	{
324		[p removeAllPoints];
325		[p moveToPoint: NSMakePoint(200,200)];
326		[p lineToPoint: NSMakePoint(200,100)];
327		[p lineToPoint: NSMakePoint(100,100)];
328		[p lineToPoint: NSMakePoint(100,200)];
329		if (i==2)
330			[p lineToPoint: NSMakePoint(200,200)];
331		if (i>=1)
332			[p closePath];
333
334		[p moveToPoint: NSMakePoint(200,200)];
335		[p lineToPoint: NSMakePoint(300,200)];
336		[p lineToPoint: NSMakePoint(300,100)];
337		[p lineToPoint: NSMakePoint(200,100)];
338		if (i==2)
339			[p lineToPoint: NSMakePoint(200,200)];
340		if (i>=1)
341			[p closePath];
342
343		if (i==0)
344			str="(u) touching rects";
345		else if (i==1)
346			str="(c) touching rects";
347		else
348			str="(d) touching rects";
349
350		/* Obvious stuff. */
351		T(0,0,0)
352		T(1,150,150)
353		T(1,250,150)
354
355		/* Check around the touching corners and edge. */
356		CHECK_AROUND(200,200,
357			0,0,0,
358			X,X,X,
359			1,1,1)
360
361		CHECK_AROUND(200,100,
362			1,1,1,
363			X,X,X,
364			0,0,0)
365
366		CHECK_AROUND(200,150,
367			1,1,1,
368			1,1,1,
369			1,1,1)
370	}
371
372	for (i=0;i<3;i++)
373	{
374		[p removeAllPoints];
375		[p moveToPoint: NSMakePoint(-100,200)];
376		[p lineToPoint: NSMakePoint(100,200)];
377		[p lineToPoint: NSMakePoint(100,-200)];
378		[p lineToPoint: NSMakePoint(-100,-200)];
379		if (i==2)
380			[p lineToPoint: NSMakePoint(-100,200)];
381		if (i>=1)
382			[p closePath];
383
384		[p moveToPoint: NSMakePoint(200,100)];
385		[p lineToPoint: NSMakePoint(200,-100)];
386		[p lineToPoint: NSMakePoint(-200,-100)];
387		[p lineToPoint: NSMakePoint(-200,100)];
388		if (i==2)
389			[p lineToPoint: NSMakePoint(200,100)];
390		if (i>=1)
391			[p closePath];
392
393		if (i==0)
394			str="(u) intersecting rects";
395		else if (i==1)
396			str="(c) intersecting rects";
397		else
398			str="(d) intersecting rects";
399
400		/* Obvious stuff. */
401		T(2,0,0)
402		T(0,200,200)
403		T(1,150,0)
404		T(1,0,150)
405	}
406
407	for (i=0;i<3;i++)
408	{
409		[p removeAllPoints];
410		[p moveToPoint: NSMakePoint(200,0)];
411		[p lineToPoint: NSMakePoint(100,-100)];
412		[p lineToPoint: NSMakePoint(100,100)];
413		if (i==2)
414			[p lineToPoint: NSMakePoint(200,0)];
415		if (i>=1)
416			[p closePath];
417
418		[p moveToPoint: NSMakePoint(200,0)];
419		[p lineToPoint: NSMakePoint(300,100)];
420		[p lineToPoint: NSMakePoint(300,-100)];
421		if (i==2)
422			[p lineToPoint: NSMakePoint(200,0)];
423		if (i>=1)
424			[p closePath];
425
426		if (i==0)
427			str="(u) touching triangles";
428		else if (i==1)
429			str="(c) touching triangles";
430		else
431			str="(d) touching triangles";
432
433		/* Obvious stuff. */
434		T(0,0,0)
435		T(1,150,0)
436		T(1,250,0)
437
438		CHECK_AROUND(200,0,
439			1,0,1,
440			1,X,1,
441			1,0,1)
442	}
443
444	for (i=0;i<3;i++)
445	{
446		CLEAR
447		[p removeAllPoints];
448		[p moveToPoint: NSMakePoint(100,100)];
449		[p lineToPoint: NSMakePoint(300,100)];
450		[p lineToPoint: NSMakePoint(100,-100)];
451		[p lineToPoint: NSMakePoint(300,-100)];
452		if (i==2)
453			[p lineToPoint: NSMakePoint(100,100)];
454		if (i>=1)
455			[p closePath];
456//		[view drawPath: p];
457
458		if (i==0)
459			str="(u) self-intersection";
460		else if (i==1)
461			str="(c) self-intersection";
462		else
463			str="(d) self-intersection";
464
465		/* Obvious stuff. */
466		T(0,0,0)
467		T(1,200,50)
468		T(-1,200,-50)
469
470		CHECK_AROUND(200,0,
471			0,1,0,
472			0,X,0,
473			0,-1,0)
474//		[view pause];
475	}
476
477	for (i=0;i<3;i++)
478	{
479		[p removeAllPoints];
480		[p moveToPoint: NSMakePoint(-100,200)];
481		[p lineToPoint: NSMakePoint(100,200)];
482		[p lineToPoint: NSMakePoint(100,-200)];
483		[p lineToPoint: NSMakePoint(-100,-200)];
484		if (i==2)
485			[p lineToPoint: NSMakePoint(-100,200)];
486		if (i>=1)
487			[p closePath];
488
489		[p moveToPoint: NSMakePoint(200,100)];
490		[p lineToPoint: NSMakePoint(200,-100)];
491		[p lineToPoint: NSMakePoint(-200,-100)];
492		[p lineToPoint: NSMakePoint(-200,100)];
493		if (i==2)
494			[p lineToPoint: NSMakePoint(200,100)];
495		if (i>=1)
496			[p closePath];
497
498		if (i==0)
499			str="(u) intersecting rects";
500		else if (i==1)
501			str="(c) intersecting rects";
502		else
503			str="(d) intersecting rects";
504
505		/* Obvious stuff. */
506		T(2,0,0)
507		T(0,200,200)
508		T(1,150,0)
509		T(1,0,150)
510
511		/* Intersection corners. */
512		CHECK_AROUND(100,100,
513			1,X,0,
514			X,X,X,
515			2,X,1)
516
517		CHECK_AROUND(100,-100,
518			2,X,1,
519			X,X,X,
520			1,X,0)
521
522		CHECK_AROUND(-100,-100,
523			1,X,2,
524			X,X,X,
525			0,X,1)
526
527		CHECK_AROUND(-100,100,
528			0,X,1,
529			X,X,X,
530			1,X,2)
531	}
532
533	for (i=0;i<3;i++)
534	{
535//		CLEAR
536		[p removeAllPoints];
537		[p moveToPoint: NSMakePoint(100,100)];
538		[p curveToPoint: NSMakePoint(100,-100)
539			controlPoint1: NSMakePoint(200,100)
540			controlPoint2: NSMakePoint(200,-100)];
541		if (i==2)
542			[p lineToPoint: NSMakePoint(100,100)];
543		if (i>=1)
544			[p closePath];
545
546
547//		DRAWPATH
548
549		if (i==0)
550			str="(u) curve 1";
551		else if (i==1)
552			str="(c) curve 1";
553		else
554			str="(d) curve 1";
555
556		/* Obvious stuff. */
557		T(0,0,0)
558		T(0,210,0)
559		T(0,190,0)
560		T(1,110,0)
561
562		/* "Extreme" point is at 175, 0.  This is at the half-way point, so
563		   any tesselation by the standard method should get it right.  */
564		CHECK_AROUND(175, 0,
565			1,0,0,
566			1,X,0,
567			1,0,0)
568
569//		PAUSE
570	}
571
572	for (i=0;i<3;i++)
573	{
574		CLEAR
575		[p removeAllPoints];
576		[p moveToPoint: NSMakePoint(-100,100)];
577		[p curveToPoint: NSMakePoint(100,100)
578			controlPoint1: NSMakePoint(-100,-100)
579			controlPoint2: NSMakePoint(100,-100)];
580		[p lineToPoint: NSMakePoint(100,-100)];
581		[p curveToPoint: NSMakePoint(-100,-100)
582			controlPoint1: NSMakePoint(100,100)
583			controlPoint2: NSMakePoint(-100,100)];
584		if (i==2)
585			[p lineToPoint: NSMakePoint(-100,100)];
586		if (i>=1)
587			[p closePath];
588
589
590		DRAWPATH
591
592		if (i==0)
593			str="(u) curve 2";
594		else if (i==1)
595			str="(c) curve 2";
596		else
597			str="(d) curve 2";
598
599		/* Obvious stuff. */
600		T(-1,0,0)
601		T(1,-90,0)
602		T(1, 90,0)
603
604		/* The two curves intersect at y=0, x= +- 400 * sqrt(3) / 9.  */
605
606		CHECK_AROUND(-400*sqrt(3)/9, 0,
607			1,0,-1,
608			1,X,-1,
609			1,0,-1)
610
611		CHECK_AROUND( 400*sqrt(3)/9, 0,
612			-1,0,1,
613			-1,X,1,
614			-1,0,1)
615
616		PAUSE
617	}
618
619	for (i=0;i<3;i++)
620	{
621		CLEAR
622		[p removeAllPoints];
623		[p moveToPoint: NSMakePoint(100,100)];
624		[p curveToPoint: NSMakePoint(100,100)
625			controlPoint1: NSMakePoint(100,200)
626			controlPoint2: NSMakePoint(200,100)];
627		if (i==2)
628			[p lineToPoint: NSMakePoint(100,100)];
629		if (i>=1)
630			[p closePath];
631
632
633		DRAWPATH
634
635		if (i==0)
636			str="(u) curve 3";
637		else if (i==1)
638			str="(c) curve 3";
639		else
640			str="(d) curve 3";
641
642		/* Obvious stuff. */
643		T(0,0,0)
644		T(1,105,105)
645
646		CHECK_AROUND(100,100,
647			0,0,1,
648			0,X,0,
649			0,0,0)
650
651		PAUSE
652	}
653#endif
654
655	for (i=0;i<3;i++)
656	{
657		CLEAR
658
659		/*
660
661		  +-+
662		  | |
663		+-* |
664		|   |
665		+---+
666
667		*/
668
669		[p removeAllPoints];
670		[p moveToPoint: NSMakePoint(0,0)];
671		[p lineToPoint: NSMakePoint(0,100)];
672		[p lineToPoint: NSMakePoint(100,100)];
673		[p lineToPoint: NSMakePoint(100,-100)];
674		[p lineToPoint: NSMakePoint(-100,-100)];
675		[p lineToPoint: NSMakePoint(-100,0)];
676		if (i==2)
677			[p lineToPoint: NSMakePoint(0,0)];
678		if (i>=1)
679			[p closePath];
680
681
682		DRAWPATH
683
684		if (i==0)
685			str="(u) curve 3";
686		else if (i==1)
687			str="(c) curve 3";
688		else
689			str="(d) curve 3";
690
691		/* Obvious stuff. */
692		T(0,-5,5)
693		T(1,5,-5)
694
695		CHECK_AROUND(0,0,
696			0,X,1,
697			X,X,1,
698			1,1,1)
699
700		PAUSE
701	}
702
703	DESTROY(arp);
704
705	return 0;
706}
707
708