1/* PathContour.m
2 * Object to build contour of paths and images using a raster algorithm (scan)
3 *
4 * Copyright (C) 2000-2011 by vhf interservice GmbH
5 * Author:   Ilonka Fleischmann
6 *
7 * created:  2000-02-23
8 * modified: 2011-04-06 (-contourImage:with: whiteStop for jpg - white tolerances)
9 *           2010-03-03 (-contourPath:with: setDirectionCCW:)
10 *           2008-04-18 (optimizePath close now)
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the vhf Public License as
14 * published by vhf interservice GmbH. Among other things, the
15 * License requires that the copyright notices and this notice
16 * be preserved on all copies.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 * See the vhf Public License for more details.
22 *
23 * You should have received a copy of the vhf Public License along
24 * with this program; see the file LICENSE. If not, write to vhf.
25 *
26 * vhf interservice GmbH, Im Marxle 3, 72119 Altingen, Germany
27 * eMail: info@vhf.de
28 * http://www.vhf.de
29 */
30
31#include <AppKit/AppKit.h>
32#include <VHFShared/types.h>
33#include <VHFShared/vhfCommonFunctions.h>
34#include "../DocView.h"		// ???
35#include "VGraphic.h"
36#include "PathContour.h"
37
38#define DEBUG_CONTUR	0
39
40/* Private methods
41*/
42@interface PathContour(PrivateMethods)
43
44
45@end
46
47@implementation PathContour
48
49//static NSBitmapImageRep	*bitmapImageRep;
50static int		size, bytesPerRow;
51static unsigned char	*data, black=0, white=255, whiteStop=240;
52static int
53Arc2cnt = 5,
54Arc2y[5] = {-2, -1, 0, 1, 2}, Arc2x[5] = {-2, -2, -2, -2, -2},
55Arc2rowcnt[5] = {5, 5, 5, 5, 5},
56Arc3cnt = 7,
57Arc3y[7] = {-3, -2, -1, 0, 1, 2, 3},
58Arc3x[7] = {-3, -3, -3, -3, -3, -3, -3},
59Arc3rowcnt[7] = {7, 7, 7, 7, 7, 7, 7},
60Arc4cnt = 9,
61Arc4y[9] = {-4, -3, -2, -1, 0, 1, 2, 3, 4},
62Arc4x[9] = {-3, -4, -4, -4, -4, -4, -4, -4, -3},
63Arc4rowcnt[9] = {7, 9, 9, 9, 9, 9, 9, 9, 7};
64
65static int
66Arc5cnt = 11,
67Arc5y[11] = {-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5},
68Arc5x[11] = {-3, -4, -5, -5, -5, -5, -5, -5, -5, -4, -3},
69Arc5rowcnt[11] = {7,9,11,11,11,11,11,11,11,9,7},
70Arc6cnt = 13,
71Arc6y[13] = {-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6},
72Arc6x[13] = {-3,-5,-5,-6,-6,-6,-6,-6,-6,-6,-5,-5,-3},
73Arc6rowcnt[13] = {7,11,11,13,13,13,13,13,13,13,11,11,7},
74Arc7cnt = 15,
75Arc7y[15] = {-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7},
76Arc7x[15] = {-3,-5,-6,-6,-7,-7,-7,-7,-7,-7,-7,-6,-6,-5,-3},
77Arc7rowcnt[15] = {7,11,13,13,15,15,15,15,15,15,15,13,13,11,7},
78Arc8cnt = 17,
79Arc8y[17] = {-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8},
80Arc8x[17] = {-3,-5,-6,-7,-7,-8,-8,-8,-8,-8,-8,-8,-7,-7,-6,-5,-3},
81Arc8rowcnt[17] = {7,11,13,15,15,17,17,17,17,17,17,17,15,15,13,11,7},
82Arc9cnt = 19,
83Arc9y[19] = {-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9},
84Arc9x[19] = {-4,-6,-7,-8,-8,-9,-9,-9,-9,-9,-9,-9,-9,-9,-8,-8,-7,-6,-4},
85Arc9rowcnt[19] = {9,13,15,17,17,19,19,19,19,19,19,19,19,19,17,17,15,13,9},
86Arc10cnt = 21,
87Arc10y[21] = {-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10},
88Arc10x[21] = {-5,-6,-8,-8,-9,-10,-10,-10,-10,-10,-10,-10,-10,-10,-10,-10,-9,-8,-8,-6,-5},
89Arc10rowcnt[21] = {11,13,17,17,19,21,21,21,21,21,21,21,21,21,21,21,19,17,17,13,11},
90Arc11cnt = 23,
91Arc11y[23] = {-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11},
92Arc11x[23] = {-5,-6,-8,-9,-9,-10,-11,-11,-11,-11,-11,-11,-11,-11,-11,-11,-11,-10,-9,-9,-8,-6,-5},
93Arc11rowcnt[23] = {11,13,17,19,19,21,23,23,23,23,23,23,23,23,23,23,23,21,19,19,17,13,11},
94Arc12cnt = 25,
95Arc12y[25] = {-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12},
96Arc12x[25] = {-5,-7,-8,-9,-10,-11,-11,-12,-12,-12,-12,-12,-12,-12,-12,-12,-12,-12,-11,-11,-10,-9,-8,-7,-5},
97Arc12rowcnt[25] = {11,15,17,19,21,23,23,25,25,25,25,25,25,25,25,25,25,25,23,23,21,19,17,15,11},
98Arc13cnt = 27,
99Arc13y[27] = {-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13},
100Arc13x[27] = {-5,-7,-9,-10,-11,-11,-12,-12,-13,-13,-13,-13,-13,-13,-13,-13,-13,-13,-13,-12,-12,-11,-11,-10,-9,-7,-5},
101Arc13rowcnt[27] = {11,15,19,21,23,23,25,25,27,27,27,27,27,27,27,27,27,27,27,25,25,23,23,21,19,15,11},
102Arc14cnt = 29,
103Arc14y[29] = {-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14},
104Arc14x[29] = {-5,-7,-9,-10,-11,-12,-12,-13,-13,-14,-14,-14,-14,-14,-14,-14,-14,-14,-14,-14,-13,-13,-12,-12,-11,-10,-9,-7,-5},
105Arc14rowcnt[29] = {11,15,19,21,23,25,25,27,27,29,29,29,29,29,29,29,29,29,29,29,27,27,25,25,23,21,19,15,11},
106Arc15cnt = 31,
107Arc15y[31] = {-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15},
108Arc15x[31] = {-5,-8,-9,-11,-12,-12,-13,-14,-14,-14,-15,-15,-15,-15,-15,-15,-15,-15,-15,-15,-15,-14,-14,-14,-13,-12,-12,-11,-9,-8,-5},
109Arc15rowcnt[31] = {10,16,18,22,24,24,26,28,28,28,30,30,30,30,30,30,30,30,30,30,30,28,28,28,26,24,24,22,18,16,10},
110Arc16cnt = 33,
111Arc16y[33] = {-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16},
112Arc16x[33] = {-5,-8,-9,-11,-12,-13,-13,-14,-15,-15,-15,-16,-16,-16,-16,-16,-16,-16,-16,-16,-16,-16,-15,-15,-15,-14,-13,-13,-12,-11,-9,-8,-5},
113Arc16rowcnt[33] = {10,16,18,22,24,26,26,28,30,30,30,32,32,32,32,32,32,32,32,32,32,32,30,30,30,28,26,26,24,22,18,16,10},
114Arc17cnt = 35,
115Arc17y[35] = {-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17},
116Arc17x[35] = {-5,-8,-10,-11,-13,-13,-14,-15,-15,-16,-16,-16,-17,-17,-17,-17,-17,-17,-17,-17,-17,-17,-17,-16,-16,-16,-15,-15,-14,-13,-13,-11,-10,-8,-5},
117Arc17rowcnt[35] = {10,16,20,22,26,26,28,30,30,32,32,32,34,34,34,34,34,34,34,34,34,34,34,32,32,32,30,30,28,26,26,22,20,16,10},
118Arc18cnt = 37,
119Arc18y[37] = {-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18},
120Arc18x[37] = {-5,-8,-10,-11,-13,-14,-14,-15,-16,-16,-17,-17,-17,-18,-18,-18,-18,-18,-18,-18,-18,-18,-18,-18,-17,-17,-17,-16,-16,-15,-14,-14,-13,-11,-10,-8,-5},
121Arc18rowcnt[37] = {10,16,20,22,26,28,28,30,32,32,34,34,34,36,36,36,36,36,36,36,36,36,36,36,34,34,34,32,32,30,28,28,26,22,20,16,10},
122Arc19cnt = 39,
123Arc19y[39] = {-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19},
124Arc19x[39] = {-5,-9,-10,-12,-13,-14,-15,-16,-16,-17,-18,-18,-18,-18,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-18,-18,-18,-18,-17,-16,-16,-15,-14,-13,-12,-10,-9,-5},
125Arc19rowcnt[39] = {10,18,20,24,26,28,30,32,32,34,36,36,36,36,38,38,38,38,38,38,38,38,38,38,38,36,36,36,36,34,32,32,30,28,26,24,20,18,10},
126Arc20cnt = 41,
127Arc20y[41] = {-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20},
128Arc20x[41] = {-5,-9,-10,-12,-13,-15,-15,-16,-17,-17,-18,-19,-19,-19,-19,-20,-20,-20,-20,-20,-20,-20,-20,-20,-20,-20,-19,-19,-19,-19,-18,-17,-17,-16,-15,-15,-13,-12,-10,-9,-5},
129Arc20rowcnt[41] = {10,18,20,24,26,30,30,32,34,34,36,38,38,38,38,40,40,40,40,40,40,40,40,40,40,40,38,38,38,38,36,34,34,32,30,30,26,24,20,18,10},
130Arc21cnt = 43,
131Arc21y[43] = {-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21},
132Arc21x[43] = {-5,-9,-11,-12,-14,-15,-16,-17,-17,-18,-19,-19,-20,-20,-20,-20,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-20,-20,-20,-20,-19,-19,-18,-17,-17,-16,-15,-14,-12,-11,-9,-5},
133Arc21rowcnt[43] = {10,18,22,24,28,30,32,34,34,36,38,38,40,40,40,40,42,42,42,42,42,42,42,42,42,42,42,40,40,40,40,38,38,36,34,34,32,30,28,24,22,18,10},
134Arc22cnt = 45,
135Arc22y[45] = {-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22},
136Arc22x[45] = {-5,-9,-11,-12,-14,-15,-16,-17,-18,-18,-19,-20,-20,-21,-21,-21,-21,-22,-22,-22,-22,-22,-22,-22,-22,-22,-22,-22,-21,-21,-21,-21,-20,-20,-19,-18,-18,-17,-16,-15,-14,-12,-11,-9,-5},
137Arc22rowcnt[45] = {10,18,22,24,28,30,32,34,36,36,38,40,40,42,42,42,42,44,44,44,44,44,44,44,44,44,44,44,42,42,42,42,40,40,38,36,36,34,32,30,28,24,22,18,10},
138Arc23cnt = 47,
139Arc23y[47] = {-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23},
140Arc23x[47] = {-5,-10,-11,-13,-14,-16,-17,-18,-18,-19,-20,-20,-21,-22,-22,-22,-22,-22,-23,-23,-23,-23,-23,-23,-23,-23,-23,-23,-23,-22,-22,-22,-22,-22,-21,-20,-20,-19,-18,-18,-17,-16,-14,-13,-11,-10,-5},
141Arc23rowcnt[47] = {10,20,22,26,28,32,34,36,36,38,40,40,42,44,44,44,44,44,46,46,46,46,46,46,46,46,46,46,46,44,44,44,44,44,42,40,40,38,36,36,34,32,28,26,22,20,10},
142Arc24cnt = 49,
143Arc24y[49] = {-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24},
144Arc24x[49] = {-5,-10,-11,-13,-14,-16,-17,-18,-19,-19,-20,-21,-21,-22,-23,-23,-23,-23,-23,-24,-24,-24,-24,-24,-24,-24,-24,-24,-24,-24,-23,-23,-23,-23,-23,-22,-21,-21,-20,-19,-19,-18,-17,-16,-14,-13,-11,-10,-5},
145Arc24rowcnt[49] = {10,20,22,26,28,32,34,36,38,38,40,42,42,44,46,46,46,46,46,48,48,48,48,48,48,48,48,48,48,48,46,46,46,46,46,44,42,42,40,38,38,36,34,32,28,26,22,20,10},
146Arc25cnt = 51,
147Arc25y[51] = {-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25},
148Arc25x[51] = {-5,-10,-12,-13,-15,-16,-18,-19,-19,-20,-21,-21,-22,-23,-23,-24,-24,-24,-24,-24,-25,-25,-25,-25,-25,-25,-25,-25,-25,-25,-25,-24,-24,-24,-24,-24,-23,-23,-22,-21,-21,-20,-19,-19,-18,-16,-15,-13,-12,-10,-5},
149Arc25rowcnt[51] = {10,20,24,26,30,32,36,38,38,40,42,42,44,46,46,48,48,48,48,48,50,50,50,50,50,50,50,50,50,50,50,48,48,48,48,48,46,46,44,42,42,40,38,38,36,32,30,26,24,20,10},
150Arc26cnt = 53,
151Arc26y[53] = {-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26},
152Arc26x[53] = {-5,-10,-12,-14,-15,-16,-18,-19,-20,-20,-21,-22,-23,-23,-24,-24,-25,-25,-25,-25,-25,-26,-26,-26,-26,-26,-26,-26,-26,-26,-26,-26,-25,-25,-25,-25,-25,-24,-24,-23,-23,-22,-21,-20,-20,-19,-18,-16,-15,-14,-12,-10,-5},
153Arc26rowcnt[53] = {10,20,24,28,30,32,36,38,40,40,42,44,46,46,48,48,50,50,50,50,50,52,52,52,52,52,52,52,52,52,52,52,50,50,50,50,50,48,48,46,46,44,42,40,40,38,36,32,30,28,24,20,10},
154Arc27cnt = 55,
155Arc27y[55] = {-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27},
156Arc27x[55] = {-5,-10,-12,-14,-15,-17,-18,-20,-20,-21,-22,-22,-23,-24,-24,-25,-25,-26,-26,-26,-26,-26,-27,-27,-27,-27,-27,-27,-27,-27,-27,-27,-27,-26,-26,-26,-26,-26,-25,-25,-24,-24,-23,-22,-22,-21,-20,-20,-18,-17,-15,-14,-12,-10,-5},
157Arc27rowcnt[55] = {10,20,24,28,30,34,36,40,40,42,44,44,46,48,48,50,50,52,52,52,52,52,54,54,54,54,54,54,54,54,54,54,54,52,52,52,52,52,50,50,48,48,46,44,44,42,40,40,36,34,30,28,24,20,10},
158Arc28cnt = 57,
159Arc28y[57] = {-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28},
160Arc28x[57] = {-5,-10,-13,-14,-16,-17,-19,-20,-21,-22,-22,-23,-24,-24,-25,-26,-26,-26,-27,-27,-27,-27,-27,-28,-28,-28,-28,-28,-28,-28,-28,-28,-28,-28,-27,-27,-27,-27,-27,-26,-26,-26,-25,-24,-24,-23,-22,-22,-21,-20,-19,-17,-16,-14,-13,-10,-5},
161Arc28rowcnt[57] = {10,20,26,28,32,34,38,40,42,44,44,46,48,48,50,52,52,52,54,54,54,54,54,56,56,56,56,56,56,56,56,56,56,56,54,54,54,54,54,52,52,52,50,48,48,46,44,44,42,40,38,34,32,28,26,20,10},
162Arc29cnt = 59,
163Arc29y[59] = {-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29},
164Arc29x[59] = {-5,-10,-13,-14,-16,-17,-19,-20,-21,-22,-23,-23,-24,-25,-25,-26,-27,-27,-27,-28,-28,-28,-28,-28,-29,-29,-29,-29,-29,-29,-29,-29,-29,-29,-29,-28,-28,-28,-28,-28,-27,-27,-27,-26,-25,-25,-24,-23,-23,-22,-21,-20,-19,-17,-16,-14,-13,-10,-5},
165Arc29rowcnt[59] = {10,20,26,28,32,34,38,40,42,44,46,46,48,50,50,52,54,54,54,56,56,56,56,56,58,58,58,58,58,58,58,58,58,58,58,56,56,56,56,56,54,54,54,52,50,50,48,46,46,44,42,40,38,34,32,28,26,20,10},
166Arc30cnt = 61,
167Arc30y[61] = {-30,-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30},
168Arc30x[61] = {-5,-10,-13,-15,-16,-18,-19,-21,-22,-23,-23,-24,-25,-25,-26,-27,-27,-28,-28,-28,-29,-29,-29,-29,-29,-30,-30,-30,-30,-30,-30,-30,-30,-30,-30,-30,-29,-29,-29,-29,-29,-28,-28,-28,-27,-27,-26,-25,-25,-24,-23,-23,-22,-21,-19,-18,-16,-15,-13,-10,-5},
169Arc30rowcnt[61] = {10,20,26,30,32,36,38,42,44,46,46,48,50,50,52,54,54,56,56,56,58,58,58,58,58,60,60,60,60,60,60,60,60,60,60,60,58,58,58,58,58,56,56,56,54,54,52,50,50,48,46,46,44,42,38,36,32,30,26,20,10},
170Arc31cnt = 63,
171Arc31y[63] = {-31,-30,-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31},
172Arc31x[63] = {-5,-10,-13,-15,-16,-18,-19,-21,-22,-23,-24,-24,-25,-26,-26,-27,-28,-28,-29,-29,-29,-30,-30,-30,-30,-30,-31,-31,-31,-31,-31,-31,-31,-31,-31,-31,-31,-30,-30,-30,-30,-30,-29,-29,-29,-28,-28,-27,-26,-26,-25,-24,-24,-23,-22,-21,-19,-18,-16,-15,-13,-10,-5},
173Arc31rowcnt[63] = {10,20,26,30,32,36,38,42,44,46,48,48,50,52,52,54,56,56,58,58,58,60,60,60,60,60,62,62,62,62,62,62,62,62,62,62,62,60,60,60,60,60,58,58,58,56,56,54,52,52,50,48,48,46,44,42,38,36,32,30,26,20,10},
174Arc32cnt = 65,
175Arc32y[65] = {-32,-31,-30,-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32},
176Arc32x[65] = {-5,-10,-14,-15,-17,-18,-20,-21,-23,-24,-24,-25,-26,-26,-27,-28,-28,-29,-30,-30,-30,-30,-31,-31,-31,-31,-31,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-31,-31,-31,-31,-31,-30,-30,-30,-30,-29,-28,-28,-27,-26,-26,-25,-24,-24,-23,-21,-20,-18,-17,-15,-14,-10,-5},
177Arc32rowcnt[65] = {10,20,28,30,34,36,40,42,46,48,48,50,52,52,54,56,56,58,60,60,60,60,62,62,62,62,62,64,64,64,64,64,64,64,64,64,64,64,62,62,62,62,62,60,60,60,60,58,56,56,54,52,52,50,48,48,46,42,40,36,34,30,28,20,10},
178Arc33cnt = 67,
179Arc33y[67] = {-33,-32,-31,-30,-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33},
180Arc33x[67] = {-5,-10,-14,-15,-17,-18,-20,-21,-23,-24,-25,-25,-26,-27,-27,-28,-29,-29,-30,-31,-31,-31,-31,-32,-32,-32,-32,-32,-33,-33,-33,-33,-33,-33,-33,-33,-33,-33,-33,-32,-32,-32,-32,-32,-31,-31,-31,-31,-30,-29,-29,-28,-27,-27,-26,-25,-25,-24,-23,-21,-20,-18,-17,-15,-14,-10,-5},
181Arc33rowcnt[67] = {10,20,28,30,34,36,40,42,46,48,50,50,52,54,54,56,58,58,60,62,62,62,62,64,64,64,64,64,66,66,66,66,66,66,66,66,66,66,66,64,64,64,64,64,62,62,62,62,60,58,58,56,54,54,52,50,50,48,46,42,40,36,34,30,28,20,10},
182Arc34cnt = 69,
183Arc34y[69] = {-34,-33,-32,-31,-30,-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34},
184Arc34x[69] = {-5,-10,-14,-16,-18,-20,-21,-22,-23,-25,-25,-26,-27,-28,-29,-29,-30,-30,-31,-31,-32,-32,-32,-32,-33,-33,-33,-33,-33,-34,-34,-34,-34,-34,-34,-34,-34,-34,-34,-34,-33,-33,-33,-33,-33,-32,-32,-32,-32,-31,-31,-30,-30,-29,-29,-28,-27,-26,-25,-25,-23,-22,-21,-20,-18,-16,-14,-10,-5},
185Arc34rowcnt[69] = {10,20,28,32,36,40,42,44,46,50,50,52,54,56,58,58,60,60,62,62,64,64,64,64,66,66,66,66,66,68,68,68,68,68,68,68,68,68,68,68,66,66,66,66,66,64,64,64,64,62,62,60,60,58,58,56,54,52,50,50,46,44,42,40,36,32,28,20,10},
186Arc35cnt = 71,
187Arc35y[71] = {-35,-34,-33,-32,-31,-30,-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35},
188Arc35x[71] = {-5,-10,-15,-16,-18,-20,-21,-23,-24,-25,-26,-27,-28,-28,-29,-30,-30,-31,-31,-32,-33,-33,-33,-33,-33,-34,-34,-34,-34,-34,-35,-35,-35,-35,-35,-35,-35,-35,-35,-35,-35,-34,-34,-34,-34,-34,-33,-33,-33,-33,-33,-32,-31,-31,-30,-30,-29,-28,-28,-27,-26,-25,-24,-23,-21,-20,-18,-16,-15,-10,-5},
189Arc35rowcnt[71] = {10,20,30,32,34,40,42,46,48,50,52,54,56,56,58,60,60,62,62,64,66,66,66,66,66,68,68,68,68,68,70,70,70,70,70,70,70,70,70,70,70,68,68,68,68,68,66,66,66,66,66,64,62,62,60,60,58,56,56,54,52,50,48,46,42,40,34,32,30,20,10},
190Arc36cnt = 73,
191Arc36y[73] = {-36,-35,-34,-33,-32,-31,-30,-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36},
192Arc36x[73] = {-9,-12,-15,-17,-18,-20,-22,-23,-24,-25,-26,-27,-28,-29,-30,-30,-31,-31,-32,-33,-33,-34,-34,-34,-35,-35,-35,-36,-36,-36,-36,-36,-36,-36,-36,-36,-36,-36,-36,-36,-36,-36,-36,-36,-36,-36,-35,-35,-35,-34,-34,-34,-33,-33,-32,-31,-31,-30,-30,-29,-28,-27,-26,-25,-24,-23,-22,-20,-18,-17,-15,-12,-9},
193Arc36rowcnt[73] = {18,24,30,34,38,40,44,46,48,50,52,54,56,58,60,60,62,62,64,66,66,68,68,68,70,70,70,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,70,70,70,68,68,68,66,66,64,62,62,60,60,58,56,54,52,50,48,46,44,40,38,34,30,24,18},
194Arc37cnt = 75,
195Arc37y[75] = {-37,-36,-35,-34,-33,-32,-31,-30,-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37},
196Arc37x[75] = {-9,-12,-15,-17,-19,-21,-22,-23,-24,-26,-27,-28,-28,-29,-30,-31,-32,-32,-33,-33,-34,-34,-35,-35,-35,-36,-36,-36,-37,-37,-37,-37,-37,-37,-37,-37,-37,-37,-37,-37,-37,-37,-37,-37,-37,-37,-37,-36,-36,-36,-35,-35,-35,-34,-34,-33,-33,-32,-32,-31,-30,-29,-28,-28,-27,-26,-24,-23,-22,-21,-19,-17,-15,-12,-9},
197Arc37rowcnt[75] = {18,24,30,34,38,42,44,46,48,52,54,56,56,58,60,62,64,64,66,66,68,68,70,70,70,72,72,72,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,72,72,72,70,70,70,68,68,66,66,64,64,62,60,58,56,56,54,52,48,46,44,42,38,34,30,24,18},
198Arc38cnt = 77,
199Arc38y[77] = {-38,-37,-36,-35,-34,-33,-32,-31,-30,-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38},
200Arc38x[77] = {-9,-12,-15,-17,-19,-21,-22,-24,-25,-26,-27,-28,-29,-30,-31,-31,-32,-33,-33,-34,-34,-35,-35,-36,-36,-36,-37,-37,-37,-38,-38,-38,-38,-38,-38,-38,-38,-38,-38,-38,-38,-38,-38,-38,-38,-38,-38,-38,-37,-37,-37,-36,-36,-36,-35,-35,-34,-34,-33,-33,-32,-31,-31,-30,-29,-28,-27,-26,-25,-24,-22,-21,-19,-17,-15,-12,-9},
201Arc38rowcnt[77] = {18,24,30,34,38,42,44,48,50,52,54,56,58,60,62,62,64,66,66,68,68,70,70,72,72,72,74,74,74,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,74,74,74,72,72,72,70,70,68,68,66,66,64,62,62,60,58,56,54,52,50,48,44,42,38,34,30,24,18},
202Arc39cnt = 79,
203Arc39y[79] = {-39,-38,-37,-36,-35,-34,-33,-32,-31,-30,-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39},
204Arc39x[79] = {-9,-12,-15,-17,-19,-21,-23,-24,-25,-26,-28,-29,-29,-30,-31,-32,-33,-33,-34,-34,-35,-35,-36,-36,-37,-37,-37,-38,-38,-38,-39,-39,-39,-39,-39,-39,-39,-39,-39,-39,-39,-39,-39,-39,-39,-39,-39,-39,-39,-38,-38,-38,-37,-37,-37,-36,-36,-35,-35,-34,-34,-33,-33,-32,-31,-30,-29,-29,-28,-26,-25,-24,-23,-21,-19,-17,-15,-12,-9},
205Arc39rowcnt[79] = {18,24,30,34,38,42,46,48,50,52,56,58,58,60,62,64,66,66,68,68,70,70,72,72,74,74,74,76,76,76,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,76,76,76,74,74,74,72,72,70,70,68,68,66,66,64,62,60,58,58,56,52,50,48,46,42,38,34,30,24,18},
206Arc40cnt = 81,
207Arc40y[81] = {-40,-39,-38,-37,-36,-35,-34,-33,-32,-31,-30,-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40},
208Arc40x[81] = {-9,-12,-16,-18,-19,-21,-23,-24,-25,-27,-28,-29,-30,-31,-31,-32,-33,-34,-34,-35,-35,-36,-37,-37,-38,-38,-38,-38,-39,-39,-39,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-39,-39,-39,-38,-38,-38,-38,-37,-37,-36,-35,-35,-34,-34,-33,-32,-31,-31,-30,-29,-28,-27,-25,-24,-23,-21,-19,-18,-16,-12,-9},
209Arc40rowcnt[81] = {18,24,32,34,38,42,46,48,50,52,56,58,60,62,62,64,66,68,68,70,70,72,74,74,76,76,76,76,78,78,78,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,78,78,78,76,76,76,76,74,74,72,70,70,68,68,66,64,62,62,60,58,56,52,50,48,46,42,38,34,32,24,18},
210Arc41cnt = 83,
211Arc41y[83] = {-41,-40,-39,-38,-37,-36,-35,-34,-33,-32,-31,-30,-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41},
212Arc41x[83] = {-9,-13,-16,-18,-20,-22,-23,-25,-26,-27,-28,-29,-30,-31,-32,-33,-34,-34,-35,-36,-36,-37,-37,-38,-38,-39,-39,-39,-40,-40,-40,-40,-41,-41,-41,-41,-41,-41,-41,-41,-41,-41,-41,-41,-41,-41,-41,-41,-41,-41,-41,-40,-40,-40,-40,-39,-39,-39,-38,-38,-37,-37,-36,-36,-35,-34,-34,-33,-32,-31,-30,-29,-28,-27,-26,-25,-23,-22,-20,-18,-16,-13,-9},
213Arc41rowcnt[83] = {18,26,32,36,40,44,46,50,52,54,56,58,60,62,64,66,68,68,70,72,72,74,74,76,76,78,78,78,80,80,80,80,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,80,80,80,80,78,78,78,76,76,74,74,72,72,70,68,68,66,64,62,60,58,56,54,52,50,46,44,40,36,32,26,18},
214Arc42cnt = 85,
215Arc42y[85] = {-42,-41,-40,-39,-38,-37,-36,-35,-34,-33,-32,-31,-30,-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42},
216Arc42x[85] = {-9,-13,-16,-18,-20,-22,-24,-25,-26,-27,-29,-30,-31,-32,-32,-33,-34,-35,-36,-36,-37,-37,-38,-38,-39,-39,-40,-40,-40,-41,-41,-41,-41,-42,-42,-42,-42,-42,-42,-42,-42,-42,-42,-42,-42,-42,-42,-42,-42,-42,-42,-42,-41,-41,-41,-41,-40,-40,-40,-39,-39,-38,-38,-37,-37,-36,-36,-35,-34,-33,-32,-32,-31,-30,-29,-27,-26,-25,-24,-22,-20,-18,-16,-13,-9},
217Arc42rowcnt[85] = {18,26,32,36,40,44,48,50,52,54,58,60,62,64,64,66,68,70,72,72,74,74,76,76,78,78,80,80,80,82,82,82,82,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,82,82,82,82,80,80,80,78,78,76,76,74,74,72,72,70,68,66,64,64,62,60,58,54,52,50,48,44,40,36,32,26,18},
218Arc43cnt = 87,
219Arc43y[87] = {-43,-42,-41,-40,-39,-38,-37,-36,-35,-34,-33,-32,-31,-30,-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43},
220Arc43x[87] = {-10,-13,-16,-18,-20,-22,-24,-25,-27,-28,-29,-30,-31,-32,-33,-34,-35,-35,-36,-37,-37,-38,-38,-39,-39,-40,-40,-41,-41,-41,-42,-42,-42,-43,-43,-43,-43,-43,-43,-43,-43,-43,-43,-43,-43,-43,-43,-43,-43,-43,-43,-43,-43,-43,-42,-42,-42,-41,-41,-41,-40,-40,-39,-39,-38,-38,-37,-37,-36,-35,-35,-34,-33,-32,-31,-30,-29,-28,-27,-25,-24,-22,-20,-18,-16,-13,-10},
221Arc43rowcnt[87] = {20,26,32,36,40,44,48,50,54,56,58,60,62,64,66,68,70,70,72,74,74,76,76,78,78,80,80,82,82,82,84,84,84,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,84,84,84,82,82,82,80,80,78,78,76,76,74,74,72,70,70,68,66,64,62,60,58,56,54,50,48,44,40,36,32,26,20},
222Arc44cnt = 89,
223Arc44y[89] = {-44,-43,-42,-41,-40,-39,-38,-37,-36,-35,-34,-33,-32,-31,-30,-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44},
224Arc44x[89] = {-10,-13,-16,-19,-20,-22,-24,-26,-27,-28,-29,-31,-32,-33,-33,-34,-35,-36,-37,-37,-38,-38,-39,-39,-40,-41,-41,-41,-42,-42,-42,-43,-43,-43,-44,-44,-44,-44,-44,-44,-44,-44,-44,-44,-44,-44,-44,-44,-44,-44,-44,-44,-44,-44,-44,-43,-43,-43,-42,-42,-42,-41,-41,-41,-40,-39,-39,-38,-38,-37,-37,-36,-35,-34,-33,-33,-32,-31,-29,-28,-27,-26,-24,-22,-20,-19,-16,-13,-10},
225Arc44rowcnt[89] = {20,26,32,38,40,44,48,52,54,56,58,62,64,66,66,68,70,72,74,74,76,76,78,78,80,82,82,82,84,84,84,86,86,86,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,86,86,86,84,84,84,82,82,82,80,78,78,76,76,74,74,72,70,68,66,66,64,62,58,56,54,52,48,44,40,38,32,26,20},
226Arc45cnt = 91,
227Arc45y[91] = {-45,-44,-43,-42,-41,-40,-39,-38,-37,-36,-35,-34,-33,-32,-31,-30,-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45},
228Arc45x[91] = {-10,-13,-16,-19,-21,-23,-24,-26,-27,-28,-30,-31,-32,-33,-34,-35,-35,-36,-37,-38,-38,-39,-40,-40,-41,-41,-42,-42,-42,-43,-43,-43,-44,-44,-44,-45,-45,-45,-45,-45,-45,-45,-45,-45,-45,-45,-45,-45,-45,-45,-45,-45,-45,-45,-45,-45,-44,-44,-44,-43,-43,-43,-42,-42,-42,-41,-41,-40,-40,-39,-38,-38,-37,-36,-35,-35,-34,-33,-32,-31,-30,-28,-27,-26,-24,-23,-21,-19,-16,-13,-10},
229Arc45rowcnt[91] = {20,26,32,38,42,46,48,52,54,56,60,62,64,66,68,70,70,72,74,76,76,78,80,80,82,82,84,84,84,86,86,86,88,88,88,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,88,88,88,86,86,86,84,84,84,82,82,80,80,78,76,76,74,72,70,70,68,66,64,62,60,56,54,52,48,46,42,38,32,26,20},
230Arc46cnt = 93,
231Arc46y[93] = {-46,-45,-44,-43,-42,-41,-40,-39,-38,-37,-36,-35,-34,-33,-32,-31,-30,-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46},
232Arc46x[93] = {-10,-13,-16,-19,-21,-23,-25,-26,-28,-29,-30,-31,-32,-33,-34,-35,-36,-37,-38,-38,-39,-40,-40,-41,-41,-42,-42,-43,-43,-43,-44,-44,-44,-45,-45,-45,-46,-46,-46,-46,-46,-46,-46,-46,-46,-46,-46,-46,-46,-46,-46,-46,-46,-46,-46,-46,-46,-45,-45,-45,-44,-44,-44,-43,-43,-43,-42,-42,-41,-41,-40,-40,-39,-38,-38,-37,-36,-35,-34,-33,-32,-31,-30,-29,-28,-26,-25,-23,-21,-19,-16,-13,-10},
233Arc46rowcnt[93] = {20,26,32,38,42,46,50,52,54,56,60,62,64,66,68,70,72,74,76,76,78,80,80,82,82,84,84,86,86,86,88,88,88,90,90,90,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,90,90,90,88,88,88,86,86,86,84,84,82,82,80,80,78,76,76,74,72,70,68,66,64,62,60,56,54,52,50,46,42,38,32,26,20};
234
235#if 0
236static int	Arc2Y[4] = {-1, 0, 1, 2}, Arc2X[4] = {-2, -2, -2, -2}, Arc2Cnt = 4,
237                Arc3Y[12] = {-2, -1, 0, 1, 2, 3, -2, -1, 0, 1, 2, 3}, Arc3Cnt = 12,
238	        Arc3X[12] = {-3, -3, -3, -3, -3, -3, -1, -1, -1, -1, -1, -1},
239	        Arc4Y[16] = {-3, -2, -1, 0, 1, 2, 3, 4, -3, -2, -1, 0, 1, 2, 3, 4}, Arc4Cnt = 16,
240	        Arc4X[16] = {-3, -4, -4, -4, -4, -4, -4, -3, -1, 0, 0, 0, 0, 0, 0, -1};
241static int
242Arc5cnt = 10,
243Arc5y[10] = {-4, -3, -2, -1, 0, 1, 2, 3, 4, 5},
244Arc5x[10] = {-3, -4, -5, -5, -5, -5, -5, -5, -4, -3},
245Arc5rowcnt[10] = {6,8,10,10,10,10,10,10,8,6},
246Arc6cnt = 12,
247Arc6y[12] = {-5,-4,-3,-2,-1,0,1,2,3,4,5,6},
248Arc6x[12] = {-3,-5,-5,-6,-6,-6,-6,-6,-6,-5,-5,-3},
249Arc6rowcnt[12] = {6,10,10,12,12,12,12,12,12,10,10,6},
250Arc7cnt = 14,
251Arc7y[14] = {-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7},
252Arc7x[14] = {-3,-5,-6,-6,-7,-7,-7,-7,-7,-7,-6,-6,-5,-3},
253Arc7rowcnt[14] = {6,10,12,12,14,14,14,14,14,14,12,12,10,6},
254Arc8cnt = 16,
255Arc8y[16] = {-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8},
256Arc8x[16] = {-3,-5,-6,-7,-7,-8,-8,-8,-8,-8,-8,-7,-7,-6,-5,-3},
257Arc8rowcnt[16] = {6,10,12,14,14,16,16,16,16,16,16,14,14,12,10,6},
258Arc9cnt = 18,
259Arc9y[18] = {-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9},
260Arc9x[18] = {-4,-6,-7,-8,-8,-9,-9,-9,-9,-9,-9,-9,-9,-8,-8,-7,-6,-4},
261Arc9rowcnt[18] = {8,12,14,16,16,18,18,18,18,18,18,18,18,16,16,14,12,8},
262Arc10cnt = 20,
263Arc10y[20] = {-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10},
264Arc10x[20] = {-5,-6,-8,-8,-9,-10,-10,-10,-10,-10,-10,-10,-10,-10,-10,-9,-8,-8,-6,-5},
265Arc10rowcnt[20] = {10,12,16,16,18,20,20,20,20,20,20,20,20,20,20,18,16,16,12,10},
266Arc11cnt = 22,
267Arc11y[22] = {-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11},
268Arc11x[22] = {-5,-6,-8,-9,-9,-10,-11,-11,-11,-11,-11,-11,-11,-11,-11,-11,-10,-9,-9,-8,-6,-5},
269Arc11rowcnt[22] = {10,12,16,18,18,20,22,22,22,22,22,22,22,22,22,22,20,18,18,16,12,10},
270Arc12cnt = 24,
271Arc12y[24] = {-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12},
272Arc12x[24] = {-5,-7,-8,-9,-10,-11,-11,-12,-12,-12,-12,-12,-12,-12,-12,-12,-12,-11,-11,-10,-9,-8,-7,-5},
273Arc12rowcnt[24] = {10,14,16,18,20,22,22,24,24,24,24,24,24,24,24,24,24,22,22,20,18,16,14,10},
274Arc13cnt = 26,
275Arc13y[26] = {-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13},
276Arc13x[26] = {-5,-7,-9,-10,-11,-11,-12,-12,-13,-13,-13,-13,-13,-13,-13,-13,-13,-13,-12,-12,-11,-11,-10,-9,-7,-5},
277Arc13rowcnt[26] = {10,14,18,20,22,22,24,24,26,26,26,26,26,26,26,26,26,26,24,24,22,22,20,18,14,10},
278Arc14cnt = 28,
279Arc14y[28] = {-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14},
280Arc14x[28] = {-5,-7,-9,-10,-11,-12,-12,-13,-13,-14,-14,-14,-14,-14,-14,-14,-14,-14,-14,-13,-13,-12,-12,-11,-10,-9,-7,-5},
281Arc14rowcnt[28] = {10,14,18,20,22,24,24,26,26,28,28,28,28,28,28,28,28,28,28,26,26,24,24,22,20,18,14,10},
282Arc15cnt = 30,
283Arc15y[30] = {-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15},
284Arc15x[30] = {-5,-8,-9,-11,-12,-12,-13,-14,-14,-14,-15,-15,-15,-15,-15,-15,-15,-15,-15,-15,-14,-14,-14,-13,-12,-12,-11,-9,-8,-5},
285Arc15rowcnt[30] = {10,16,18,22,24,24,26,28,28,28,30,30,30,30,30,30,30,30,30,30,28,28,28,26,24,24,22,18,16,10},
286Arc16cnt = 32,
287Arc16y[32] = {-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16},
288Arc16x[32] = {-5,-8,-9,-11,-12,-13,-13,-14,-15,-15,-15,-16,-16,-16,-16,-16,-16,-16,-16,-16,-16,-15,-15,-15,-14,-13,-13,-12,-11,-9,-8,-5},
289Arc16rowcnt[32] = {10,16,18,22,24,26,26,28,30,30,30,32,32,32,32,32,32,32,32,32,32,30,30,30,28,26,26,24,22,18,16,10},
290Arc17cnt = 34,
291Arc17y[34] = {-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17},
292Arc17x[34] = {-5,-8,-10,-11,-13,-13,-14,-15,-15,-16,-16,-16,-17,-17,-17,-17,-17,-17,-17,-17,-17,-17,-16,-16,-16,-15,-15,-14,-13,-13,-11,-10,-8,-5},
293Arc17rowcnt[34] = {10,16,20,22,26,26,28,30,30,32,32,32,34,34,34,34,34,34,34,34,34,34,32,32,32,30,30,28,26,26,22,20,16,10},
294Arc18cnt = 36,
295Arc18y[36] = {-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18},
296Arc18x[36] = {-5,-8,-10,-11,-13,-14,-14,-15,-16,-16,-17,-17,-17,-18,-18,-18,-18,-18,-18,-18,-18,-18,-18,-17,-17,-17,-16,-16,-15,-14,-14,-13,-11,-10,-8,-5},
297Arc18rowcnt[36] = {10,16,20,22,26,28,28,30,32,32,34,34,34,36,36,36,36,36,36,36,36,36,36,34,34,34,32,32,30,28,28,26,22,20,16,10},
298Arc19cnt = 38,
299Arc19y[38] = {-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19},
300Arc19x[38] = {-5,-9,-10,-12,-13,-14,-15,-16,-16,-17,-18,-18,-18,-18,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-18,-18,-18,-18,-17,-16,-16,-15,-14,-13,-12,-10,-9,-5},
301Arc19rowcnt[38] = {10,18,20,24,26,28,30,32,32,34,36,36,36,36,38,38,38,38,38,38,38,38,38,38,36,36,36,36,34,32,32,30,28,26,24,20,18,10},
302Arc20cnt = 40,
303Arc20y[40] = {-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20},
304Arc20x[40] = {-5,-9,-10,-12,-13,-15,-15,-16,-17,-17,-18,-19,-19,-19,-19,-20,-20,-20,-20,-20,-20,-20,-20,-20,-20,-19,-19,-19,-19,-18,-17,-17,-16,-15,-15,-13,-12,-10,-9,-5},
305Arc20rowcnt[40] = {10,18,20,24,26,30,30,32,34,34,36,38,38,38,38,40,40,40,40,40,40,40,40,40,40,38,38,38,38,36,34,34,32,30,30,26,24,20,18,10},
306Arc21cnt = 42,
307Arc21y[42] = {-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21},
308Arc21x[42] = {-5,-9,-11,-12,-14,-15,-16,-17,-17,-18,-19,-19,-20,-20,-20,-20,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-20,-20,-20,-20,-19,-19,-18,-17,-17,-16,-15,-14,-12,-11,-9,-5},
309Arc21rowcnt[42] = {10,18,22,24,28,30,32,34,34,36,38,38,40,40,40,40,42,42,42,42,42,42,42,42,42,42,40,40,40,40,38,38,36,34,34,32,30,28,24,22,18,10},
310Arc22cnt = 44,
311Arc22y[44] = {-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22},
312Arc22x[44] = {-5,-9,-11,-12,-14,-15,-16,-17,-18,-18,-19,-20,-20,-21,-21,-21,-21,-22,-22,-22,-22,-22,-22,-22,-22,-22,-22,-21,-21,-21,-21,-20,-20,-19,-18,-18,-17,-16,-15,-14,-12,-11,-9,-5},
313Arc22rowcnt[44] = {10,18,22,24,28,30,32,34,36,36,38,40,40,42,42,42,42,44,44,44,44,44,44,44,44,44,44,42,42,42,42,40,40,38,36,36,34,32,30,28,24,22,18,10},
314Arc23cnt = 46,
315Arc23y[46] = {-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23},
316Arc23x[46] = {-5,-10,-11,-13,-14,-16,-17,-18,-18,-19,-20,-20,-21,-22,-22,-22,-22,-22,-23,-23,-23,-23,-23,-23,-23,-23,-23,-23,-22,-22,-22,-22,-22,-21,-20,-20,-19,-18,-18,-17,-16,-14,-13,-11,-10,-5},
317Arc23rowcnt[46] = {10,20,22,26,28,32,34,36,36,38,40,40,42,44,44,44,44,44,46,46,46,46,46,46,46,46,46,46,44,44,44,44,44,42,40,40,38,36,36,34,32,28,26,22,20,10},
318Arc24cnt = 48,
319Arc24y[48] = {-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24},
320Arc24x[48] = {-5,-10,-11,-13,-14,-16,-17,-18,-19,-19,-20,-21,-21,-22,-23,-23,-23,-23,-23,-24,-24,-24,-24,-24,-24,-24,-24,-24,-24,-23,-23,-23,-23,-23,-22,-21,-21,-20,-19,-19,-18,-17,-16,-14,-13,-11,-10,-5},
321Arc24rowcnt[48] = {10,20,22,26,28,32,34,36,38,38,40,42,42,44,46,46,46,46,46,48,48,48,48,48,48,48,48,48,48,46,46,46,46,46,44,42,42,40,38,38,36,34,32,28,26,22,20,10},
322Arc25cnt = 50,
323Arc25y[50] = {-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25},
324Arc25x[50] = {-5,-10,-12,-13,-15,-16,-18,-19,-19,-20,-21,-21,-22,-23,-23,-24,-24,-24,-24,-24,-25,-25,-25,-25,-25,-25,-25,-25,-25,-25,-24,-24,-24,-24,-24,-23,-23,-22,-21,-21,-20,-19,-19,-18,-16,-15,-13,-12,-10,-5},
325Arc25rowcnt[50] = {10,20,24,26,30,32,36,38,38,40,42,42,44,46,46,48,48,48,48,48,50,50,50,50,50,50,50,50,50,50,48,48,48,48,48,46,46,44,42,42,40,38,38,36,32,30,26,24,20,10},
326Arc26cnt = 52,
327Arc26y[52] = {-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26},
328Arc26x[52] = {-5,-10,-12,-14,-15,-16,-18,-19,-20,-20,-21,-22,-23,-23,-24,-24,-25,-25,-25,-25,-25,-26,-26,-26,-26,-26,-26,-26,-26,-26,-26,-25,-25,-25,-25,-25,-24,-24,-23,-23,-22,-21,-20,-20,-19,-18,-16,-15,-14,-12,-10,-5},
329Arc26rowcnt[52] = {10,20,24,28,30,32,36,38,40,40,42,44,46,46,48,48,50,50,50,50,50,52,52,52,52,52,52,52,52,52,52,50,50,50,50,50,48,48,46,46,44,42,40,40,38,36,32,30,28,24,20,10},
330Arc27cnt = 54,
331Arc27y[54] = {-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27},
332Arc27x[54] = {-5,-10,-12,-14,-15,-17,-18,-20,-20,-21,-22,-22,-23,-24,-24,-25,-25,-26,-26,-26,-26,-26,-27,-27,-27,-27,-27,-27,-27,-27,-27,-27,-26,-26,-26,-26,-26,-25,-25,-24,-24,-23,-22,-22,-21,-20,-20,-18,-17,-15,-14,-12,-10,-5},
333Arc27rowcnt[54] = {10,20,24,28,30,34,36,40,40,42,44,44,46,48,48,50,50,52,52,52,52,52,54,54,54,54,54,54,54,54,54,54,52,52,52,52,52,50,50,48,48,46,44,44,42,40,40,36,34,30,28,24,20,10},
334Arc28cnt = 56,
335Arc28y[56] = {-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28},
336Arc28x[56] = {-5,-10,-13,-14,-16,-17,-19,-20,-21,-22,-22,-23,-24,-24,-25,-26,-26,-26,-27,-27,-27,-27,-27,-28,-28,-28,-28,-28,-28,-28,-28,-28,-28,-27,-27,-27,-27,-27,-26,-26,-26,-25,-24,-24,-23,-22,-22,-21,-20,-19,-17,-16,-14,-13,-10,-5},
337Arc28rowcnt[56] = {10,20,26,28,32,34,38,40,42,44,44,46,48,48,50,52,52,52,54,54,54,54,54,56,56,56,56,56,56,56,56,56,56,54,54,54,54,54,52,52,52,50,48,48,46,44,44,42,40,38,34,32,28,26,20,10},
338Arc29cnt = 58,
339Arc29y[58] = {-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29},
340Arc29x[58] = {-5,-10,-13,-14,-16,-17,-19,-20,-21,-22,-23,-23,-24,-25,-25,-26,-27,-27,-27,-28,-28,-28,-28,-28,-29,-29,-29,-29,-29,-29,-29,-29,-29,-29,-28,-28,-28,-28,-28,-27,-27,-27,-26,-25,-25,-24,-23,-23,-22,-21,-20,-19,-17,-16,-14,-13,-10,-5},
341Arc29rowcnt[58] = {10,20,26,28,32,34,38,40,42,44,46,46,48,50,50,52,54,54,54,56,56,56,56,56,58,58,58,58,58,58,58,58,58,58,56,56,56,56,56,54,54,54,52,50,50,48,46,46,44,42,40,38,34,32,28,26,20,10},
342Arc30cnt = 60,
343Arc30y[60] = {-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30},
344Arc30x[60] = {-5,-10,-13,-15,-16,-18,-19,-21,-22,-23,-23,-24,-25,-25,-26,-27,-27,-28,-28,-28,-29,-29,-29,-29,-29,-30,-30,-30,-30,-30,-30,-30,-30,-30,-30,-29,-29,-29,-29,-29,-28,-28,-28,-27,-27,-26,-25,-25,-24,-23,-23,-22,-21,-19,-18,-16,-15,-13,-10,-5},
345Arc30rowcnt[60] = {10,20,26,30,32,36,38,42,44,46,46,48,50,50,52,54,54,56,56,56,58,58,58,58,58,60,60,60,60,60,60,60,60,60,60,58,58,58,58,58,56,56,56,54,54,52,50,50,48,46,46,44,42,38,36,32,30,26,20,10},
346Arc31cnt = 62,
347Arc31y[62] = {-30,-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31},
348Arc31x[62] = {-5,-10,-13,-15,-16,-18,-19,-21,-22,-23,-24,-24,-25,-26,-26,-27,-28,-28,-29,-29,-29,-30,-30,-30,-30,-30,-31,-31,-31,-31,-31,-31,-31,-31,-31,-31,-30,-30,-30,-30,-30,-29,-29,-29,-28,-28,-27,-26,-26,-25,-24,-24,-23,-22,-21,-19,-18,-16,-15,-13,-10,-5},
349Arc31rowcnt[62] = {10,20,26,30,32,36,38,42,44,46,48,48,50,52,52,54,56,56,58,58,58,60,60,60,60,60,62,62,62,62,62,62,62,62,62,62,60,60,60,60,60,58,58,58,56,56,54,52,52,50,48,48,46,44,42,38,36,32,30,26,20,10},
350Arc32cnt = 64,
351Arc32y[64] = {-31,-30,-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32},
352Arc32x[64] = {-5,-10,-14,-15,-17,-18,-20,-21,-23,-24,-24,-25,-26,-26,-27,-28,-28,-29,-30,-30,-30,-30,-31,-31,-31,-31,-31,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-31,-31,-31,-31,-31,-30,-30,-30,-30,-29,-28,-28,-27,-26,-26,-25,-24,-24,-23,-21,-20,-18,-17,-15,-14,-10,-5},
353Arc32rowcnt[64] = {10,20,28,30,34,36,40,42,46,48,48,50,52,52,54,56,56,58,60,60,60,60,62,62,62,62,62,64,64,64,64,64,64,64,64,64,64,62,62,62,62,62,60,60,60,60,58,56,56,54,52,52,50,48,48,46,42,40,36,34,30,28,20,10},
354Arc33cnt = 66,
355Arc33y[66] = {-32,-31,-30,-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33},
356Arc33x[66] = {-5,-10,-14,-15,-17,-18,-20,-21,-23,-24,-25,-25,-26,-27,-27,-28,-29,-29,-30,-31,-31,-31,-31,-32,-32,-32,-32,-32,-33,-33,-33,-33,-33,-33,-33,-33,-33,-33,-32,-32,-32,-32,-32,-31,-31,-31,-31,-30,-29,-29,-28,-27,-27,-26,-25,-25,-24,-23,-21,-20,-18,-17,-15,-14,-10,-5},
357Arc33rowcnt[66] = {10,20,28,30,34,36,40,42,46,48,50,50,52,54,54,56,58,58,60,62,62,62,62,64,64,64,64,64,66,66,66,66,66,66,66,66,66,66,64,64,64,64,64,62,62,62,62,60,58,58,56,54,54,52,50,50,48,46,42,40,36,34,30,28,20,10},
358Arc34cnt = 68,
359Arc34y[68] = {-33,-32,-31,-30,-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34},
360Arc34x[68] = {-5,-10,-14,-16,-18,-20,-21,-22,-23,-25,-25,-26,-27,-28,-29,-29,-30,-30,-31,-31,-32,-32,-32,-32,-33,-33,-33,-33,-33,-34,-34,-34,-34,-34,-34,-34,-34,-34,-34,-33,-33,-33,-33,-33,-32,-32,-32,-32,-31,-31,-30,-30,-29,-29,-28,-27,-26,-25,-25,-23,-22,-21,-20,-18,-16,-14,-10,-5},
361Arc34rowcnt[68] = {10,20,28,32,36,40,42,44,46,50,50,52,54,56,58,58,60,60,62,62,64,64,64,64,66,66,66,66,66,68,68,68,68,68,68,68,68,68,68,66,66,66,66,66,64,64,64,64,62,62,60,60,58,58,56,54,52,50,50,46,44,42,40,36,32,28,20,10},
362Arc35cnt = 70,
363Arc35y[70] = {-34,-33,-32,-31,-30,-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35},
364Arc35x[70] = {-5,-10,-15,-16,-18,-20,-21,-23,-24,-25,-26,-27,-28,-28,-29,-30,-30,-31,-31,-32,-33,-33,-33,-33,-33,-34,-34,-34,-34,-34,-35,-35,-35,-35,-35,-35,-35,-35,-35,-35,-34,-34,-34,-34,-34,-33,-33,-33,-33,-33,-32,-31,-31,-30,-30,-29,-28,-28,-27,-26,-25,-24,-23,-21,-20,-18,-16,-15,-10,-5},
365Arc35rowcnt[70] = {10,20,30,32,34,40,42,46,48,50,52,54,56,56,58,60,60,62,62,64,66,66,66,66,66,68,68,68,68,68,70,70,70,70,70,70,70,70,70,70,68,68,68,68,68,66,66,66,66,66,64,62,62,60,60,58,56,56,54,52,50,48,46,42,40,34,32,30,20,10},
366Arc36cnt = 72,
367Arc36y[72] = {-35,-34,-33,-32,-31,-30,-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36},
368Arc36x[72] = {-9,-12,-15,-17,-18,-20,-22,-23,-24,-25,-26,-27,-28,-29,-30,-30,-31,-31,-32,-33,-33,-34,-34,-34,-35,-35,-35,-36,-36,-36,-36,-36,-36,-36,-36,-36,-36,-36,-36,-36,-36,-36,-36,-36,-36,-35,-35,-35,-34,-34,-34,-33,-33,-32,-31,-31,-30,-30,-29,-28,-27,-26,-25,-24,-23,-22,-20,-18,-17,-15,-12,-9},
369Arc36rowcnt[72] = {18,24,30,34,38,40,44,46,48,50,52,54,56,58,60,60,62,62,64,66,66,68,68,68,70,70,70,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,70,70,70,68,68,68,66,66,64,62,62,60,60,58,56,54,52,50,48,46,44,40,38,34,30,24,18},
370Arc37cnt = 74,
371Arc37y[74] = {-36,-35,-34,-33,-32,-31,-30,-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37},
372Arc37x[74] = {-9,-12,-15,-17,-19,-21,-22,-23,-24,-26,-27,-28,-28,-29,-30,-31,-32,-32,-33,-33,-34,-34,-35,-35,-35,-36,-36,-36,-37,-37,-37,-37,-37,-37,-37,-37,-37,-37,-37,-37,-37,-37,-37,-37,-37,-37,-36,-36,-36,-35,-35,-35,-34,-34,-33,-33,-32,-32,-31,-30,-29,-28,-28,-27,-26,-24,-23,-22,-21,-19,-17,-15,-12,-9},
373Arc37rowcnt[74] = {18,24,30,34,38,42,44,46,48,52,54,56,56,58,60,62,64,64,66,66,68,68,70,70,70,72,72,72,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,72,72,72,70,70,70,68,68,66,66,64,64,62,60,58,56,56,54,52,48,46,44,42,38,34,30,24,18},
374Arc38cnt = 76,
375Arc38y[76] = {-37,-36,-35,-34,-33,-32,-31,-30,-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38},
376Arc38x[76] = {-9,-12,-15,-17,-19,-21,-22,-24,-25,-26,-27,-28,-29,-30,-31,-31,-32,-33,-33,-34,-34,-35,-35,-36,-36,-36,-37,-37,-37,-38,-38,-38,-38,-38,-38,-38,-38,-38,-38,-38,-38,-38,-38,-38,-38,-38,-38,-37,-37,-37,-36,-36,-36,-35,-35,-34,-34,-33,-33,-32,-31,-31,-30,-29,-28,-27,-26,-25,-24,-22,-21,-19,-17,-15,-12,-9},
377Arc38rowcnt[76] = {18,24,30,34,38,42,44,48,50,52,54,56,58,60,62,62,64,66,66,68,68,70,70,72,72,72,74,74,74,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,74,74,74,72,72,72,70,70,68,68,66,66,64,62,62,60,58,56,54,52,50,48,44,42,38,34,30,24,18},
378Arc39cnt = 78,
379Arc39y[78] = {-38,-37,-36,-35,-34,-33,-32,-31,-30,-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39},
380Arc39x[78] = {-9,-12,-15,-17,-19,-21,-23,-24,-25,-26,-28,-29,-29,-30,-31,-32,-33,-33,-34,-34,-35,-35,-36,-36,-37,-37,-37,-38,-38,-38,-39,-39,-39,-39,-39,-39,-39,-39,-39,-39,-39,-39,-39,-39,-39,-39,-39,-39,-38,-38,-38,-37,-37,-37,-36,-36,-35,-35,-34,-34,-33,-33,-32,-31,-30,-29,-29,-28,-26,-25,-24,-23,-21,-19,-17,-15,-12,-9},
381Arc39rowcnt[78] = {18,24,30,34,38,42,46,48,50,52,56,58,58,60,62,64,66,66,68,68,70,70,72,72,74,74,74,76,76,76,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,76,76,76,74,74,74,72,72,70,70,68,68,66,66,64,62,60,58,58,56,52,50,48,46,42,38,34,30,24,18},
382Arc40cnt = 80,
383Arc40y[80] = {-39,-38,-37,-36,-35,-34,-33,-32,-31,-30,-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40},
384Arc40x[80] = {-9,-12,-16,-18,-19,-21,-23,-24,-25,-27,-28,-29,-30,-31,-31,-32,-33,-34,-34,-35,-35,-36,-37,-37,-38,-38,-38,-38,-39,-39,-39,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-39,-39,-39,-38,-38,-38,-38,-37,-37,-36,-35,-35,-34,-34,-33,-32,-31,-31,-30,-29,-28,-27,-25,-24,-23,-21,-19,-18,-16,-12,-9},
385Arc40rowcnt[80] = {18,24,32,34,38,42,46,48,50,52,56,58,60,62,62,64,66,68,68,70,70,72,74,74,76,76,76,76,78,78,78,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,78,78,78,76,76,76,76,74,74,72,70,70,68,68,66,64,62,62,60,58,56,52,50,48,46,42,38,34,32,24,18},
386Arc41cnt = 82,
387Arc41y[82] = {-40,-39,-38,-37,-36,-35,-34,-33,-32,-31,-30,-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41},
388Arc41x[82] = {-9,-13,-16,-18,-20,-22,-23,-25,-26,-27,-28,-29,-30,-31,-32,-33,-34,-34,-35,-36,-36,-37,-37,-38,-38,-39,-39,-39,-40,-40,-40,-40,-41,-41,-41,-41,-41,-41,-41,-41,-41,-41,-41,-41,-41,-41,-41,-41,-41,-41,-40,-40,-40,-40,-39,-39,-39,-38,-38,-37,-37,-36,-36,-35,-34,-34,-33,-32,-31,-30,-29,-28,-27,-26,-25,-23,-22,-20,-18,-16,-13,-9},
389Arc41rowcnt[82] = {18,26,32,36,40,44,46,50,52,54,56,58,60,62,64,66,68,68,70,72,72,74,74,76,76,78,78,78,80,80,80,80,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,80,80,80,80,78,78,78,76,76,74,74,72,72,70,68,68,66,64,62,60,58,56,54,52,50,46,44,40,36,32,26,18},
390Arc42cnt = 84,
391Arc42y[84] = {-41,-40,-39,-38,-37,-36,-35,-34,-33,-32,-31,-30,-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42},
392Arc42x[84] = {-9,-13,-16,-18,-20,-22,-24,-25,-26,-27,-29,-30,-31,-32,-32,-33,-34,-35,-36,-36,-37,-37,-38,-38,-39,-39,-40,-40,-40,-41,-41,-41,-41,-42,-42,-42,-42,-42,-42,-42,-42,-42,-42,-42,-42,-42,-42,-42,-42,-42,-42,-41,-41,-41,-41,-40,-40,-40,-39,-39,-38,-38,-37,-37,-36,-36,-35,-34,-33,-32,-32,-31,-30,-29,-27,-26,-25,-24,-22,-20,-18,-16,-13,-9},
393Arc42rowcnt[84] = {18,26,32,36,40,44,48,50,52,54,58,60,62,64,64,66,68,70,72,72,74,74,76,76,78,78,80,80,80,82,82,82,82,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,82,82,82,82,80,80,80,78,78,76,76,74,74,72,72,70,68,66,64,64,62,60,58,54,52,50,48,44,40,36,32,26,18},
394Arc43cnt = 86,
395Arc43y[86] = {-42,-41,-40,-39,-38,-37,-36,-35,-34,-33,-32,-31,-30,-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43},
396Arc43x[86] = {-10,-13,-16,-18,-20,-22,-24,-25,-27,-28,-29,-30,-31,-32,-33,-34,-35,-35,-36,-37,-37,-38,-38,-39,-39,-40,-40,-41,-41,-41,-42,-42,-42,-43,-43,-43,-43,-43,-43,-43,-43,-43,-43,-43,-43,-43,-43,-43,-43,-43,-43,-43,-43,-42,-42,-42,-41,-41,-41,-40,-40,-39,-39,-38,-38,-37,-37,-36,-35,-35,-34,-33,-32,-31,-30,-29,-28,-27,-25,-24,-22,-20,-18,-16,-13,-10},
397Arc43rowcnt[86] = {20,26,32,36,40,44,48,50,54,56,58,60,62,64,66,68,70,70,72,74,74,76,76,78,78,80,80,82,82,82,84,84,84,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,84,84,84,82,82,82,80,80,78,78,76,76,74,74,72,70,70,68,66,64,62,60,58,56,54,50,48,44,40,36,32,26,20},
398Arc44cnt = 88,
399Arc44y[88] = {-43,-42,-41,-40,-39,-38,-37,-36,-35,-34,-33,-32,-31,-30,-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44},
400Arc44x[88] = {-10,-13,-16,-19,-20,-22,-24,-26,-27,-28,-29,-31,-32,-33,-33,-34,-35,-36,-37,-37,-38,-38,-39,-39,-40,-41,-41,-41,-42,-42,-42,-43,-43,-43,-44,-44,-44,-44,-44,-44,-44,-44,-44,-44,-44,-44,-44,-44,-44,-44,-44,-44,-44,-44,-43,-43,-43,-42,-42,-42,-41,-41,-41,-40,-39,-39,-38,-38,-37,-37,-36,-35,-34,-33,-33,-32,-31,-29,-28,-27,-26,-24,-22,-20,-19,-16,-13,-10},
401Arc44rowcnt[88] = {20,26,32,38,40,44,48,52,54,56,58,62,64,66,66,68,70,72,74,74,76,76,78,78,80,82,82,82,84,84,84,86,86,86,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,86,86,86,84,84,84,82,82,82,80,78,78,76,76,74,74,72,70,68,66,66,64,62,58,56,54,52,48,44,40,38,32,26,20},
402Arc45cnt = 90,
403Arc45y[90] = {-44,-43,-42,-41,-40,-39,-38,-37,-36,-35,-34,-33,-32,-31,-30,-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45},
404Arc45x[90] = {-10,-13,-16,-19,-21,-23,-24,-26,-27,-28,-30,-31,-32,-33,-34,-35,-35,-36,-37,-38,-38,-39,-40,-40,-41,-41,-42,-42,-42,-43,-43,-43,-44,-44,-44,-45,-45,-45,-45,-45,-45,-45,-45,-45,-45,-45,-45,-45,-45,-45,-45,-45,-45,-45,-45,-44,-44,-44,-43,-43,-43,-42,-42,-42,-41,-41,-40,-40,-39,-38,-38,-37,-36,-35,-35,-34,-33,-32,-31,-30,-28,-27,-26,-24,-23,-21,-19,-16,-13,-10},
405Arc45rowcnt[90] = {20,26,32,38,42,46,48,52,54,56,60,62,64,66,68,70,70,72,74,76,76,78,80,80,82,82,84,84,84,86,86,86,88,88,88,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,88,88,88,86,86,86,84,84,84,82,82,80,80,78,76,76,74,72,70,70,68,66,64,62,60,56,54,52,48,46,42,38,32,26,20},
406Arc46cnt = 92,
407Arc46y[92] = {-45,-44,-43,-42,-41,-40,-39,-38,-37,-36,-35,-34,-33,-32,-31,-30,-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46},
408Arc46x[92] = {-10,-13,-16,-19,-21,-23,-25,-26,-28,-29,-30,-31,-32,-33,-34,-35,-36,-37,-38,-38,-39,-40,-40,-41,-41,-42,-42,-43,-43,-43,-44,-44,-44,-45,-45,-45,-46,-46,-46,-46,-46,-46,-46,-46,-46,-46,-46,-46,-46,-46,-46,-46,-46,-46,-46,-46,-45,-45,-45,-44,-44,-44,-43,-43,-43,-42,-42,-41,-41,-40,-40,-39,-38,-38,-37,-36,-35,-34,-33,-32,-31,-30,-29,-28,-26,-25,-23,-21,-19,-16,-13,-10},
409Arc46rowcnt[92] = {20,26,32,38,42,46,50,52,54,56,60,62,64,66,68,70,72,74,76,76,78,80,80,82,82,84,84,86,86,86,88,88,88,90,90,90,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,90,90,90,88,88,88,86,86,86,84,84,82,82,80,80,78,76,76,74,72,70,68,66,64,62,60,56,54,52,50,46,42,38,32,26,20};
410#endif
411
412/*
413 * 4 2 6
414 * 0 8 1
415 * 5 3 7
416 */
417
418/* pixel(nxp) has left, right, up or down a white pixel at its side -> return YES
419 */
420#define SameGradients(grad, grad0)	\
421( ((Diff(grad.y, 0)<TOLERANCE || Diff(grad0.y, 0)<TOLERANCE) && Diff(grad.y/grad.x, grad0.y/grad0.x) < 0.01 && \
422   ((grad.x<0 && grad0.x<0) || (grad.x>0 && grad0.x>0))) || \
423  ((Diff(grad.x, 0)<TOLERANCE || Diff(grad0.x, 0)<TOLERANCE) && Diff(grad.x/grad.y, grad0.x/grad0.y) < 0.01 && \
424   ((grad.y<0 && grad0.y<0) || (grad.y>0 && grad0.y>0))) || \
425  (Abs(grad.x) < Abs(grad.y) && grad.y != 0 && grad0.y != 0 && ((grad.y<0 && grad0.y<0) || (grad.y>0 && grad0.y>0)) &&\
426   Diff(grad.x, 0)>TOLERANCE && Diff(grad0.x, 0)>TOLERANCE && Diff(grad.x/grad.y, grad0.x/grad0.y) < 0.03) || \
427  (Abs(grad.x) > Abs(grad.y) && grad.x != 0 && grad0.x != 0 && ((grad.x<0 && grad0.x<0) || (grad.x>0 && grad0.x>0)) &&\
428   Diff(grad.y, 0)>TOLERANCE && Diff(grad0.y, 0)>TOLERANCE && Diff(grad.y/grad.x, grad0.y/grad0.x) < 0.03) || \
429  (Diff(grad.x, 0.0)>TOLERANCE && Diff(grad0.x, 0.0)>TOLERANCE && Diff(grad.x/grad.y, grad0.x/grad0.y) < 0.01 && \
430   ((grad.x < 0 && grad0.x < 0) || (grad.x > 0 && grad0.x > 0) || \
431    (grad.y < 0 && grad0.y < 0) || (grad.y > 0 && grad0.y > 0))) || \
432  (Diff(grad.y, 0.0)>TOLERANCE && Diff(grad0.y, 0.0)>TOLERANCE && Diff(grad.y/grad.x, grad0.y/grad0.x) < 0.01 && \
433   ((grad.x < 0 && grad0.x < 0) || (grad.x > 0 && grad0.x > 0) || \
434    (grad.y < 0 && grad0.y < 0) || (grad.y > 0 && grad0.y > 0))) )
435
436#define NearlySameGradients(grad, grad0)	\
437( ((Diff(grad.y, 0)<TOLERANCE || Diff(grad0.y, 0)<TOLERANCE) && Diff(grad.y/grad.x, grad0.y/grad0.x) < 0.3 && \
438   ((grad.x<0 && grad0.x<0) || (grad.x>0 && grad0.x>0))) || \
439  ((Diff(grad.x, 0)<TOLERANCE || Diff(grad0.x, 0)<TOLERANCE) && Diff(grad.x/grad.y, grad0.x/grad0.y) < 0.3 && \
440   ((grad.y<0 && grad0.y<0) || (grad.y>0 && grad0.y>0))) || \
441  (Abs(grad.x) < Abs(grad.y) && grad.y != 0 && grad0.y != 0 && ((grad.y<0 && grad0.y<0) || (grad.y>0 && grad0.y>0)) &&\
442   Diff(grad.x, 0)>TOLERANCE && Diff(grad0.x, 0)>TOLERANCE && Diff(grad.x/grad.y, grad0.x/grad0.y) < 0.3) || \
443  (Abs(grad.x) > Abs(grad.y) && grad.x != 0 && grad0.x != 0 && ((grad.x<0 && grad0.x<0) || (grad.x>0 && grad0.x>0)) &&\
444   Diff(grad.y, 0)>TOLERANCE && Diff(grad0.y, 0)>TOLERANCE && Diff(grad.y/grad.x, grad0.y/grad0.x) < 0.3) || \
445  (Diff(grad.x, 0.0)>TOLERANCE && Diff(grad0.x, 0.0)>TOLERANCE && Diff(grad.x/grad.y, grad0.x/grad0.y) < 0.25 && \
446   ((grad.x < 0 && grad0.x < 0) || (grad.x > 0 && grad0.x > 0) || \
447    (grad.y < 0 && grad0.y < 0) || (grad.y > 0 && grad0.y > 0))) || \
448  (Diff(grad.y, 0.0)>TOLERANCE && Diff(grad0.y, 0.0)>TOLERANCE && Diff(grad.y/grad.x, grad0.y/grad0.x) < 0.25 && \
449   ((grad.x < 0 && grad0.x < 0) || (grad.x > 0 && grad0.x > 0) || \
450    (grad.y < 0 && grad0.y < 0) || (grad.y > 0 && grad0.y > 0))) )
451
452#define NNSameGradients(grad, grad0)	\
453( ((Diff(grad.y, 0)<TOLERANCE || Diff(grad0.y, 0)<TOLERANCE) && Diff(grad.y/grad.x, grad0.y/grad0.x) < 0.5 && \
454   ((grad.x<0 && grad0.x<0) || (grad.x>0 && grad0.x>0))) || \
455  ((Diff(grad.x, 0)<TOLERANCE || Diff(grad0.x, 0)<TOLERANCE) && Diff(grad.x/grad.y, grad0.x/grad0.y) < 0.5 && \
456   ((grad.y<0 && grad0.y<0) || (grad.y>0 && grad0.y>0))) || \
457  (Abs(grad.x) < Abs(grad.y) && grad.y != 0 && grad0.y != 0 && ((grad.y<0 && grad0.y<0) || (grad.y>0 && grad0.y>0)) &&\
458   Diff(grad.x, 0)>TOLERANCE && Diff(grad0.x, 0)>TOLERANCE && Diff(grad.x/grad.y, grad0.x/grad0.y) < 0.5) || \
459  (Abs(grad.x) > Abs(grad.y) && grad.x != 0 && grad0.x != 0 && ((grad.x<0 && grad0.x<0) || (grad.x>0 && grad0.x>0)) &&\
460   Diff(grad.y, 0)>TOLERANCE && Diff(grad0.y, 0)>TOLERANCE && Diff(grad.y/grad.x, grad0.y/grad0.x) < 0.5) || \
461  (Diff(grad.x, 0.0)>TOLERANCE && Diff(grad0.x, 0.0)>TOLERANCE && Diff(grad.x/grad.y, grad0.x/grad0.y) < 0.5 && \
462   ((grad.x < 0 && grad0.x < 0) || (grad.x > 0 && grad0.x > 0) || \
463    (grad.y < 0 && grad0.y < 0) || (grad.y > 0 && grad0.y > 0))) || \
464  (Diff(grad.y, 0.0)>TOLERANCE && Diff(grad0.y, 0.0)>TOLERANCE && Diff(grad.y/grad.x, grad0.y/grad0.x) < 0.5 && \
465   ((grad.x < 0 && grad0.x < 0) || (grad.x > 0 && grad0.x > 0) || \
466    (grad.y < 0 && grad0.y < 0) || (grad.y > 0 && grad0.y > 0))) )
467
468#define NNNNSameGradients(grad, grad0)	\
469( ((Diff(grad.y, 0)<TOLERANCE || Diff(grad0.y, 0)<TOLERANCE) && Diff(grad.y/grad.x, grad0.y/grad0.x) < 0.65 && \
470   ((grad.x<0 && grad0.x<0) || (grad.x>0 && grad0.x>0))) || \
471  ((Diff(grad.x, 0)<TOLERANCE || Diff(grad0.x, 0)<TOLERANCE) && Diff(grad.x/grad.y, grad0.x/grad0.y) < 0.65 && \
472   ((grad.y<0 && grad0.y<0) || (grad.y>0 && grad0.y>0))) || \
473  (Abs(grad.x) < Abs(grad.y) && grad.y != 0 && grad0.y != 0 && ((grad.y<0 && grad0.y<0) || (grad.y>0 && grad0.y>0)) &&\
474   Diff(grad.x, 0)>TOLERANCE && Diff(grad0.x, 0)>TOLERANCE && Diff(grad.x/grad.y, grad0.x/grad0.y) < 0.65) || \
475  (Abs(grad.x) > Abs(grad.y) && grad.x != 0 && grad0.x != 0 && ((grad.x<0 && grad0.x<0) || (grad.x>0 && grad0.x>0)) &&\
476   Diff(grad.y, 0)>TOLERANCE && Diff(grad0.y, 0)>TOLERANCE && Diff(grad.y/grad.x, grad0.y/grad0.x) < 0.65) || \
477  (Diff(grad.x, 0.0)>TOLERANCE && Diff(grad0.x, 0.0)>TOLERANCE && Diff(grad.x/grad.y, grad0.x/grad0.y) < 0.65 && \
478   ((grad.x < 0 && grad0.x < 0) || (grad.x > 0 && grad0.x > 0) || \
479    (grad.y < 0 && grad0.y < 0) || (grad.y > 0 && grad0.y > 0))) || \
480  (Diff(grad.y, 0.0)>TOLERANCE && Diff(grad0.y, 0.0)>TOLERANCE && Diff(grad.y/grad.x, grad0.y/grad0.x) < 0.65 && \
481   ((grad.x < 0 && grad0.x < 0) || (grad.x > 0 && grad0.x > 0) || \
482    (grad.y < 0 && grad0.y < 0) || (grad.y > 0 && grad0.y > 0))) )
483
484- (void)invertData
485{   int			i;
486    unsigned char	everything=255;
487
488    for (i=0; i<size; i++)
489        *(data+i) ^= everything;
490}
491
492/* modified: 02.02.00
493 *
494 */
495-(void)drawArcInDataAt:(int)byteX radius:(int)radius color:(unsigned char)col
496{   int		j;
497
498    switch (radius)
499    {
500        case 0: return;
501        case 1:
502            *((WORD*)(data+byteX-bytesPerRow-1)) = 0; // intBlack
503            *((WORD*)(data+byteX-1)) = 0; // intBlack
504            *((WORD*)(data+byteX+bytesPerRow-1)) = 0; // intBlack
505            *((WORD*)(data+byteX-bytesPerRow)) = 0; // intBlack
506            *((WORD*)(data+byteX)) = 0; // intBlack
507            *((WORD*)(data+byteX+bytesPerRow)) = 0; // intBlack
508            break;
509        case 2:
510            for (j=0; j<Arc2cnt; j++)
511                memset((data+byteX+(Arc2y[j]*bytesPerRow)+(Arc2x[j])), col, Arc2rowcnt[j]);
512            break;
513        case 3:
514            for (j=0; j<Arc3cnt; j++)
515                memset((data+byteX+(Arc3y[j]*bytesPerRow)+(Arc3x[j])), col, Arc3rowcnt[j]);
516            break;
517        case 4:
518            for (j=0; j<Arc4cnt; j++)
519                memset((data+byteX+(Arc4y[j]*bytesPerRow)+(Arc4x[j])), col, Arc4rowcnt[j]);
520            break;
521        case 5:
522            for (j=0; j<Arc5cnt; j++)
523                memset((data+byteX+(Arc5y[j]*bytesPerRow)+(Arc5x[j])), col, Arc5rowcnt[j]);
524            break;
525        case 6:
526            for (j=0; j<Arc6cnt; j++)
527                memset((data+byteX+(Arc6y[j]*bytesPerRow)+(Arc6x[j])), col, Arc6rowcnt[j]);
528            break;
529        case 7:
530            for (j=0; j<Arc7cnt; j++)
531                memset((data+byteX+(Arc7y[j]*bytesPerRow)+(Arc7x[j])), col, Arc7rowcnt[j]);
532            break;
533        case 8:
534            for (j=0; j<Arc8cnt; j++)
535                memset((data+byteX+(Arc8y[j]*bytesPerRow)+(Arc8x[j])), col, Arc8rowcnt[j]);
536            break;
537        case 9:
538            for (j=0; j<Arc9cnt; j++)
539                memset((data+byteX+(Arc9y[j]*bytesPerRow)+(Arc9x[j])), col, Arc9rowcnt[j]);
540            break;
541        case 10:
542            for (j=0; j<Arc10cnt; j++)
543                memset((data+byteX+(Arc10y[j]*bytesPerRow)+(Arc10x[j])), col, Arc10rowcnt[j]);
544            break;
545        case 11:
546            for (j=0; j<Arc11cnt; j++)
547                memset((data+byteX+(Arc11y[j]*bytesPerRow)+(Arc11x[j])), col, Arc11rowcnt[j]);
548            break;
549        case 12:
550            for (j=0; j<Arc12cnt; j++)
551                memset((data+byteX+(Arc12y[j]*bytesPerRow)+(Arc12x[j])), col, Arc12rowcnt[j]);
552            break;
553        case 13:
554            for (j=0; j<Arc13cnt; j++)
555                memset((data+byteX+(Arc13y[j]*bytesPerRow)+(Arc13x[j])), col, Arc13rowcnt[j]);
556            break;
557        case 14:
558            for (j=0; j<Arc14cnt; j++)
559                memset((data+byteX+(Arc14y[j]*bytesPerRow)+(Arc14x[j])), col, Arc14rowcnt[j]);
560            break;
561        case 15:
562            for (j=0; j<Arc15cnt; j++)
563                memset((data+byteX+(Arc15y[j]*bytesPerRow)+(Arc15x[j])), col, Arc15rowcnt[j]+1);
564            break;
565        case 16:
566            for (j=0; j<Arc16cnt; j++)
567                memset((data+byteX+(Arc16y[j]*bytesPerRow)+(Arc16x[j])), col, Arc16rowcnt[j]+1);
568            break;
569        case 17:
570            for (j=0; j<Arc17cnt; j++)
571                memset((data+byteX+(Arc17y[j]*bytesPerRow)+(Arc17x[j])), col, Arc17rowcnt[j]+1);
572            break;
573        case 18:
574            for (j=0; j<Arc18cnt; j++)
575                memset((data+byteX+(Arc18y[j]*bytesPerRow)+(Arc18x[j])), col, Arc18rowcnt[j]+1);
576            break;
577        case 19:
578            for (j=0; j<Arc19cnt; j++)
579                memset((data+byteX+(Arc19y[j]*bytesPerRow)+(Arc19x[j])), col, Arc19rowcnt[j]+1);
580            break;
581        case 20:
582            for (j=0; j<Arc20cnt; j++)
583                memset((data+byteX+(Arc20y[j]*bytesPerRow)+(Arc20x[j])), col, Arc20rowcnt[j]+1);
584            break;
585        case 21:
586            for (j=0; j<Arc21cnt; j++)
587                memset((data+byteX+(Arc21y[j]*bytesPerRow)+(Arc21x[j])), col, Arc21rowcnt[j]+1);
588            break;
589        case 22:
590            for (j=0; j<Arc22cnt; j++)
591                memset((data+byteX+(Arc22y[j]*bytesPerRow)+(Arc22x[j])), col, Arc22rowcnt[j]+1);
592            break;
593        case 23:
594            for (j=0; j<Arc23cnt; j++)
595                memset((data+byteX+(Arc23y[j]*bytesPerRow)+(Arc23x[j])), col, Arc23rowcnt[j]+1);
596            break;
597        case 24:
598            for (j=0; j<Arc24cnt; j++)
599                memset((data+byteX+(Arc24y[j]*bytesPerRow)+(Arc24x[j])), col, Arc24rowcnt[j]+1);
600            break;
601        case 25:
602            for (j=0; j<Arc25cnt; j++)
603                memset((data+byteX+(Arc25y[j]*bytesPerRow)+(Arc25x[j])), col, Arc25rowcnt[j]+1);
604            break;
605        case 26:
606            for (j=0; j<Arc26cnt; j++)
607                memset((data+byteX+(Arc26y[j]*bytesPerRow)+(Arc26x[j])), col, Arc26rowcnt[j]+1);
608            break;
609        case 27:
610            for (j=0; j<Arc27cnt; j++)
611                memset((data+byteX+(Arc27y[j]*bytesPerRow)+(Arc27x[j])), col, Arc27rowcnt[j]+1);
612            break;
613        case 28:
614            for (j=0; j<Arc28cnt; j++)
615                memset((data+byteX+(Arc28y[j]*bytesPerRow)+(Arc28x[j])), col, Arc28rowcnt[j]+1);
616            break;
617        case 29:
618            for (j=0; j<Arc29cnt; j++)
619                memset((data+byteX+(Arc29y[j]*bytesPerRow)+(Arc29x[j])), col, Arc29rowcnt[j]+1);
620            break;
621        case 30:
622            for (j=0; j<Arc30cnt; j++)
623                memset((data+byteX+(Arc30y[j]*bytesPerRow)+(Arc30x[j])), col, Arc30rowcnt[j]+1);
624            break;
625        case 31:
626            for (j=0; j<Arc31cnt; j++)
627                memset((data+byteX+(Arc31y[j]*bytesPerRow)+(Arc31x[j])), col, Arc31rowcnt[j]+1);
628            break;
629        case 32:
630            for (j=0; j<Arc32cnt; j++)
631                memset((data+byteX+(Arc32y[j]*bytesPerRow)+(Arc32x[j])), col, Arc32rowcnt[j]+1);
632            break;
633        case 33:
634            for (j=0; j<Arc33cnt; j++)
635                memset((data+byteX+(Arc33y[j]*bytesPerRow)+(Arc33x[j])), col, Arc33rowcnt[j]+1);
636            break;
637        case 34:
638            for (j=0; j<Arc34cnt; j++)
639                memset((data+byteX+(Arc34y[j]*bytesPerRow)+(Arc34x[j])), col, Arc34rowcnt[j]+1);
640            break;
641        case 35:
642            for (j=0; j<Arc35cnt; j++)
643                memset((data+byteX+(Arc35y[j]*bytesPerRow)+(Arc35x[j])), col, Arc35rowcnt[j]+1);
644            break;
645       case 36:
646            for (j=0; j<Arc36cnt; j++)
647                memset((data+byteX+(Arc36y[j]*bytesPerRow)+(Arc36x[j])), col, Arc36rowcnt[j]+1);
648            break;
649       case 37:
650            for (j=0; j<Arc37cnt; j++)
651                memset((data+byteX+(Arc37y[j]*bytesPerRow)+(Arc37x[j])), col, Arc37rowcnt[j]+1);
652            break;
653       case 38:
654            for (j=0; j<Arc38cnt; j++)
655                memset((data+byteX+(Arc38y[j]*bytesPerRow)+(Arc38x[j])), col, Arc38rowcnt[j]+1);
656            break;
657       case 39:
658            for (j=0; j<Arc39cnt; j++)
659                memset((data+byteX+(Arc39y[j]*bytesPerRow)+(Arc39x[j])), col, Arc39rowcnt[j]+1);
660            break;
661       case 40:
662            for (j=0; j<Arc40cnt; j++)
663                memset((data+byteX+(Arc40y[j]*bytesPerRow)+(Arc40x[j])), col, Arc40rowcnt[j]+1);
664            break;
665       case 41:
666            for (j=0; j<Arc41cnt; j++)
667                memset((data+byteX+(Arc41y[j]*bytesPerRow)+(Arc41x[j])), col, Arc41rowcnt[j]+1);
668            break;
669       case 42:
670            for (j=0; j<Arc42cnt; j++)
671                memset((data+byteX+(Arc42y[j]*bytesPerRow)+(Arc42x[j])), col, Arc42rowcnt[j]+1);
672            break;
673       case 43:
674            for (j=0; j<Arc43cnt; j++)
675                memset((data+byteX+(Arc43y[j]*bytesPerRow)+(Arc43x[j])), col, Arc43rowcnt[j]+1);
676            break;
677       case 44:
678            for (j=0; j<Arc44cnt; j++)
679                memset((data+byteX+(Arc44y[j]*bytesPerRow)+(Arc44x[j])), col, Arc44rowcnt[j]+1);
680            break;
681       case 45:
682            for (j=0; j<Arc45cnt; j++)
683                memset((data+byteX+(Arc45y[j]*bytesPerRow)+(Arc45x[j])), col, Arc45rowcnt[j]+1);
684            break;
685       case 46:
686            for (j=0; j<Arc46cnt; j++)
687                memset((data+byteX+(Arc46y[j]*bytesPerRow)+(Arc46x[j])), col, Arc46rowcnt[j]+1);
688            break;
689        default: // calculate with a loop
690            printf("arcs greater 46 not yet implemented :-)");
691    }
692}
693
694#define NoEdgeGradients(grad, grad0)	\
695( ((Diff(grad.y, 0)<TOLERANCE || Diff(grad0.y, 0)<TOLERANCE) && Diff(grad.y/grad.x, grad0.y/grad0.x) < 1.5 && \
696   ((grad.x<0 && grad0.x<0) || (grad.x>0 && grad0.x>0))) || \
697  ((Diff(grad.x, 0)<TOLERANCE || Diff(grad0.x, 0)<TOLERANCE) && Diff(grad.x/grad.y, grad0.x/grad0.y) < 1.5 && \
698   ((grad.y<0 && grad0.y<0) || (grad.y>0 && grad0.y>0))) || \
699  (Abs(grad.x) < Abs(grad.y) && grad.y != 0 && grad0.y != 0 && ((grad.y<0 && grad0.y<0) || (grad.y>0 && grad0.y>0)) &&\
700   Diff(grad.x, 0)>TOLERANCE && Diff(grad0.x, 0)>TOLERANCE && Diff(grad.x/grad.y, grad0.x/grad0.y) < 1.5) || \
701  (Abs(grad.x) > Abs(grad.y) && grad.x != 0 && grad0.x != 0 && ((grad.x<0 && grad0.x<0) || (grad.x>0 && grad0.x>0)) &&\
702   Diff(grad.y, 0)>TOLERANCE && Diff(grad0.y, 0)>TOLERANCE && Diff(grad.y/grad.x, grad0.y/grad0.x) < 1.5) || \
703  (Diff(grad.x, 0.0)>TOLERANCE && Diff(grad0.x, 0.0)>TOLERANCE && Diff(grad.x/grad.y, grad0.x/grad0.y) < 1.5 && \
704   ((grad.x < 0 && grad0.x < 0) || (grad.x > 0 && grad0.x > 0) || \
705    (grad.y < 0 && grad0.y < 0) || (grad.y > 0 && grad0.y > 0))) || \
706  (Diff(grad.y, 0.0)>TOLERANCE && Diff(grad0.y, 0.0)>TOLERANCE && Diff(grad.y/grad.x, grad0.y/grad0.x) < 1.5 && \
707   ((grad.x < 0 && grad0.x < 0) || (grad.x > 0 && grad0.x > 0) || \
708    (grad.y < 0 && grad0.y < 0) || (grad.y > 0 && grad0.y > 0))) )
709
710-(BOOL)noEdgeOrGapBetweenLines:(VGraphic*)l1 :(VGraphic*)l2
711{   NSPoint	l1s, l1e, l2s, l2e, grad1, grad2;
712
713        [(VLine*)l1 getVertices:&l1s :&l1e];
714        grad1.x = l1e.x - l1s.x; grad1.y = l1e.y - l1s.y;
715        [(VLine*)l2 getVertices:&l2s :&l2e];
716        grad2.x = l2e.x - l2s.x; grad2.y = l2e.y - l2s.y;
717
718        if ( SqrDistPoints(l1e, l2s) < 5 && NNSameGradients(grad1, grad2) ) // NoEdgeGradients
719            return YES;
720        return NO;
721}
722
723-(BOOL)noEdgeOrGapBetweenGraphics:(VGraphic*)l1 :(VGraphic*)l2
724{   NSPoint	l1s, l1e, l2s, l2e, grad1, grad2, p1, p2, pm;
725
726    if ( [l1 isKindOfClass:[VLine class]] )
727    {   [(VLine*)l1 getVertices:&l1s :&l1e];
728        grad1.x = l1e.x - l1s.x; grad1.y = l1e.y - l1s.y;
729    }
730    else
731    {   [(VCurve*)l1 getVertices:&l1s :&p1 :&p2 :&l1e];
732        pm = CenterPoint(p1, p2);
733        grad1.x = l1e.x - pm.x; grad1.y = l1e.y - pm.y;
734    }
735
736    if ( [l2 isKindOfClass:[VLine class]] )
737    {   [(VLine*)l2 getVertices:&l2s :&l2e];
738        grad2.x = l2e.x - l2s.x; grad2.y = l2e.y - l2s.y;
739    }
740    else
741    {   [(VCurve*)l2 getVertices:&l2s :&p1 :&p2 :&l2e];
742        pm = CenterPoint(p1, p2);
743        grad2.x = pm.x - l2s.x; grad2.y = pm.y - l2s.y;
744    }
745    if ( SqrDistPoints(l1e, l2s) < TOLERANCE && SameGradients(grad1, grad2) )
746        return YES;
747    return NO;
748}
749
750- (void)uniteCurvesToLines:(VPath*)path :(int)w
751{   int			i, j, k, lineCnt=0, curveCnt=0;
752    NSPoint		ls, le, l1e, l2s, l2e, p1, p2;
753    VGraphic		*lineG, *l1, *l2;
754    NSMutableArray	*myList;
755    NSColor		*nxBlack = [NSColor colorWithCalibratedRed:0.0 green:0.0 blue:0.0 alpha:1.0];
756
757    myList = [[[NSMutableArray allocWithZone:[self zone]] init] autorelease];
758
759    if ( ![[path list] count] )
760        return;
761
762    /* collect curves (NO edge between!!!) and test if they are on a line
763     * remove curves and add line
764     */
765    for (i=0; i<(int)[[path list] count]; i++)
766    {	id	g1 = [[path list] objectAtIndex:i], g2;
767        NSPoint	s, e;
768        int	noEdge = 0, onlyThreeTimes = 0;
769
770        if ( i < (int)[[path list] count]-1 )
771     	{   g2 = [[path list] objectAtIndex:i+1];
772            noEdge = [self noEdgeOrGapBetweenGraphics:g1 :g2];
773        }
774        else
775        {   g2 = [[path list] objectAtIndex:i-1];
776            noEdge = [self noEdgeOrGapBetweenGraphics:g2 :g1];
777            if ( !noEdge && lineCnt > 3 )
778                [myList addObject:[[path list] objectAtIndex:i]];
779        }
780        if ( noEdge && i < (int)[[path list] count]-1 )
781        {   lineCnt++;
782            continue;
783        }
784        else if ( lineCnt <= 3 )
785        {   for (j=0; j<=lineCnt; j++)
786                [myList addObject:[[path list] objectAtIndex:i-j]];
787            if ( i == (int)[[path list] count]-2 )
788                [myList addObject:g2];
789            lineCnt=0;
790            continue;
791        }
792        /* set lineG */
793        l1=[[path list] objectAtIndex:i-lineCnt];
794        l2=[[path list] objectAtIndex:i];
795        if ( [l1 isKindOfClass:[VLine class]] )
796            [(VLine*)l1 getVertices:&ls :&l1e];
797        else
798            [(VCurve*)l1 getVertices:&ls :&p1 :&p2 :&l1e];
799
800        if ( [l2 isKindOfClass:[VLine class]] )
801            [(VLine*)l2 getVertices:&l2s :&le];
802        else
803            [(VCurve*)l2 getVertices:&l2s :&p1 :&p2 :&le];
804        lineG = [VLine line];
805        [lineG setColor:nxBlack]; [lineG setWidth:0]; [lineG setSelected:NO];
806        [(VLine*)lineG setVertices:ls :le];
807        onlyThreeTimes = 0;
808
809        /* test curves */
810        for (j=i-lineCnt, k=0; k<lineCnt+1; k++, j++)
811        {   VGraphic	*lg=[[path list] objectAtIndex:j];
812            float	tol = 9.0;
813
814            if ( [lg isKindOfClass:[VLine class]] )
815            {   [(VLine*)lg getVertices:&s :&e];
816                if ( (sqrDistancePointLine(&ls, &le, &s) <= tol) && (sqrDistancePointLine(&ls, &le, &e) <= tol) )
817                    curveCnt++;
818                else if ( !curveCnt && onlyThreeTimes < 4 )
819                {   VGraphic	*lg=[[path list] objectAtIndex:i-lineCnt];
820                    [myList addObject:lg];
821                    /* correct lineG */
822                    lg = [[path list] objectAtIndex:i-lineCnt+1];
823                    [(VLine*)lg getVertices:&l2s :&l2e];
824                    [(VLine*)lineG setVertices:l2s :le];
825                    lineCnt --; k = -1;
826                    onlyThreeTimes++;
827                }
828                else
829                    break;
830            }
831            else
832            {   [(VCurve*)lg getVertices:&s :&p1 :&p2 :&e];
833                if ( (sqrDistancePointLine(&ls, &le, &s) <= tol) && (sqrDistancePointLine(&ls, &le, &e) <= tol)
834                    && (sqrDistancePointLine(&ls, &le, &p1) <= tol) && (sqrDistancePointLine(&ls, &le, &p2) <= tol) )
835                    curveCnt++;
836                else if ( !curveCnt && onlyThreeTimes < 4 )
837                {   VGraphic	*lg=[[path list] objectAtIndex:i-lineCnt];
838                    [myList addObject:lg];
839                    /* correct lineG */
840                    lg = [[path list] objectAtIndex:i-lineCnt+1];
841                    [(VCurve*)lg getVertices:&l2s :&p1 :&p2 :&l2e];
842                    [(VLine*)lineG setVertices:l2s :le];
843                    lineCnt --; k = -1;
844                    onlyThreeTimes++;
845                }
846                else
847                    break;
848            }
849        }
850        /* build line from curves (curveCnt) */
851        if ( curveCnt > 1 )
852        {
853            if ( curveCnt < lineCnt )
854            {
855                g2=[[path list] objectAtIndex:i-lineCnt+curveCnt];
856                if ( [g2 isKindOfClass:[VLine class]] )
857                    [(VLine*)g2 getVertices:&l2s :&l2e];
858                else
859                    [(VCurve*)g2 getVertices:&l2s :&p1 :&p2 :&l2e];
860                [(VLine*)lineG setVertices:ls :l2e];
861            }
862            [myList addObject:lineG];
863
864            if ( curveCnt < lineCnt )
865            {   for (j=i-lineCnt+curveCnt+1, k=curveCnt; k<lineCnt; k++, j++)
866                {   VGraphic	*lg=[[path list] objectAtIndex:j];
867                    [myList addObject:lg];
868                }
869            }
870        }
871        else
872        {
873            for (j=i-lineCnt, k=0; k<lineCnt+1; k++, j++)
874            {   VGraphic	*lg=[[path list] objectAtIndex:j];
875                [myList addObject:lg];
876            }
877        }
878        lineCnt=0;
879        curveCnt=0;
880    }
881    /* list to path */
882    [path setList:myList]; /* optimize list also */
883}
884
885-(BOOL)noEdgeOrGapBetweenCurves:(VGraphic*)l1 :(VGraphic*)l2
886{   NSPoint	l1s, l1e, l2s, l2e, grad1, grad2, p1, p2;
887
888    [(VCurve*)l1 getVertices:&l1s :&p1 :&p2 :&l1e];
889    grad1.x = l1e.x - p2.x; grad1.y = l1e.y - p2.y;
890
891    [(VCurve*)l2 getVertices:&l2s :&p1 :&p2 :&l2e];
892    grad2.x = p1.x - l2s.x; grad2.y = p1.y - l2s.y;
893
894    if ( SqrDistPoints(l1e, l2s) < TOLERANCE && SameGradients(grad1, grad2) )
895        return YES;
896    return NO;
897}
898
899/* never used ?
900 */
901- (void)unite3CurvesTo1Curve:(VPath*)path
902{   int			i, j, k, lineCnt=0;
903    NSMutableArray	*myList;
904
905    myList = [[[NSMutableArray allocWithZone:[self zone]] init] autorelease];
906
907    if ( ![[path list] count] )
908        return;
909
910    /* collect curves (NO edge between!!!) and test if they are on a line
911     * remove curves and add line
912     */
913    for (i=0; i<(int)[[path list] count]; i++)
914    {	id	g1 = [[path list] objectAtIndex:i], g2;
915        int	noEdge = 0;
916
917        if ( i < (int)[[path list] count]-1 )
918     	{   g2 = [[path list] objectAtIndex:i+1];
919            if ( [g1 isKindOfClass:[VCurve class]] && [g2 isKindOfClass:[VCurve class]] )
920                noEdge = [self noEdgeOrGapBetweenCurves:g1 :g2];
921            else noEdge = 0;
922        }
923        else
924        {   g2 = [[path list] objectAtIndex:i-1];
925            if ( [g1 isKindOfClass:[VCurve class]] && [g2 isKindOfClass:[VCurve class]] )
926                noEdge = [self noEdgeOrGapBetweenCurves:g2 :g1];
927            else noEdge = 0;
928            if ( !noEdge && lineCnt > 3 )
929                [myList addObject:[[path list] objectAtIndex:i]];
930        }
931        if ( noEdge && i < (int)[[path list] count]-1 )
932        {   lineCnt++;
933            continue;
934        }
935        else if ( lineCnt <= 3 )
936        {   for (j=0; j<=lineCnt; j++)
937                [myList addObject:[[path list] objectAtIndex:i-j]];
938            if ( i == (int)[[path list] count]-2 )
939                [myList addObject:g2];
940            lineCnt=0;
941            continue;
942        }
943        /* set lineG */
944
945        /* unite curves - allways three */
946//        for (j=i-lineCnt, k=0; k<lineCnt+1; k+=3, j++)
947        for (j=i-lineCnt, k=0; k<lineCnt+1-2; k+=3, j+=3)
948        {   VGraphic    *c1 = [[path list] objectAtIndex:j];
949            VGraphic    *c2 = [[path list] objectAtIndex:j+1];
950            VGraphic    *c3 = [[path list] objectAtIndex:j+2];
951            NSPoint     s1, c1p1, c1p2, e1, s2, c2p1, c2p2, e2, s3, c3p1, c3p2, e3;
952
953            [(VCurve*)c1 getVertices:&s1 :&c1p1 :&c1p2 :&e1];
954            [(VCurve*)c2 getVertices:&s2 :&c2p1 :&c2p2 :&e2];
955            [(VCurve*)c3 getVertices:&s3 :&c3p1 :&c3p2 :&e3];
956            [(VCurve*)c1 calcVerticesFromPoints:s1 :e1 :e2 :e3];
957            [myList addObject:c1];
958        }
959        for ( ; k<lineCnt+1; k++, j++ ) // FIXME: is it correct to start at j ?
960        {   VGraphic	*lg = [[path list] objectAtIndex:j];
961            [myList addObject:lg];
962        }
963        lineCnt = 0;
964    }
965    /* list to path */
966    [path setList:myList]; /* optimize list also */
967}
968
969- (void)uniteLinesWithSameGradient2:(VPath*)path :(int)w
970{   int		i, j, k, lineCnt=0;
971    NSPoint	s1, e1, s2, e2, grad1, grad2;
972
973    if ( ![[path list] count] )
974        return;
975
976    // unite realy vertical lines !
977    for (i=0; i<(int)[[path list] count]-1; i++)
978    {	VGraphic	*l1=[[path list] objectAtIndex:i];
979        VGraphic	*l2=[[path list] objectAtIndex:i+1];
980
981        [(VLine*)l1 getVertices:&s1 :&e1];
982        [(VLine*)l2 getVertices:&s2 :&e2];
983        if ( e1.x == s1.x && e2.x == s2.x && e1.x == s2.x && e1.y == s2.y )
984        {
985            [(VLine*)l1 setVertices:s1 :e2]; /* l1 go now until l2 end */
986            [[path list] removeObjectAtIndex:i+1]; /*[l2 release];*/
987            i--;
988        }
989    }
990
991    for (i=0; i<(int)[[path list] count]; i++)
992    {	id	g1 = [[path list] objectAtIndex:i], g2;
993        int	noEdge = 0;
994
995        if ( i < (int)[[path list] count]-1 )
996     	{   g2 = [[path list] objectAtIndex:i+1];
997            [(VLine*)g1 getVertices:&s1 :&e1];
998            grad1.x = e1.x - s1.x; grad1.y = e1.y - s1.y;
999            [(VLine*)g2 getVertices:&s2 :&e2];
1000            grad2.x = e2.x - s2.x; grad2.y = e2.y - s2.y;
1001            if ( [self noEdgeOrGapBetweenLines:g1 :g2] && NearlySameGradients(grad1, grad2) )
1002                noEdge = 1.0;
1003            else
1004                noEdge = 0.0;
1005        }
1006        else
1007        {   g2 = [[path list] objectAtIndex:i-1];
1008            [(VLine*)g1 getVertices:&s1 :&e1];
1009            grad1.x = e1.x - s1.x; grad1.y = e1.y - s1.y;
1010            [(VLine*)g2 getVertices:&s2 :&e2];
1011            grad2.x = e2.x - s2.x; grad2.y = e2.y - s2.y;
1012            if ( [self noEdgeOrGapBetweenLines:g2 :g1] && NearlySameGradients(grad1, grad2) )
1013                noEdge = 1.0;
1014            else
1015                noEdge = 0.0;
1016        }
1017        if ( noEdge && i < (int)[[path list] count]-1 )
1018        {   lineCnt++;
1019            continue;
1020        }
1021        else if ( lineCnt <= 3 )
1022        {   lineCnt=0;
1023            continue;
1024        }
1025        /* unite lines - allways two */
1026        for (j=i-lineCnt, k=0; k<lineCnt+1-1 && lineCnt > 3; k+=2, j++)
1027        {   VGraphic	*l1=[[path list] objectAtIndex:j];
1028            VGraphic	*l2=[[path list] objectAtIndex:j+1];
1029
1030            [(VLine*)l1 getVertices:&s1 :&e1];
1031            [(VLine*)l2 getVertices:&s2 :&e2];
1032            [(VLine*)l1 setVertices:s1 :e2]; /* l1 go now until l2 end */
1033            [[path list] removeObjectAtIndex:j+1];
1034            i--;
1035        }
1036        lineCnt = 0;
1037    }
1038}
1039
1040/* build from n f[] values (t[] are the distance between f[] values)
1041 * splineSize calcf[] interpolated values (x or y)
1042 */
1043void cubicSplineC(int n, double t[], double f[], int splineSize, double calcf[])
1044{   int i,j;
1045    double a[n], b[n], c[n], delta_t[n], D[n], m[n], k[n];
1046    double bh, dh, e, h, wt, dt;
1047
1048    for (i=1; i<n; i++)
1049    {
1050        delta_t[i] = t[i]-t[i-1];
1051        D[i] = (f[i]-f[i-1])/delta_t[i];
1052    }
1053    m[0] = delta_t[2];
1054    delta_t[0] = t[2]-t[0];
1055    h = delta_t[1];
1056    k[0] = ((h + 2*delta_t[0])*D[1]*delta_t[2]+h*h*D[2])/delta_t[0];
1057    for (i=1; i<(n-1); i++)
1058    {
1059        h = -delta_t[i+1]/m[i-1];
1060        k[i] = h*k[i-1]+3*(delta_t[i]*D[i+1]+delta_t[i+1]*D[i]);
1061        m[i] = h *delta_t[i-1] + 2* (delta_t[i] + delta_t[i+1]);
1062    }
1063    h = t[n-1]-t[n-3];
1064    dh = delta_t[n-1];
1065    k[n-1] = ((dh+h+h)*D[n-1]*delta_t[n-2] + dh*dh*D[n-2])/h;
1066    h = -h/m[n-2];
1067    m[n-1] = delta_t[n-2];
1068    m[n-1] = h*delta_t[n-2] + m[n-1];
1069    a[n-1] = (h*k[n-2]+k[n-1])/m[n-1];
1070    for (i=n-2; i>=0; i--)
1071        a[i] = (k[i]-delta_t[i]*a[i+1])/m[i];
1072    for (i=1; i<n; i++)
1073    {
1074        dh = D[i]; bh = delta_t[i];
1075        e = a[i-1]+a[i]-dh-dh;
1076        b[i-1] = 2*(dh-a[i-1]-e)/bh;
1077        c[i-1] = 6*e/(bh*bh);
1078    }
1079    wt = 0; j=0;
1080    dt = t[n-1]/(double)(splineSize-1);
1081    for (i=0; i<splineSize; i++)
1082    {
1083        while ( (t[j+1]<wt) && (j<splineSize) )
1084            j++;
1085        h = wt - t[j];
1086        calcf[i] = f[j]+h*(a[j]+h*(b[j]+h*c[j]/3)/2);
1087        wt = wt+dt;
1088    }
1089    calcf[splineSize-1] = f[n-1];
1090}
1091
1092-(void)addCurvesFromBSplineToList:(NSMutableArray*)listle :(int)cnt :(NSPoint*)bSplinePts
1093{   NSPoint	b[3*cnt+1];
1094    long	m, k;
1095    NSColor	*nxBlack=[NSColor colorWithCalibratedRed:0.0 green:0.0 blue:0.0 alpha:1.0];
1096
1097    m = cnt; // m = Anzahl der Gewichtspunkte der BSpline
1098    m--; // m Gewichtspunkte ergeben m-1 Polynome oder Kurvenzuege bzw Bezier-Kurven
1099
1100    b[0] = bSplinePts[0];
1101    b[3*m] = bSplinePts[m];
1102    // Bezierpunkte b[i] aus Gewichtspunkten berechnen
1103    for (k=1; k<=m; k++) /* calc all p1 of curves */
1104    {
1105        b[3*k-2].x = (2.0*bSplinePts[k-1].x + bSplinePts[k].x) / 3.0;
1106        b[3*k-2].y = (2.0*bSplinePts[k-1].y + bSplinePts[k].y) / 3.0;
1107    }
1108    for (k=1; k<=m-1; k++) /* calc p3 of curves */
1109    {
1110        b[3*k].x = (bSplinePts[k-1].x + 4.0*bSplinePts[k].x + bSplinePts[k+1].x) / 6.0;
1111        b[3*k].y = (bSplinePts[k-1].y + 4.0*bSplinePts[k].y + bSplinePts[k+1].y) / 6.0;
1112    }
1113    for (k=0; k<=m-1; k++) /* calc all p2 of curves */
1114    {
1115        b[3*k+2].x = (bSplinePts[k].x + 2.0*bSplinePts[k+1].x) / 3.0;
1116        b[3*k+2].y = (bSplinePts[k].y + 2.0*bSplinePts[k+1].y) / 3.0;
1117    }
1118    // jeweils Endpunkt der letzten VCurve als Anfangspunkt in die naechste Kurve uebernehmen!
1119    for (k=3; k<=3*m; k+=3)
1120    {	VGraphic	*curveG = [VCurve curve];
1121
1122        [curveG setColor:nxBlack];
1123        [curveG setWidth:0];
1124        [(VCurve*)curveG setVertices:b[k-3] :b[k-2] :b[k-1] :b[k]]; /* p0 p1 p2 p3 */
1125        [listle addObject:curveG];
1126    }
1127}
1128
1129- (void)linesToCurvesInPath:(VPath*)path :(int)w
1130{   int			i, j, k, lineCnt=0;
1131    NSPoint		ls, le;
1132    NSMutableArray	*myList;
1133
1134    if ( [[path list] count] < 2 )
1135        return;
1136
1137    myList = [[[NSMutableArray allocWithZone:[self zone]] init] autorelease];
1138
1139    /* unite lines with same gradients */
1140    [self uniteLinesWithSameGradient2:path :w];
1141//return;
1142
1143    if ( [[path list] count] < 2 )
1144        return;
1145
1146    /* build bSplines from lines and than curves from bSplines */
1147
1148    /* collect 3/4 lines (NO edge between!!!) and make a bSpline->curve from it
1149     * remove lines and add curves
1150     */
1151    for (i=0; i<(int)[[path list] count]; i++)
1152    {	id	g1 = [[path list] objectAtIndex:i], g2;
1153        int	noEdge = 0, sameLength = 0, len1, len2, addLastGraphic=0;
1154        NSPoint	s1, e1, s2, e2;
1155
1156        if ( i < (int)[[path list] count]-1 )
1157     	{   g2 = [[path list] objectAtIndex:i+1];
1158            noEdge = [self noEdgeOrGapBetweenLines:g1 :g2];
1159            [(VLine*)g1 getVertices:&s1 :&e1];
1160            [(VLine*)g2 getVertices:&s2 :&e2];
1161            len1 = SqrDistPoints(s1, e1);
1162            len2 = SqrDistPoints(s2, e2);
1163            ( Diff(len1, len2) <= 25 ) ? (sameLength = 1) : (sameLength = 0);
1164        }
1165        else
1166        {   g2 = [[path list] objectAtIndex:i-1];
1167            noEdge = [self noEdgeOrGapBetweenLines:g2 :g1];
1168            [(VLine*)g1 getVertices:&s1 :&e1];
1169            [(VLine*)g2 getVertices:&s2 :&e2];
1170            ( Diff(SqrDistPoints(s1, e1), SqrDistPoints(s2, e2)) <= 25 ) ? (sameLength = 1) : (sameLength = 0);
1171            if ( (!noEdge || !sameLength) && lineCnt >= 3 )
1172            {   addLastGraphic = 1; i--; } // lineCnt from previous i !!!!
1173//                [myList addObject:[[path list] objectAtIndex:i]];
1174        }
1175        if ( noEdge && sameLength && i < (int)[[path list] count]-1 ) // sameLength !!!
1176        {   lineCnt++;
1177            continue;
1178        }
1179        else if ( lineCnt < 3 )
1180//            for (j=0; j<=lineCnt; j++)
1181        {   for (j=lineCnt; j>=0; j--) // hold sort of list !!!
1182                [myList addObject:[[path list] objectAtIndex:i-j]];
1183            if ( i == (int)[[path list] count]-2 )
1184            {   [myList addObject:g2];
1185                break; // ende !!!
1186            }
1187            lineCnt=0;
1188            continue;
1189        }
1190
1191        /* if ( lineCnt > 3 ) */
1192        {   double	x[lineCnt+2], y[lineCnt+2], t[lineCnt+2]; /* x,y coordinates our linePts and t */
1193            double	ax, ay, dd;
1194            int	splineSize = (lineCnt+1.0 > 3) ? (lineCnt+1.0) : (4);
1195//            int	splineSize = (Even((lineCnt+1))) ? (lineCnt+2.0) : (lineCnt+1.0);
1196            NSPoint	bSplinePts[splineSize+1];
1197            double	calcfx[splineSize+1], calcfy[splineSize+1];
1198
1199            /* build spline through points */
1200//printf("\n%i", lineCnt);
1201            /* fill x,y value Arrays and calc t values - lineCnt+1 lines -> lineCnt + 2 pts
1202                  * with dist = 1/3*(dx+dy+2*max{dx,dy}) (euclid) */
1203            for (j=i-lineCnt, k=0; k<lineCnt+1; k++, j++)
1204            {   VGraphic	*lg=[[path list] objectAtIndex:j];
1205
1206                [(VLine*)lg getVertices:&ls :&le];
1207                x[k] = ls.x;
1208                y[k] = ls.y;
1209//printf("linePts:\t%.2f x\t%.2f y\n", ls.x, ls.y);
1210                if ( k == lineCnt ) /* last line we need also the end */
1211                {   x[k+1] = le.x;
1212                    y[k+1] = le.y;
1213//printf("linePts:\t%.2f x\t%.2f y\n", le.x, le.y);
1214                    break;
1215                }
1216            }
1217//printf("\n\n");
1218
1219            t[0] = 0.0;
1220            for (j=1; j<lineCnt+2; j++) /* we have lineCnt+1 lines -> lineCnt+2 t values to points */
1221            {   ax = Abs(x[j]-x[j-1]);
1222                ay = Abs(y[j]-y[j-1]);
1223                dd = ax + ay;
1224                if ( ax > ay ) dd = dd + 2.0*ax;
1225                else           dd = dd + 2.0*ay;
1226                t[j] = t[j-1] + dd/3.0;
1227            }
1228            /* calc interpolation values*/
1229            cubicSplineC(lineCnt+2, t, x, splineSize, calcfx);
1230            cubicSplineC(lineCnt+2, t, y, splineSize, calcfy);
1231            for (j=0; j<splineSize; j++)
1232            {   bSplinePts[j].x = calcfx[j];
1233                bSplinePts[j].y = calcfy[j];
1234//printf("splinePts:\t%.2f x\t%.2f y\n", bSplinePts[j].x, bSplinePts[j].y);
1235if ( calcfx[j] < 0 || calcfy[j] < 0 )
1236    printf("oh no 2\n");
1237            }
1238//printf("\n");
1239            /* build curves from bSpline */
1240            [self addCurvesFromBSplineToList:myList :splineSize :bSplinePts];
1241            if ( addLastGraphic )
1242            {   [myList addObject:[[path list] objectAtIndex:(int)[[path list] count]-1]]; // to hold sort of list
1243                i++; // correct i !
1244            }
1245            lineCnt = 0;
1246        }
1247    }
1248    /* list to path */
1249    [path setList:myList]; /* optimize list also */
1250}
1251
1252
1253
1254- (float)distanceParallelLines:(VLine*)l1 :(VLine*)l2 :(int)fillDist
1255{   NSPoint	l1S, l1E, l2S, l2E;
1256    float	xDistS, xDistE, yDist, dist, d1, d2;
1257
1258    [l1 getVertices:&l1S :&l1E];
1259    [l2 getVertices:&l2S :&l2E];
1260
1261    xDistS = Diff(l1E.x, l2S.x);
1262    xDistE = Diff(l1E.x, l2E.x);
1263    yDist = Diff(l1E.y, l2S.y);
1264
1265    if ( Diff(yDist, fillDist) < TOLERANCE && (xDistS < 5 || xDistE < 5) )
1266    {
1267        if ( xDistE < 5 )
1268            [l2 setVertices:l2E :l2S]; /* change direction */
1269        dist = 0;
1270    }
1271    else
1272    {   if ( (d1=SqrDistPoints(l1E, l2S)) < (d2=SqrDistPoints(l1E, l2E)) )
1273            dist = d1;
1274        else
1275        {   [l2 setVertices:l2E :l2S]; /* change direction */
1276            dist = d2;
1277        }
1278    }
1279    return dist;
1280}
1281#if 0
1282- (void)uniteLinesWithSameGradient:(VPath*)path :(int)w
1283{   int		i, j, k, m, uniteUntil = 0;
1284    NSPoint	l1S, l1E, l2S, l2E, l3S, l3E, mPts[1000], tp; // FIX ME - malloc points
1285    float	maxDiff = 0.25, sqrDist = 10, maxLen = (w+1)*(w+1); // maxDiff was 0.35 mit mPts;
1286
1287    if ( ![[path list] count] )
1288        return;
1289//return;
1290    /* unite short lines all other */
1291    for (i=0; i<(int)[[path list] count]-1; i++)
1292    {	VGraphic	*l1=[[path list] objectAtIndex:i];
1293        VGraphic	*l2=[[path list] objectAtIndex:i+1];
1294        NSPoint		lastEndPt;
1295        float		d1, d2, d3, dl1, dl2, dl3, angleDiff = 15, angle1, angle2, lastAngle=0;
1296        int		mCnt = 0;
1297        BOOL		curveAhead = NO;
1298
1299        [(VLine*)l1 getVertices:&l1S :&l1E];
1300        [(VLine*)l2 getVertices:&l2S :&l2E];
1301//        mPts[mCnt++] = CenterPoint(l1S, l1E);
1302        mPts[mCnt++] = l1E;
1303//        mPts[mCnt++] = CenterPoint(l2S, l2E);
1304        mPts[mCnt++] = l2S;
1305        dl1 = SqrDistPoints(l1S, l1E);
1306        dl2 = SqrDistPoints(l2S, l2E);
1307        sqrDist = SqrDistPoints(l1E, l2S);
1308        lastEndPt = l2E;
1309
1310if (mCnt > 999)
1311    NSLog(@"PathContour.m: -uniteLinesWith... mPts Ueberlauf");
1312
1313        if ( sqrDist > 5 || (l1S.y == l1E.y && Diff(l1S.x, l1E.x) > w*2.0) || /*dl1 > maxLen ||*/
1314             (d1 = pointOnLineClosestToPoint(l1S, l2E, mPts[mCnt-1], &tp)) > maxDiff )
1315            continue;
1316        if ( /*dl2 > maxLen ||*/ (l2S.y == l2E.y && Diff(l2S.x, l2E.x) > w*2.0) ||
1317             (d2 = pointOnLineClosestToPoint(l1S, l2E, mPts[mCnt-1], &tp)) > maxDiff )
1318            continue;
1319
1320        angle1 = [(VLine*)l1 angle];
1321        lastAngle = angle2 = [(VLine*)l2 angle];
1322        if ( Diff(angle1, angle2) > angleDiff && Diff(Diff(angle1, angle2), 360.0) > angleDiff )
1323            continue;
1324
1325        for (j=i+2 ;j<(int)[[path list] count]; j++)
1326        {   VGraphic	*l3=[[path list] objectAtIndex:j];
1327            float	angle3;
1328
1329            [(VLine*)l3 getVertices:&l3S :&l3E];
1330//            mPts[mCnt++] = CenterPoint(l3S, l3E);
1331            mPts[mCnt++] = l3S;
1332
1333            dl3 = SqrDistPoints(l3S, l3E);
1334            sqrDist = SqrDistPoints(lastEndPt, l3S);
1335            lastEndPt = l3E;
1336
1337            angle3 = [(VLine*)l3 angle];
1338            if ( (Diff(lastAngle, angle3) > angleDiff && Diff(Diff(lastAngle, angle3), 360.0) > angleDiff) ||
1339                 (l3S.y == l3E.y && Diff(l3S.x, l3E.x) > w*2.0) )
1340            {   curveAhead = YES;
1341                uniteUntil = j - 1;
1342                break;
1343            }
1344            lastAngle = angle3;
1345
1346            /* check all mPts start at end */
1347            for (m=mCnt-1; m >= 0; m--)
1348            {
1349                if ( (Diff(lastAngle, angle3) > angleDiff && Diff(Diff(lastAngle, angle3), 360.0) > angleDiff) ||
1350                          /*dl3 > maxLen ||*/ sqrDist > 5 ||
1351                          (d3 = pointOnLineClosestToPoint(l1S, l3E, mPts[m], &tp)) > maxDiff )
1352                {
1353                    curveAhead = YES;
1354                    uniteUntil = j - 1; // j - (mCnt - ((!m) ? (1):(m)));
1355                    break;
1356                }
1357            }
1358            if ( curveAhead )
1359            {
1360                break;
1361            }
1362       }
1363
1364        if ( !curveAhead )
1365            uniteUntil = [[path list] count]-1;
1366        /* unite lines until j-(mCnt-m) ????????? */
1367        if ( Diff(uniteUntil, i) >= 1 )
1368        {   VGraphic	*uline=[[path list] objectAtIndex:uniteUntil];
1369
1370            [(VLine*)uline getVertices:&l3S :&l3E];
1371            [(VLine*)l1 setVertices:l1S :l3E];
1372            for (k=uniteUntil; k > i; k--)
1373            {
1374                if ( k < [[path list] count] )
1375                    [[path list] removeObjectAtIndex:k];
1376                else
1377                    NSLog(@"falscher index");
1378            }
1379        }
1380    }
1381}
1382#endif
1383#if 0
1384- (void)uniteLinesWithSameGradient:(VPath*)path :(int)w
1385{   int		i, j, k, curveI=-1;
1386    NSPoint	l1S, l1E, l2S, l2E, l3S, l3E, l4S, l4E;
1387    float	angleDiff = 6.0, angleD1 = 0.01, angleD2 = 0.02;
1388    BOOL	curveAhead = NO;
1389
1390    if ( ![[path list] count] )
1391        return;
1392
1393    for (i=0; i<(int)[[path list] count]-1; i++)
1394    {	VGraphic	*l1=[[path list] objectAtIndex:i];
1395        VGraphic	*l2=[[path list] objectAtIndex:i+1];
1396        float		angle1, angle2, aVals[10];
1397        int		aCnt = 0;
1398
1399        [(VLine*)l1 getVertices:&l1S :&l1E];
1400        [(VLine*)l2 getVertices:&l2S :&l2E];
1401        angle1 = [(VLine*)l1 angle];
1402        angle2 = [(VLine*)l2 angle];
1403        aVals[aCnt++] = angle1;
1404
1405        if ( curveAhead == YES && i <= curveI && l1E.x == l2S.x && l1E.y == l2S.y &&
1406             (Diff(angle1, angle2) < angleD1 || Diff(Diff(angle1, angle2), 360.0) < angleD1) )
1407        {
1408            [(VLine*)l1 setVertices:l1S :l2E]; /* l1 go now until l2 end */
1409            [[path list] removeObjectAtIndex:i+1];
1410            i--;
1411            continue;
1412        }
1413        else if ( curveAhead == YES && i <= curveI )
1414            continue;
1415        else if ( curveAhead == YES )
1416        {   curveAhead = NO;
1417            curveI = -1;
1418        }
1419
1420        if ( Diff(angle1, angle2) > angleD2 && Diff(Diff(angle1, angle2), 360.0) > angleD2 )
1421            aVals[aCnt++] = angle2;
1422        if ( l1E.x == l2S.x && l1E.y == l2S.y &&
1423             (Diff(angle1, angle2) < angleDiff || Diff(Diff(angle1, angle2), 360.0) < angleDiff) )
1424        {
1425            for (j=i+1 ;j<(int)[[path list] count]-1; j++)
1426            {	VGraphic	*l3=[[path list] objectAtIndex:j];
1427                VGraphic	*l4=[[path list] objectAtIndex:j+1];
1428                float		angle3, angle4;
1429
1430                [(VLine*)l3 getVertices:&l3S :&l3E];
1431                [(VLine*)l4 getVertices:&l4S :&l4E];
1432                angle3 = [(VLine*)l3 angle];
1433                angle4 = [(VLine*)l4 angle];
1434                if ( l3E.x == l4S.x && l3E.y == l4S.y &&
1435                     (Diff(angle3, angle4) < angleDiff || Diff(Diff(angle3, angle4), 360.0) < angleDiff) )
1436                {
1437                    if ( Diff(aVals[0], angle4) > angleD2 && Diff(Diff(aVals[0], angle4), 360.0) > angleD2 )
1438                    {
1439                        /* new different Angle */
1440                        if ( aCnt > 1 &&
1441                             Diff(aVals[1], angle4) > angleD2 && Diff(Diff(aVals[1], angle4), 360.0) > angleD2 )
1442                        {
1443//                            if ( aCnt > 2 &&
1444//                                 ((Diff(aVals[2], angle4) > angleD2 &&
1445//                                 Diff(Diff(aVals[2], angle4), 360.0) > angleD2) ||
1446//                                 ( Diff(j, i) < 9 )) )
1447                            {
1448                                /* aCnt ist 3 ist maximum - bis hier uniten */
1449                                if ( Diff(j, i) >= 9 )
1450                                {
1451                                    [(VLine*)l1 setVertices:l1S :l3E];
1452                                    for (k=j; k > i; k--)
1453                                        [[path list] removeObjectAtIndex:k];
1454
1455                                    aCnt = 10.0; // so we do not unite until end
1456                                    break;
1457                                }
1458                                /* 4. different Value OR 3 inside 8 lines - curve ahead - no line */
1459                                curveAhead = YES;
1460                                curveI = j;
1461                                break;
1462                            }
1463/*                            else if ( aCnt == 2 )
1464                            {   aVals[aCnt++] = angle4;
1465                                continue;
1466                            }
1467                            else
1468                                continue;
1469*/
1470                        }
1471                        else if ( aCnt == 1 )
1472                        {   aVals[aCnt++] = angle4;
1473                            continue;
1474                        }
1475                        else
1476                            continue;
1477                    }
1478                    else
1479                        continue;
1480                }
1481                /* unite all lines until j,  if less / or 3 values */
1482                else if ( (aCnt < 3 && Diff(j, i) > 6) || (aCnt < 4 && Diff(j, i) >= 9) )
1483                {   VLine	*lj = [[path list] objectAtIndex:j];
1484                    NSPoint	lje = [lj pointWithNum:MAXINT];
1485
1486                    [(VLine*)l1 setVertices:l1S :lje];
1487                    for (k=j; k > i; k--)
1488                        [[path list] removeObjectAtIndex:k];
1489
1490                    aCnt = 10.0; // so we do not unite until end
1491                    break;
1492                }
1493                else /* else unite only with an angleDiff of angleD1 */
1494                {
1495                    /* 4. different Value OR 3 inside 8 lines - curve ahead - no line */
1496                    curveAhead = YES;
1497                    curveI = j;
1498                    break;
1499                }
1500            }
1501            /* unite all lines until list end,  if less / or 3 values */
1502            if ( curveAhead == NO &&
1503                 ((aCnt < 3 && Diff([[path list] count], i) > 6) ||
1504                  (aCnt < 4 && Diff([[path list] count], i) >= 9)) )
1505            {	VLine	*ll = [[path list] objectAtIndex:[[path list] count]-1];
1506                NSPoint	lle = [ll pointWithNum:MAXINT];
1507
1508                [(VLine*)l1 setVertices:l1S :lle];
1509                for (j=[[path list] count]-1; j > i; j--)
1510                    [[path list] removeObjectAtIndex:j];
1511
1512                return;
1513            }
1514            /* unite l1 and l2 if angle diff smaller angleD1 */
1515            else if ( curveAhead == YES &&
1516                      (Diff(angle1, angle2) < angleD1 || Diff(Diff(angle1, angle2), 360.0) < angleD1) )
1517            {
1518                [(VLine*)l1 setVertices:l1S :l2E]; /* l1 go now until l2 end */
1519                [[path list] removeObjectAtIndex:i+1];
1520                i--;
1521            }
1522        }
1523    }
1524}
1525#endif
1526
1527// OLD
1528- (void)uniteLinesWithSameGradient:(VPath*)path :(int)w
1529{   int		i, sqrDist=(w/2.0)*(w/2.0);
1530    NSPoint	grad1, grad2; // grad3;
1531    NSPoint	l1S, l1E, l2S, l2E; //, l3S, l3E;
1532
1533    if ( ![[path list] count] )
1534        return;
1535
1536    // unite realy vertical lines !
1537    for (i=0; i<(int)[[path list] count]-1; i++)
1538    {	VGraphic	*l1=[[path list] objectAtIndex:i];
1539        VGraphic	*l2=[[path list] objectAtIndex:i+1];
1540
1541        [(VLine*)l1 getVertices:&l1S :&l1E];
1542        [(VLine*)l2 getVertices:&l2S :&l2E];
1543        if ( l1E.x == l1S.x && l2E.x == l2S.x && l1E.x == l2S.x && l1E.y == l2S.y )
1544        {
1545            [(VLine*)l1 setVertices:l1S :l2E]; /* l1 go now until l2 end */
1546            [[path list] removeObjectAtIndex:i+1]; /*[l2 release];*/
1547            i--;
1548        }
1549    }
1550
1551    for (i=0; i<(int)[[path list] count]-1; i++)
1552    {	VGraphic	*l1=[[path list] objectAtIndex:i];
1553        VGraphic	*l2=[[path list] objectAtIndex:i+1];
1554
1555        [(VLine*)l1 getVertices:&l1S :&l1E];
1556        [(VLine*)l2 getVertices:&l2S :&l2E];
1557        grad1.x = l1E.x - l1S.x; grad1.y = l1E.y - l1S.y;
1558        grad2.x = l2E.x - l2S.x; grad2.y = l2E.y - l2S.y;
1559        if ( l1E.x == l2S.x && l1E.y == l2S.y && SameGradients(grad1, grad2) && SqrDistPoints(l2S, l2E) < sqrDist && SqrDistPoints(l1S, l1E) < sqrDist )
1560        {
1561            [(VLine*)l1 setVertices:l1S :l2E]; /* l1 go now until l2 end */
1562            [[path list] removeObjectAtIndex:i+1]; /*[l2 release];*/
1563            i--;
1564        }
1565    }
1566#if 0
1567    for (i=0; i<(int)[[path list] count]-2; i++)
1568    {	VGraphic	*l1=[[path list] objectAtIndex:i];
1569        VGraphic	*l2=[[path list] objectAtIndex:i+1];
1570        VGraphic	*l3=[[path list] objectAtIndex:i+2];
1571
1572        [(VLine*)l1 getVertices:&l1S :&l1E];
1573        [(VLine*)l2 getVertices:&l2S :&l2E];
1574        [(VLine*)l3 getVertices:&l3S :&l3E];
1575        grad1.x = l1E.x - l1S.x; grad1.y = l1E.y - l1S.y;
1576        grad2.x = l2E.x - l2S.x; grad2.y = l2E.y - l2S.y;
1577        grad3.x = l3E.x - l3S.x; grad3.y = l3E.y - l3S.y;
1578        if ( l1E.x == l2S.x && l1E.y == l2S.y && l2E.x == l3S.x && l2E.y == l3S.y && SameGradients(grad1, grad2) && SameGradients(grad2, grad3) && SameGradients(grad1, grad3) && SqrDistPoints(l2S, l2E) < sqrDist && SqrDistPoints(l1S, l1E) < sqrDist
1579             /*&& (SameGradients(grad1, grad2) || SameGradients(grad3, grad2))*/ )
1580        {
1581            [(VLine*)l1 setVertices:l1S :l3E]; /* l1 go now until l3 end */
1582            [[path list] removeObjectAtIndex:i+2]; /*[l3 release];*/
1583            [[path list] removeObjectAtIndex:i+1]; /*[l2 release];*/
1584            i--;
1585        }
1586    }
1587#endif
1588    return;
1589}
1590
1591#if 0
1592- (void)smoothenLinesInPath:(VPath*)path :(int)w
1593{   int		i, j, k, lineCnt=0;
1594    NSPoint	s1, e1, s2, e2, mPrev;
1595    float	angle1, angle2, angleDiff1 = 13.0, angleDiff2 = 5.0, angleDiffE = 27.0;
1596    float	curAngleDiff = angleDiff1, aDiff = 0.0, sqrDist = 0.0, firstA = -1.0;
1597
1598    if ( [[path list] count] < 2 )
1599        return;
1600
1601    for (i=0; i<(int)[[path list] count]; i++)
1602    {	id	g1 = [[path list] objectAtIndex:i], g2;
1603        int	noEdge = 0;
1604
1605        if ( i < (int)[[path list] count]-1 )
1606     	{   g2 = [[path list] objectAtIndex:i+1];
1607            [(VLine*)g1 getVertices:&s1 :&e1];
1608            [(VLine*)g2 getVertices:&s2 :&e2];
1609            angle1 = [(VLine*)g1 angle];
1610            angle2 = [(VLine*)g2 angle];
1611            aDiff = Diff(angle1, angle2);
1612            sqrDist = SqrDistPoints(e1, s2);
1613            /* angleDiff < 0-7 */
1614            if ( (s1.y == e1.y && Diff(s1.x, e1.x) > w) || (s2.y == e2.y && Diff(s2.x, e2.x) > w) )
1615            {   noEdge = 0.0;
1616                curAngleDiff = angleDiffE;
1617            }
1618            else if (sqrDist < 5 && (aDiff < angleDiff1 || Diff(aDiff, 360.0) < angleDiff1))
1619            {
1620                if (curAngleDiff == angleDiff1 || curAngleDiff == angleDiffE)
1621                {   noEdge = 1.0;
1622                    curAngleDiff = angleDiff1;
1623                    if (!lineCnt)
1624                        firstA = angle1;
1625                }
1626                else if (curAngleDiff == angleDiff2 && // angleDiff < 5-7
1627                         aDiff > angleDiff2 && Diff(aDiff, 360.0) > angleDiff2)
1628                    noEdge = 1.0;
1629                else
1630                {   noEdge = 0.0;
1631                    curAngleDiff = angleDiff1;
1632                }
1633            }
1634            /* angleDiff < 8-20 */
1635            else if (sqrDist < 5 && (aDiff < angleDiffE || Diff(aDiff, 360.0) < angleDiffE))
1636            {
1637                if (curAngleDiff == angleDiff2)
1638                {   noEdge = 1.0;
1639                    if (!lineCnt)
1640                        firstA = angle1;
1641                }
1642                else
1643                {   noEdge = 0.0;
1644                    curAngleDiff = angleDiff2;
1645                }
1646            }
1647            /* angleDiff > 20 */
1648            else
1649            {   noEdge = 0.0;
1650                curAngleDiff = angleDiffE;
1651            }
1652        }
1653        else
1654        {   g2 = [[path list] objectAtIndex:i-1];
1655            [(VLine*)g1 getVertices:&s1 :&e1];
1656            [(VLine*)g2 getVertices:&s2 :&e2];
1657            angle1 = [(VLine*)g1 angle];
1658            angle2 = [(VLine*)g2 angle];
1659            aDiff = Diff(angle1, angle2);
1660            sqrDist = SqrDistPoints(e2, s1);
1661            /* angleDiff < 0-7 */
1662            if ( (s1.y == e1.y && Diff(s1.x, e1.x) > w) || (s2.y == e2.y && Diff(s2.x, e2.x) > w) )
1663            {   noEdge = 0.0;
1664                curAngleDiff = angleDiffE;
1665            }
1666            else if (sqrDist < 5 && (aDiff < angleDiff1 || Diff(aDiff, 360.0) < angleDiff1))
1667            {
1668                if (curAngleDiff == angleDiff1 || curAngleDiff == angleDiffE)
1669                {   noEdge = 1.0;
1670                    curAngleDiff = angleDiff1;
1671                    if (!lineCnt)
1672                        firstA = angle1;
1673                }
1674                else if (curAngleDiff == angleDiff2 && // angleDiff < 5-7
1675                         aDiff > angleDiff2 && Diff(aDiff, 360.0) > angleDiff2)
1676                    noEdge = 1.0;
1677                else
1678                {   noEdge = 0.0;
1679                    curAngleDiff = angleDiff1;
1680                }
1681            }
1682            /* angleDiff < 8-20 */
1683            else if (sqrDist < 5 && (aDiff < angleDiffE || Diff(aDiff, 360.0) < angleDiffE))
1684            {
1685                if (curAngleDiff == angleDiff2)
1686                    noEdge = 1.0;
1687                else
1688                {   noEdge = 0.0;
1689                    curAngleDiff = angleDiff2;
1690                }
1691            }
1692            /* angleDiff > 20 */
1693            else
1694            {   noEdge = 0.0;
1695                curAngleDiff = angleDiffE;
1696            }
1697        }
1698        if ( noEdge && i < (int)[[path list] count]-1 )
1699        {   lineCnt++;
1700            continue;
1701        }
1702        else if ( lineCnt <= 3 ) /*|| Diff(firstA, angle1) > angleDiff1*/
1703        {   lineCnt=0;
1704            continue;
1705        }
1706        mPrev.x = mPrev.y = -1;
1707        /* smoothen lines - allways ??? */
1708        for (j=i-lineCnt, k=0; k<lineCnt+1-1 && lineCnt > 3; k+=2, j+=2)
1709        {   VGraphic	*l1=[[path list] objectAtIndex:j];
1710            VGraphic	*l2=[[path list] objectAtIndex:j+1];
1711            NSPoint	m1, m2;
1712
1713            [(VLine*)l1 getVertices:&s1 :&e1];
1714            [(VLine*)l2 getVertices:&s2 :&e2];
1715            m1 = CenterPoint(s1, e1);
1716            m2 = CenterPoint(s2, e2);
1717            if ( mPrev.x == -1 && mPrev.y == -1 ) // first
1718                [(VLine*)l1 setVertices:s1 :m1];
1719            else
1720                [(VLine*)l1 setVertices:mPrev :m1];
1721            [(VLine*)l2 setVertices:m1 :m2];
1722            mPrev = m2;
1723            if ( k >= lineCnt+1-3 ) // last
1724            {	VGraphic	*lineG=[VLine line];
1725                NSColor	*nxBlack = [NSColor colorWithCalibratedRed:0.0 green:0.0 blue:0.0 alpha:1.0];
1726                [lineG setColor:nxBlack]; [lineG setWidth:0]; [lineG setSelected:NO];
1727
1728                if ( j+2 == lineCnt )
1729                {   VGraphic	*l3=[[path list] objectAtIndex:j+2];
1730                    NSPoint	s3, e3, m3;
1731
1732                    [(VLine*)l3 getVertices:&s3 :&e3];
1733                    m3 = CenterPoint(s3, e3);
1734                    [(VLine*)l3 setVertices:m2 :m3];
1735                    [(VLine*)lineG setVertices:m3 :e3];
1736                    [[path list] insertObject:lineG atIndex:j+3];
1737                }
1738                else
1739                {   [(VLine*)lineG setVertices:m2 :e2];
1740                    [[path list] insertObject:lineG atIndex:j+2];
1741                }
1742                i++;
1743                lineCnt++; // one line more !!!
1744            }
1745        }
1746        /* smoothen lines - allways ------------- second time */
1747        mPrev.x = mPrev.y = -1;
1748        for (j=i-lineCnt, k=0; k<lineCnt+1-1 && lineCnt > 3; k+=2, j+=2)
1749        {   VGraphic	*l1=[[path list] objectAtIndex:j];
1750            VGraphic	*l2=[[path list] objectAtIndex:j+1];
1751            NSPoint	m1, m2;
1752
1753            [(VLine*)l1 getVertices:&s1 :&e1];
1754            [(VLine*)l2 getVertices:&s2 :&e2];
1755            m1 = CenterPoint(s1, e1);
1756            m2 = CenterPoint(s2, e2);
1757            if ( mPrev.x == -1 && mPrev.y == -1 ) // first
1758                [(VLine*)l1 setVertices:s1 :m1];
1759            else
1760                [(VLine*)l1 setVertices:mPrev :m1];
1761            [(VLine*)l2 setVertices:m1 :m2];
1762            mPrev = m2;
1763            if ( k >= lineCnt+1-3 ) // last
1764            {	VGraphic	*lineG=[VLine line];
1765                NSColor	*nxBlack = [NSColor colorWithCalibratedRed:0.0 green:0.0 blue:0.0 alpha:1.0];
1766                [lineG setColor:nxBlack]; [lineG setWidth:0]; [lineG setSelected:NO];
1767
1768                if ( j+2 == lineCnt )
1769                {   VGraphic	*l3=[[path list] objectAtIndex:j+2];
1770                    NSPoint	s3, e3, m3;
1771
1772                    [(VLine*)l3 getVertices:&s3 :&e3];
1773                    m3 = CenterPoint(s3, e3);
1774                    [(VLine*)l3 setVertices:m2 :m3];
1775                    [(VLine*)lineG setVertices:m3 :e3];
1776                    [[path list] insertObject:lineG atIndex:j+3];
1777                }
1778                else
1779                {   [(VLine*)lineG setVertices:m2 :e2];
1780                    [[path list] insertObject:lineG atIndex:j+2];
1781                }
1782                i++;
1783            }
1784        }
1785#if 0
1786        if ( Diff(firstA, angle1) < angleDiff1 ) // line i hope
1787        {
1788            /* smoothen lines ------------- third time */
1789            mPrev.x = mPrev.y = -1;
1790            for (j=i-lineCnt, k=0; k<lineCnt+1-1 && lineCnt > 3; k+=2, j+=2)
1791            {   VGraphic	*l1=[[path list] objectAtIndex:j];
1792                VGraphic	*l2=[[path list] objectAtIndex:j+1];
1793                NSPoint	m1, m2;
1794
1795                [(VLine*)l1 getVertices:&s1 :&e1];
1796                [(VLine*)l2 getVertices:&s2 :&e2];
1797                m1 = CenterPoint(s1, e1);
1798                m2 = CenterPoint(s2, e2);
1799                if ( mPrev.x == -1 && mPrev.y == -1 ) // first
1800                    [(VLine*)l1 setVertices:s1 :m1];
1801                else
1802                    [(VLine*)l1 setVertices:mPrev :m1];
1803                [(VLine*)l2 setVertices:m1 :m2];
1804                mPrev = m2;
1805                if ( k >= lineCnt+1-3 ) // last
1806                {	VGraphic	*lineG=[VLine line];
1807                    NSColor	*nxBlack = [NSColor colorWithCalibratedRed:0.0 green:0.0 blue:0.0 alpha:1.0];
1808                    [lineG setColor:nxBlack]; [lineG setWidth:0]; [lineG setSelected:NO];
1809
1810                    if ( j+2 == lineCnt )
1811                    {   VGraphic	*l3=[[path list] objectAtIndex:j+2];
1812                        NSPoint	s3, e3, m3;
1813
1814                        [(VLine*)l3 getVertices:&s3 :&e3];
1815                        m3 = CenterPoint(s3, e3);
1816                        [(VLine*)l3 setVertices:m2 :m3];
1817                        [(VLine*)lineG setVertices:m3 :e3];
1818                        [[path list] insertObject:lineG atIndex:j+3];
1819                    }
1820                    else
1821                    {   [(VLine*)lineG setVertices:m2 :e2];
1822                        [[path list] insertObject:lineG atIndex:j+2];
1823                    }
1824                    i++;
1825                }
1826            }
1827        }
1828#endif
1829        lineCnt = 0;
1830    }
1831}
1832#endif
1833
1834// OLD
1835- (void)smoothenLinesInPath:(VPath*)path
1836{   int		i, j, k, lineCnt=0;
1837    NSPoint	s1, e1, s2, e2, grad1, grad2, mPrev;
1838
1839    if ( [[path list] count] < 2 )
1840        return;
1841
1842    for (i=0; i<(int)[[path list] count]; i++)
1843    {	id	g1 = [[path list] objectAtIndex:i], g2;
1844        int	noEdge = 0;
1845
1846        if ( i < (int)[[path list] count]-1 )
1847     	{   g2 = [[path list] objectAtIndex:i+1];
1848            [(VLine*)g1 getVertices:&s1 :&e1];
1849            grad1.x = e1.x - s1.x; grad1.y = e1.y - s1.y;
1850            [(VLine*)g2 getVertices:&s2 :&e2];
1851            grad2.x = e2.x - s2.x; grad2.y = e2.y - s2.y;
1852            if ( SqrDistPoints(e1, s2) < 5 && NNNNSameGradients(grad1, grad2) ) // [self noEdgeOrGapBetweenLines:g1 :g2]
1853                noEdge = 1.0;
1854            else
1855                noEdge = 0.0;
1856        }
1857        else
1858        {   g2 = [[path list] objectAtIndex:i-1];
1859            [(VLine*)g1 getVertices:&s1 :&e1];
1860            grad1.x = e1.x - s1.x; grad1.y = e1.y - s1.y;
1861            [(VLine*)g2 getVertices:&s2 :&e2];
1862            grad2.x = e2.x - s2.x; grad2.y = e2.y - s2.y;
1863            if ( SqrDistPoints(e2, s1) < 5 && NNNNSameGradients(grad1, grad2) ) //  && [self noEdgeOrGapBetweenLines:g2 :g1]
1864                noEdge = 1.0;
1865            else
1866                noEdge = 0.0;
1867        }
1868        if ( noEdge && i < (int)[[path list] count]-1 )
1869        {   lineCnt++;
1870            continue;
1871        }
1872        else if ( lineCnt <= 3 )
1873        {   lineCnt=0;
1874            continue;
1875        }
1876        mPrev.x = mPrev.y = -1;
1877        /* smoothen lines - allways ??? */
1878        for (j=i-lineCnt, k=0; k<lineCnt+1-1 && lineCnt > 3; k+=2, j+=2)
1879        {   VGraphic	*l1=[[path list] objectAtIndex:j];
1880            VGraphic	*l2=[[path list] objectAtIndex:j+1];
1881            NSPoint	m1, m2;
1882
1883            [(VLine*)l1 getVertices:&s1 :&e1];
1884            [(VLine*)l2 getVertices:&s2 :&e2];
1885            m1 = CenterPoint(s1, e1);
1886            m2 = CenterPoint(s2, e2);
1887            if ( mPrev.x == -1 && mPrev.y == -1 ) // first
1888                [(VLine*)l1 setVertices:s1 :m1];
1889            else
1890                [(VLine*)l1 setVertices:mPrev :m1];
1891            [(VLine*)l2 setVertices:m1 :m2];
1892            mPrev = m2;
1893            if ( k >= lineCnt+1-3 ) // last
1894            {	VGraphic	*lineG=[VLine line];
1895                NSColor	*nxBlack = [NSColor colorWithCalibratedRed:0.0 green:0.0 blue:0.0 alpha:1.0];
1896                [lineG setColor:nxBlack]; [lineG setWidth:0]; [lineG setSelected:NO];
1897                [(VLine*)lineG setVertices:m2 :e2];
1898                [[path list] insertObject:lineG atIndex:j+2];
1899                i++;
1900            }
1901        }
1902        lineCnt = 0;
1903    }
1904}
1905
1906/* modified:	30.01.00
1907 * go on building the path with these new points
1908 */
1909- (BOOL)pointIsEdge:(NSPoint)pt
1910{   int			byteY, byteX;
1911    unsigned char	byte, lbyte, rbyte, ubyte, dbyte, ulbyte, urbyte, dlbyte, drbyte;
1912    unsigned char	uullbyte, uurrbyte, ddllbyte, ddrrbyte, uulbyte, uurbyte, ddlbyte, ddrbyte;
1913    unsigned char	llbyte, rrbyte, uubyte, ddbyte, ullbyte, urrbyte, dllbyte, drrbyte;
1914    unsigned char	uuulllbyte, uuullbyte, uuulbyte, uuubyte, uuurbyte, uuurrbyte, uuurrrbyte;
1915    unsigned char	uulllbyte, uurrrbyte, ulllbyte, urrrbyte, lllbyte, rrrbyte, dlllbyte, drrrbyte, ddlllbyte;
1916    unsigned char	ddrrrbyte, dddlllbyte, dddllbyte, dddlbyte, dddbyte, dddrbyte, dddrrbyte, dddrrrbyte;
1917
1918    byteY = pt.y * bytesPerRow;	/* the height */
1919    byteY = size - byteY - bytesPerRow;
1920    byteX = byteY + pt.x; /* the width in bytes */
1921    byte = *(data+byteX);
1922
1923//    if ( byte != white )
1924//        return NO;
1925
1926    lbyte = *(data+(byteX-1));			rbyte = *(data+(byteX+1));
1927    dbyte = *(data+byteX+bytesPerRow);		ubyte = *(data+byteX-bytesPerRow);
1928    ulbyte = *(data+(byteX-1) - bytesPerRow);	urbyte = *(data+(byteX+1) - bytesPerRow);
1929    dlbyte = *(data+(byteX-1) + bytesPerRow);	drbyte = *(data+(byteX+1) + bytesPerRow);
1930
1931    uullbyte = *(data+(byteX-2)-(2*bytesPerRow));	uurrbyte = *(data+(byteX+2)-(2*bytesPerRow));
1932    ddllbyte = *(data+(byteX-2)+(2*bytesPerRow));	ddrrbyte = *(data+(byteX+2)+(2*bytesPerRow));
1933    uulbyte = *(data+(byteX-1)-(2*bytesPerRow));	uurbyte = *(data+(byteX+1)-(2*bytesPerRow));
1934    ddlbyte = *(data+(byteX-1)+(2*bytesPerRow));	ddrbyte = *(data+(byteX+1)+(2*bytesPerRow));
1935    uubyte = *(data+byteX-(2*bytesPerRow));		ddbyte = *(data+byteX+(2*bytesPerRow));
1936    llbyte = *(data+(byteX-2));				rrbyte = *(data+(byteX+2));
1937    ullbyte = *(data+(byteX-2) - bytesPerRow);		urrbyte = *(data+(byteX+2) - bytesPerRow);
1938    dllbyte = *(data+(byteX-2) + bytesPerRow);		drrbyte = *(data+(byteX+2) + bytesPerRow);
1939
1940    uuulllbyte = *(data+(byteX-3)-(3*bytesPerRow));	uuurrrbyte = *(data+(byteX+3)-(3*bytesPerRow));
1941    uuullbyte = *(data+(byteX-2)-(3*bytesPerRow));	uuurrbyte = *(data+(byteX+2)-(3*bytesPerRow));
1942    uuulbyte = *(data+(byteX-1)-(3*bytesPerRow));	uuurbyte = *(data+(byteX+1)-(3*bytesPerRow));
1943    uuubyte = *(data+byteX-(3*bytesPerRow));		dddbyte = *(data+byteX+(3*bytesPerRow));
1944    lllbyte = *(data+(byteX-3));			rrrbyte = *(data+(byteX+3));
1945    dddlbyte = *(data+(byteX-1)+(3*bytesPerRow));	dddrbyte = *(data+(byteX+1)+(3*bytesPerRow));
1946    dddllbyte = *(data+(byteX-2)+(3*bytesPerRow));	dddrrbyte = *(data+(byteX+2)+(3*bytesPerRow));
1947    dddlllbyte = *(data+(byteX-3)+(3*bytesPerRow));	dddrrrbyte = *(data+(byteX+3)+(3*bytesPerRow));
1948    ulllbyte = *(data+(byteX-3) - bytesPerRow);		urrrbyte = *(data+(byteX+3) - bytesPerRow);
1949    dlllbyte = *(data+(byteX-3) + bytesPerRow);		drrrbyte = *(data+(byteX+3) + bytesPerRow);
1950    uulllbyte = *(data+(byteX-3)-(2*bytesPerRow));	uurrrbyte = *(data+(byteX+3)-(2*bytesPerRow));
1951    ddlllbyte = *(data+(byteX-3)+(2*bytesPerRow));	ddrrrbyte = *(data+(byteX+3)+(2*bytesPerRow));
1952
1953    if ( !rbyte && !dbyte )
1954    {
1955        if ( !uuurbyte && !uuurrbyte && !uuurrrbyte && !uurrrbyte && !urrrbyte && !rrrbyte && !drrrbyte && !ddrrrbyte &&
1956            !dddrrrbyte && !dddrrbyte && !dddrbyte && !dddbyte && !dddlbyte && !dddllbyte &&
1957            !uurbyte && !uurrbyte && !urbyte && !urrbyte && !rrbyte && !drbyte && !drrbyte && !ddrbyte && !ddrrbyte &&
1958            !ddbyte && !ddlbyte )
1959            return YES;
1960        if ( !dlllbyte && !ddlllbyte && !dddlllbyte && !dddllbyte && !dddlbyte && !dddbyte && !dddrbyte && !dddrrbyte &&
1961            !dddrrrbyte && !ddrrrbyte && !drrrbyte && !rrrbyte && !urrrbyte && !uurrrbyte &&
1962            !urrbyte && !rrbyte && !drbyte && !drrbyte && !ddrbyte && !ddrrbyte && !ddbyte && !ddlbyte && !dlbyte &&
1963            !dllbyte && !ddllbyte )
1964            return YES;
1965    }
1966    if ( !rbyte && !ubyte )
1967    {
1968        if ( !uuullbyte && !uuulbyte && !uuubyte && !uuurbyte && !uuurrbyte && !uuurrrbyte && !uurrrbyte && !urrrbyte &&
1969            !rrrbyte && !drrrbyte && ddrrrbyte && !dddrrrbyte && !dddrrbyte && !dddrbyte &&
1970            !uulbyte && !uubyte && !uurbyte && !uurrbyte && !urbyte && !urrbyte && !rrbyte && !drbyte && !drrbyte &&
1971            !ddrbyte && !ddrrbyte )
1972            return YES;
1973        if ( !ulllbyte && !uulllbyte && !uuulllbyte && !uuullbyte && !uuulbyte && !uuubyte && !uuurbyte && !uuurrbyte &&
1974            !uuurrrbyte && !uurrrbyte && !urrrbyte && !rrrbyte && !drrrbyte && !ddrrrbyte &&
1975            !uullbyte && !ullbyte && !uulbyte && !ulbyte && !uubyte && !uurbyte && !uurrbyte &&!urbyte && !urrbyte &&
1976            !rrbyte && !drrbyte )
1977            return YES;
1978    }
1979    if ( !lbyte && !ubyte )
1980    {
1981        if ( !urrrbyte && !uurrrbyte && !uuurrrbyte && !uuurrbyte && !uuurbyte && !uuubyte && !uuulbyte && !uuullbyte &&
1982            !uuulllbyte && !uulllbyte && !ulllbyte && !lllbyte && !dlllbyte && !ddlllbyte &&
1983            !uullbyte && !uulbyte && !uubyte && !uurbyte && !uurrbyte && !urbyte && !urrbyte && !ulbyte && !ullbyte &&
1984            !llbyte && !dllbyte )
1985            return YES;
1986        if ( !uuurrbyte && !uuurbyte && !uuubyte && !uuulbyte && !uuullbyte && !uuulllbyte && !uulllbyte && !ulllbyte &&
1987            !lllbyte && !dlllbyte && !ddlllbyte && !dddlllbyte && !dddllbyte && !dddlbyte &&
1988            !uullbyte && !uulbyte && !uubyte && !uurbyte && !ulbyte && !ullbyte && !llbyte && !dllbyte && !dlbyte &&
1989            !ddllbyte && !ddlbyte )
1990            return YES;
1991    }
1992    if ( !lbyte && !dbyte )
1993    {
1994        if ( !uuulbyte && !uuullbyte && !uuulllbyte && !uulllbyte && !ulllbyte && !lllbyte && !dlllbyte && !ddlllbyte &&
1995            !dddlllbyte && !dddllbyte && !dddlbyte && !dddbyte && !dddrbyte && !dddrrbyte &&
1996            !uullbyte && !uulbyte && !ullbyte && !ulbyte && !llbyte && !dllbyte && !dlbyte && !ddllbyte && !ddlbyte &&
1997            !ddrbyte && !ddbyte )
1998            return YES;
1999        if ( !uulllbyte && !ulllbyte && !lllbyte && !dlllbyte && !ddlllbyte && !dddlllbyte && !dddllbyte && !dddlbyte &&
2000            !dddbyte && !dddrbyte && !dddrrbyte && !dddrrrbyte && !ddrrrbyte && !drrrbyte &&
2001            !ullbyte && !llbyte && !dllbyte && !dlbyte && !drbyte && !drrbyte && !ddllbyte && !ddlbyte && !ddbyte &&
2002            !ddrbyte && !ddrrbyte )
2003            return YES;
2004    }
2005    // the same++ for white !!!
2006    if ( rbyte==white && dbyte==white && ubyte==white )
2007    {
2008        if ( white==uubyte && white==uuubyte && white==dlbyte && white==ddllbyte && white==dddlllbyte &&
2009            white==uuurbyte && white==uuurrbyte && white==uuurrrbyte && white==uurrrbyte && white==urrrbyte &&
2010            white==rrrbyte && white==drrrbyte && white==ddrrrbyte && white==dddrrrbyte && white==dddrrbyte &&
2011            white==dddrbyte && white==dddbyte && white==dddlbyte && white==dddllbyte && white==uurbyte &&
2012            white==uurrbyte && white==urbyte && white==urrbyte && white==rrbyte && white==drbyte && white==drrbyte &&
2013            white==ddrbyte && white==ddrrbyte && white==ddbyte && white==ddlbyte )
2014            return YES;
2015        if ( white==ddbyte && white==dddbyte && white==uuulllbyte && white==uullbyte && white==ulbyte &&
2016            white==uuullbyte && white==uuulbyte && white==uuubyte && white==uuurbyte && white==uuurrbyte &&
2017            white==uuurrrbyte && white==uurrrbyte && white==urrrbyte && white==rrrbyte && white==drrrbyte &&
2018            ddrrrbyte && white==dddrrrbyte && white==dddrrbyte && white==dddrbyte && white==uulbyte &&
2019            white==uubyte && white==uurbyte && white==uurrbyte && white==urbyte && white==urrbyte && white==rrbyte &&
2020            white==drbyte && white==drrbyte && white==ddrbyte && white==ddrrbyte )
2021            return YES;
2022    }
2023    if ( white==rbyte && white==ubyte && white==lbyte )
2024    {
2025        if ( white==rrbyte && white==rrrbyte && white==dlbyte && ddllbyte && dddlllbyte &&
2026            white==urrrbyte && white==uurrrbyte && white==uuurrrbyte && white==uuurrbyte && white==uuurbyte &&
2027            white==uuubyte && white==uuulbyte && white==uuullbyte && white==uuulllbyte && white==uulllbyte &&
2028            white==ulllbyte && white==lllbyte && white==dlllbyte && white==ddlllbyte && white==uullbyte &&
2029            white==uulbyte && white==uubyte && white==uurbyte && white==uurrbyte && white==urbyte && white==urrbyte &&
2030            white==ulbyte && white==ullbyte && white==llbyte && white==dllbyte )
2031            return YES;
2032        if ( white==llbyte && white==lllbyte && white==drbyte && white==ddrrbyte && dddrrrbyte &&
2033            white==ulllbyte && white==uulllbyte && white==uuulllbyte && white==uuullbyte && white==uuulbyte &&
2034            white==uuubyte && white==uuurbyte && white==uuurrbyte && white==uuurrrbyte && white==uurrrbyte &&
2035            white==urrrbyte && white==rrrbyte && white==drrrbyte && white==ddrrrbyte && white==uullbyte &&
2036            white==ullbyte && white==uulbyte && white==ulbyte && white==uubyte && white==uurbyte && white==uurrbyte &&
2037            white==urbyte && white==urrbyte && white==rrbyte && white==drrbyte )
2038            return YES;
2039    }
2040    if ( white==lbyte && white==ubyte && white==dbyte )
2041    {
2042        if ( white==uubyte && white==uuubyte && white==drbyte && white==ddrrbyte && dddrrrbyte &&
2043            white==uuulbyte && white==uuullbyte && white==uuulllbyte && white==uulllbyte && white==ulllbyte &&
2044            white==lllbyte && white==dlllbyte && white==ddlllbyte && white==dddlllbyte && white==dddllbyte &&
2045            white==dddlbyte && white==dddbyte && white==dddrbyte && white==dddrrbyte && white==uullbyte &&
2046            white==uulbyte && white==ullbyte && white==ulbyte && white==llbyte && white==dllbyte && white==dlbyte &&
2047            white==ddllbyte && white==ddlbyte && white==ddrbyte && white==ddbyte )
2048            return YES;
2049        if ( white==ddbyte && white==dddbyte && white==ulbyte && white==uullbyte && white==uuulllbyte &&
2050            white==uuurrbyte && white==uuurbyte && white==uuubyte && white==uuulbyte && white==uuullbyte &&
2051            white==uuulllbyte && white==uulllbyte && white==ulllbyte && white==lllbyte && white==dlllbyte &&
2052            white==ddlllbyte && white==dddlllbyte && white==dddllbyte && white==dddlbyte && white==uullbyte &&
2053            white==uulbyte && white==uubyte && white==uurbyte && white==ulbyte && white==ullbyte && white==llbyte &&
2054            white==dllbyte && white==dlbyte && white==ddllbyte && white==ddlbyte )
2055            return YES;
2056    }
2057    if ( white==lbyte && white==dbyte && white==rbyte )
2058    {
2059        if ( white==llbyte && white==lllbyte && white==urbyte && white==uurrbyte && white==uuurrrbyte &&
2060            white==dlllbyte && white==ddlllbyte && white==dddlllbyte && white==dddllbyte && white==dddlbyte &&
2061            white==dddbyte && white==dddrbyte && white==dddrrbyte && white==dddrrrbyte && white==ddrrrbyte &&
2062            white==drrrbyte && white==rrrbyte && white==urrrbyte && white==uurrrbyte && white==urrbyte &&
2063            white==rrbyte && white==drbyte && white==drrbyte && white==ddrbyte && white==ddrrbyte && white==ddbyte &&
2064            white==ddlbyte && white==dlbyte && white==dllbyte && white==ddllbyte )
2065            return YES;
2066        if ( white==rrbyte && white==rrrbyte && white==ulbyte && white==uullbyte && white==uuulllbyte &&
2067            white==uulllbyte && white==ulllbyte && white==lllbyte && white==dlllbyte && white==ddlllbyte &&
2068            white==dddlllbyte && white==dddllbyte && white==dddlbyte && white==dddbyte && white==dddrbyte &&
2069            white==dddrrbyte && white==dddrrrbyte && white==ddrrrbyte && white==drrrbyte && white==ullbyte &&
2070            white==llbyte && white==dllbyte && white==dlbyte && white==drbyte && white==drrbyte && white==ddllbyte &&
2071            white==ddlbyte && white==ddbyte && white==ddrbyte && white==ddrrbyte )
2072            return YES;
2073    }
2074
2075    if ( !lbyte && !dbyte && !rbyte )
2076    {   unsigned char	ullllbyte, llllbyte, dllllbyte, urrrrbyte, rrrrbyte, drrrrbyte;
2077
2078        llllbyte = *(data+(byteX-4));			rrrrbyte = *(data+(byteX+4));
2079        ullllbyte = *(data+(byteX-4) - bytesPerRow);	urrrrbyte = *(data+(byteX+4) - bytesPerRow);
2080        dllllbyte = *(data+(byteX-4) + bytesPerRow);	drrrrbyte = *(data+(byteX+4) + bytesPerRow);
2081
2082        if ( !dlbyte && !drbyte && !llbyte && !dllbyte && !ddllbyte && !ddlbyte && !ddbyte && !ddrbyte && !ddrrbyte && !drrbyte && !rrbyte && !lllbyte && !dlllbyte && !ddlllbyte && !dddlllbyte && !dddllbyte && !dddlbyte && !dddbyte && !dddrbyte && !dddrrbyte && !dddrrrbyte && !ddrrrbyte && !drrrbyte && !rrrbyte && !ullllbyte && !llllbyte && !dllllbyte && !drrrrbyte && !rrrrbyte && !urrrrbyte )
2083            return YES;
2084    }
2085    if ( !lbyte && !ubyte && !rbyte )
2086    {   unsigned char	ullllbyte, llllbyte, dllllbyte, urrrrbyte, rrrrbyte, drrrrbyte;
2087
2088        llllbyte = *(data+(byteX-4));			rrrrbyte = *(data+(byteX+4));
2089        ullllbyte = *(data+(byteX-4) - bytesPerRow);	urrrrbyte = *(data+(byteX+4) - bytesPerRow);
2090        dllllbyte = *(data+(byteX-4) + bytesPerRow);	drrrrbyte = *(data+(byteX+4) + bytesPerRow);
2091
2092        if ( !ulbyte && !urbyte && !llbyte && !ullbyte && !uullbyte && !uulbyte && !uubyte && !uurbyte && !uurrbyte && !urrbyte && !rrbyte && !lllbyte && !ulllbyte && !uulllbyte && !uuulllbyte && !uuullbyte && !uuulbyte && !uuubyte && !uuurbyte && !uuurrbyte && !uuurrrbyte && !uurrrbyte && !urrrbyte && !rrrbyte && !ullllbyte && !llllbyte && !dllllbyte && !drrrrbyte && !rrrrbyte && !urrrrbyte )
2093            return YES;
2094    }
2095    if ( !ubyte && !dbyte && !rbyte )
2096    {   unsigned char	uuuubyte, ddddbyte, uuuulbyte, uuuurbyte, ddddlbyte, ddddrbyte;
2097
2098        uuuubyte = *(data+byteX-(4*bytesPerRow));	ddddbyte = *(data+byteX+(4*bytesPerRow));
2099        uuuulbyte = *(data+(byteX-1)-(4*bytesPerRow));	uuuurbyte = *(data+(byteX+1)-(4*bytesPerRow));
2100        ddddlbyte = *(data+(byteX-1)+(4*bytesPerRow));	ddddrbyte = *(data+(byteX+1)+(4*bytesPerRow));
2101
2102        if ( !urbyte && !drbyte && !uubyte && !uurbyte && !uurrbyte && !urrbyte && !rrbyte && !drrbyte && !ddrrbyte && !ddrbyte && !ddbyte && !uuubyte && !uuurbyte && !uuurrbyte && !uuurrrbyte && !uurrrbyte && !urrrbyte && !rrrbyte && !drrrbyte && !ddrrrbyte && !dddrrrbyte && !dddrrbyte && !dddrbyte && !dddbyte && !uuuulbyte && !uuuubyte && !uuuurbyte && !ddddlbyte && !ddddbyte && !ddddrbyte )
2103            return YES;
2104    }
2105    if ( !ubyte && !dbyte && !lbyte )
2106    {   unsigned char	uuuubyte, ddddbyte, uuuulbyte, uuuurbyte, ddddlbyte, ddddrbyte;
2107
2108        uuuubyte = *(data+byteX-(4*bytesPerRow));	ddddbyte = *(data+byteX+(4*bytesPerRow));
2109        uuuulbyte = *(data+(byteX-1)-(4*bytesPerRow));	uuuurbyte = *(data+(byteX+1)-(4*bytesPerRow));
2110        ddddlbyte = *(data+(byteX-1)+(4*bytesPerRow));	ddddrbyte = *(data+(byteX+1)+(4*bytesPerRow));
2111
2112        if ( !ulbyte && !dlbyte && !uubyte && !uulbyte && !uullbyte && !ullbyte && !llbyte && !dllbyte && !ddllbyte && !ddlbyte && !ddbyte && !uuubyte && !uuulbyte && !uuullbyte && !uuulllbyte && !uulllbyte && !ulllbyte && !lllbyte && !dlllbyte && !ddlllbyte && !dddlllbyte && !dddllbyte && !dddlbyte && !dddbyte && !uuuulbyte && !uuuubyte && !uuuurbyte && !ddddlbyte && !ddddbyte && !ddddrbyte )
2113            return YES;
2114    }
2115//white
2116    return NO;
2117}
2118
2119- (void)connectPtToLine:(int)indexL :(NSPoint)pt :(int*)endIsNearer :(int*)lineArray :(VPath*)path :(float)w
2120{   int	edge=0;
2121    float	minLineLength=81, minLineLenHV=7, len;
2122    NSPoint	start, end;
2123    VGraphic	*lineG = [[path list] objectAtIndex:lineArray[indexL]];
2124
2125    if ( Abs(w) < 0.29 ) // < 0.1 mm
2126    {   minLineLength = 25; minLineLenHV = 5; }
2127    if ( Abs(w) >= 0.29 ) // >= 0.1 mm
2128    {   minLineLength = 36; minLineLenHV = 5; }
2129    if ( Abs(w) >= 0.86 ) // >= 0.3 mm
2130    {   minLineLength = 49; minLineLenHV = 5; }
2131    if ( Abs(w) >= 1.42 ) // >= 0.5 mm
2132    {   minLineLength = 64; minLineLenHV = 6; }
2133    if ( Abs(w) >= 2.83 ) // >= 1.0 mm
2134    {   minLineLength = 81; minLineLenHV = 7; }
2135    if ( Abs(w) >= 5.6 ) // >= 2.0 mm
2136    {   minLineLength = 100; minLineLenHV = 8; }
2137
2138    [(VLine*)lineG getVertices:&start :&end];
2139    ( *endIsNearer ) ? (len=SqrDistPoints(start, pt)) : (len=SqrDistPoints(end, pt));
2140    //lenOld = SqrDistPoints(start, end);
2141    if ( [self pointIsEdge:pt] )
2142        edge = 1;
2143    if ( start.x == end.x && start.y == end.y ) // have at least started a new line
2144    {
2145        if ( edge && ![self pointIsEdge:start] )
2146        {   [lineG setSelected:YES];
2147            [(VLine*)lineG setVertices:pt :pt];
2148        }
2149        else [(VLine*)lineG setVertices:start :pt];
2150    }
2151    else if ( (start.x == end.x && Diff(start.y, end.y) >= minLineLenHV) ||
2152             (start.y == end.y && Diff(start.x, end.x) >= minLineLenHV) )
2153    {   // vertical lines not so long !
2154        if ( /*len > lenOld &&*/ ((len <= minLineLength && start.x == end.x && pt.x == start.x)
2155                                 || (start.y == end.y && pt.y == start.y)) )
2156        {
2157            if ( [lineG isSelected] &&
2158                ((!(*endIsNearer)  && [self pointIsEdge:start]) || (endIsNearer && [self pointIsEdge:end])) )
2159            {   // else we would change the edge !
2160                lineG = [VLine line];
2161                [lineG setSelected:YES]; [lineG setColor:[NSColor blackColor]]; [lineG setWidth:0];
2162                [(VLine*)lineG setVertices:pt :pt];
2163                [[path list] addObject:lineG]; *endIsNearer = 1;
2164                lineArray[indexL] = (int)[[path list] count]-1; // replace value at indexL with new line index
2165            }
2166            else // connect
2167            {   if ( *endIsNearer ) [(VLine*)lineG setVertices:start :pt];
2168                else		   [(VLine*)lineG setVertices:pt :end]; // here other direction is ok
2169                if ( edge )
2170                {   [lineG setSelected:YES];
2171                    lineG = [VLine line]; [lineG setSelected:YES];
2172                    [lineG setColor:[NSColor blackColor]]; [lineG setWidth:0];
2173                    [(VLine*)lineG setVertices:pt :pt]; *endIsNearer = 1;
2174                    [[path list] addObject:lineG];
2175                    lineArray[indexL] = (int)[[path list] count]-1; // replace value at indexL with new line index
2176                }
2177            }
2178        }
2179        else // if ( len <= lenOld )
2180        {   lineG = [VLine line]; ( edge ) ? [lineG setSelected:YES] : [lineG setSelected:NO];
2181            [lineG setColor:[NSColor blackColor]]; [lineG setWidth:0];
2182            if ( *endIsNearer ) [(VLine*)lineG setVertices:end :pt];
2183            else	      { [(VLine*)lineG setVertices:start :pt]; *endIsNearer = 1; }
2184            [[path list] addObject:lineG];
2185            lineArray[indexL] = (int)[[path list] count]-1; // replace value at indexL with new line index
2186        }
2187    }
2188    else // no vertical / horicontal line
2189    {
2190        if ( /*len > lenOld &&*/ len <= minLineLength )
2191        {
2192            if ( [lineG isSelected] && // start or end is edge point - do not change !!!
2193                ((!(*endIsNearer)  && [self pointIsEdge:start]) || (*endIsNearer && [self pointIsEdge:end])) )
2194            {   // else we would change the edge !
2195                lineG = [VLine line];
2196                [lineG setSelected:YES]; [lineG setColor:[NSColor blackColor]]; [lineG setWidth:0];
2197                [(VLine*)lineG setVertices:pt :pt]; *endIsNearer = 1;
2198                [[path list] addObject:lineG];
2199                lineArray[indexL] = (int)[[path list] count]-1; // replace value at indexL with new line index
2200            }
2201            else
2202            {   if ( *endIsNearer ) [(VLine*)lineG setVertices:start :pt];
2203                else		  { [(VLine*)lineG setVertices:end :pt]; *endIsNearer = 1; }// change direction !
2204                if ( edge )
2205                {   [lineG setSelected:YES];
2206                    lineG = [VLine line];
2207                    [lineG setSelected:YES]; [lineG setColor:[NSColor blackColor]]; [lineG setWidth:0];
2208                    [(VLine*)lineG setVertices:pt :pt]; *endIsNearer = 1;
2209                    [[path list] addObject:lineG];
2210                    lineArray[indexL] = (int)[[path list] count]-1; // replace value at indexL with new line index
2211                }
2212            }
2213        }
2214#if 0
2215                else if ( len <= lenOld )
2216                {   lineG = [VLine line]; ( edge ) ? [lineG setSelected:YES] : [lineG setSelected:NO];
2217                    [lineG setColor:[NSColor blackColor]]; [lineG setWidth:0];
2218                    [(VLine*)lineG setVertices:pt :pt]; *endIsNearer = 1;
2219                    [[path list] addObject:lineG];
2220                    lineArray[indexL] = (int)[[path list] count]-1; // replace value at indexL with new line index
2221                    return;
2222                }
2223#endif
2224        else
2225        {
2226            if ( [lineG isSelected] &&
2227                ((!(*endIsNearer)  && [self pointIsEdge:start]) || (endIsNearer && [self pointIsEdge:end])) )
2228            {   // else we would change the edge !
2229                lineG = [VLine line];
2230                [lineG setSelected:YES]; [lineG setColor:[NSColor blackColor]]; [lineG setWidth:0];
2231                [(VLine*)lineG setVertices:pt :pt]; *endIsNearer = 1;
2232                [[path list] addObject:lineG];
2233                lineArray[indexL] = (int)[[path list] count]-1; // replace value at indexL with new line index
2234            }
2235            else
2236            {   if ( edge )
2237                {   if ( *endIsNearer ) { [(VLine*)lineG setVertices:start :pt]; end=pt; }
2238                    else	       { [(VLine*)lineG setVertices:end :pt]; start = pt; }
2239                    [lineG setSelected:YES];
2240                }
2241                lineG = [VLine line]; ( edge ) ? [lineG setSelected:YES] : [lineG setSelected:NO];
2242                [lineG setColor:[NSColor blackColor]]; [lineG setWidth:0];
2243                if ( *endIsNearer ) [(VLine*)lineG setVertices:end :pt];
2244                else		   { [(VLine*)lineG setVertices:start :pt]; *endIsNearer = 1; }
2245                [[path list] addObject:lineG];
2246                lineArray[indexL] = (int)[[path list] count]-1; // replace value at indexL with new line index
2247            }
2248        }
2249    }
2250}
2251
2252/* modified:	2008-02-08
2253 * go on building the path with these new points
2254 */
2255- (void)buildPath:(VPath*)path :(NSPoint*)pts :(int)pCnt :(float)w :(int*)lineArray :(int*)lineCnt
2256{   int         i, j, k, myPcnt=pCnt, startNewLine = 0; // lineArray[pCnt*2], lineCnt=0
2257    NSPoint     start, end, s, e;
2258    VGraphic    *lineG, *lineG2;
2259    NSColor     *nxBlack = [NSColor colorWithCalibratedRed:0.0 green:0.0 blue:0.0 alpha:1.0];
2260
2261    if ( ![[path list] count] && pCnt)
2262    {
2263        if ( pCnt > 1 && Diff(pts[0].x, pts[1].x) <= 1 ) // waagerechte ?
2264        {   for (i=0; i<2; i++)
2265            {   lineG = [VLine line]; ( [self pointIsEdge:pts[0]] ) ? [lineG setSelected:YES] : [lineG setSelected:NO];
2266                [lineG setColor:nxBlack]; [lineG setWidth:0];
2267                [(VLine*)lineG setVertices:pts[0] :pts[0]];
2268                [[path list] addObject:lineG];
2269                lineArray[(*lineCnt)++] = i;
2270                for (k=0; k<myPcnt-1; k++)
2271                    pts[k] = pts[k+1];
2272                myPcnt--;
2273            }
2274        }
2275        else // start two lines !
2276        {   for (i=0; i<2; i++)
2277            {   lineG = [VLine line]; ( [self pointIsEdge:pts[0]] ) ? [lineG setSelected:YES] : [lineG setSelected:NO];
2278                [lineG setColor:nxBlack]; [lineG setWidth:0];
2279                [(VLine*)lineG setVertices:pts[0] :pts[0]];
2280                [[path list] addObject:lineG];
2281                lineArray[(*lineCnt)++] = i;
2282            }
2283            for (k=0; k<myPcnt-1; k++)
2284                pts[k] = pts[k+1];
2285            myPcnt--;
2286        }
2287    }
2288
2289    while ( myPcnt > 0 )
2290    {
2291        // connect pts to lines
2292        for (i=0; i<(*lineCnt); i++)
2293        {   int	endIsNearer=-1, indexE=-1, indexS=-1, secondLine=0, endIsNearer2=0;
2294            int	fromLeftToRight=1, stopForLine2 = 0, secDiff=0, doNotRemovePtJ = 0, rowDiff=0;
2295            NSPoint	stopPt = NSZeroPoint, lastRowPt;
2296
2297            if ( myPcnt <= 0 && startNewLine )
2298                break; // else we must remove lines with no point !!
2299
2300            lineG=[[path list] objectAtIndex:lineArray[i]];
2301            [(VLine*)lineG getVertices:&start :&end];
2302            // first get nearest pt to lineG
2303            for (j=0; j<myPcnt; j++)
2304            {
2305                if ( indexS == -1 && end.y >= start.y && // indexS allways set -> do not set indexE !!!
2306                    Diff(pts[j].x, end.x) <= 1 && Diff(pts[j].y, end.y) <= 1 &&
2307                    Diff(pts[j].x, end.x) <= Diff(pts[j].x, start.x) && end.y >= start.y &&
2308                    ((indexE == -1 || (Diff(pts[j].x, end.x) < Diff(pts[indexE].x, end.x))) ||
2309                    (indexE != -1 && Diff(pts[j].x, end.x) == Diff(pts[indexE].x, end.x) && end.x > start.x)) )
2310                    // line from le to ri -> prefer ri pt
2311                {   indexE = j; endIsNearer = 1; }
2312                else if ( indexE == -1 && start.y >= end.y && // (start.x != end.x || start.y != end.y) &&
2313                          Diff(pts[j].x, start.x) <= 1 && Diff(pts[j].y, start.y) <= 1 &&
2314                          Diff(pts[j].x, start.x) <= Diff(pts[j].x, end.x) && start.y >= end.y &&
2315                          ((indexS == -1 || (Diff(pts[j].x, start.x) < Diff(pts[indexS].x, start.x))) ||
2316                           (indexS != -1 && Diff(pts[j].x, start.x) == Diff(pts[indexS].x, start.x) && start.x > end.x)) )
2317                {   indexS = j; endIsNearer = 0; }
2318                else if ( (end.y > start.y && pts[j].x > end.x+1) || (start.y > end.y && pts[j].x > start.x+1) ||
2319                          (end.y == start.y && pts[j].x > end.x+1 && pts[j].x > start.x+1) )
2320                    break;
2321            }
2322            if ( indexE == -1 && indexS == -1 )
2323            {   int	m;
2324                if ( !(start.x == end.x && start.y == end.y && start.y == pts[0].y) && !startNewLine )
2325                {   for (m=i; m<(*lineCnt)-1; m++) // sort out line from lineArray
2326                        lineArray[m] = lineArray[m+1];
2327                    (*lineCnt)--;
2328                    i--; // else we jump over one line
2329                }
2330                continue;
2331            }
2332            ( endIsNearer ) ? (j = indexE) : (j=indexS); // must set j !!!!!!!!!!!!!!!!!!!
2333
2334            // check if pt row
2335            rowDiff = 0;
2336            for (k=j; k<myPcnt-1 && i<(*lineCnt)-1; k++)
2337            {   if ( Diff(pts[k].x, pts[k+1].x) <= 1 )
2338                {   rowDiff = (k+1)-j; lastRowPt = pts[k+1]; }
2339                else break;
2340            }
2341            rowDiff += 2; // min of two - if one pt and two lines !!
2342
2343            // look for a second line right of lineG with rowDist distance
2344            if ( i < (*lineCnt)-1 )
2345            {   NSPoint	tp;
2346                lineG2 = [[path list] objectAtIndex:lineArray[i+1]];
2347                [(VLine*)lineG2 getVertices:&s :&e];
2348                if ( s.y > e.y ) tp = s;
2349                else if ( e.y > s.y ) tp = e;
2350                else tp = e; // if ( pts[j].x <= s.x && pts[j].x <= e.x ) - only possible !
2351                if ( ( endIsNearer && (secDiff=Diff(  end.x, tp.x)) <= rowDiff) ||
2352                     (!endIsNearer && (secDiff=Diff(start.x, tp.x)) <= rowDiff) )
2353                {   secondLine = 1; secDiff += 2;
2354                    endIsNearer2 = 1; // allways the end
2355                }
2356            }
2357            // set connect direction and j if necessary !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
2358            // pts on both sides of pts[j]
2359            if ( ((!secondLine && j-1 >= 0 && Diff(pts[j-1].x, pts[j].x) <= 1) ||
2360                  (secondLine && j-1 >= 0 && Diff(pts[j-1].x, pts[j].x) <= secDiff)) &&
2361                 ((!secondLine && j+1 < myPcnt && Diff(pts[j+1].x, pts[j].x) <= 1) ||
2362                  (secondLine && j+1 < myPcnt && Diff(pts[j+1].x, pts[j].x) <= secDiff)) )
2363            {
2364                // look for direction of line ???
2365                if ( (endIsNearer && end.x <= start.x) || (!endIsNearer && start.x <= end.x) ||
2366                    (secondLine && e.x <= s.x) )
2367                    fromLeftToRight = 0; // start right - at j
2368                else if ( (endIsNearer && end.x > start.x) || (!endIsNearer && start.x > end.x) ||
2369                          (secondLine && e.x > s.x) )
2370                    fromLeftToRight = 1; // start left - at j until stopPt !!
2371            }
2372            // pts left of pts[j]
2373            else if ( (!secondLine && j-1 >= 0 && Diff(pts[j-1].x, pts[j].x) <= 1) ||
2374                    (secondLine && j-1 >= 0 && Diff(pts[j-1].x, pts[j].x) <= secDiff) )
2375            {
2376                fromLeftToRight = 0;
2377                if ( secondLine && Diff(pts[j].x, pts[j-1].x) <= 1 )
2378                    doNotRemovePtJ = 1; // need j also for second line
2379                else if ( secondLine )
2380                    j = j-1; // must connect one pt to second line !
2381                if ( !secondLine && ((endIsNearer && start.x < end.x) || (!endIsNearer && end.x < start.x)) &&
2382                    [self pointIsEdge:pts[j]] ) // direction change !!
2383                {   int	m;
2384                    lineG = [VLine line]; // start a new line !!!
2385                    [lineG setSelected:YES]; [lineG setColor:nxBlack]; [lineG setWidth:0];
2386                    [(VLine*)lineG setVertices:pts[j] :pts[j]]; start = end = pts[j];
2387                    [[path list] addObject:lineG];
2388                    lineArray[i] = (int)[[path list] count]-1; // replace line index
2389                    for (m=j; m<myPcnt-1; m++) // sort out pt j from pts
2390                        pts[m] = pts[m+1];
2391                    myPcnt--;
2392                }
2393            }
2394            // pts right of pts[j]
2395            else if ( (!secondLine && j+1 < myPcnt && Diff(pts[j+1].x, pts[j].x) <= 1) ||
2396                    (secondLine && j+1 < myPcnt && Diff(pts[j+1].x, pts[j].x) <= secDiff) )
2397            {
2398                fromLeftToRight = 1;
2399                if ( !secondLine && ((endIsNearer && start.x > end.x) || (!endIsNearer && end.x > start.x)) &&
2400                    [self pointIsEdge:pts[j]] )
2401                {   int	m;
2402                    lineG = [VLine line]; // start a new line !!!
2403                    [lineG setSelected:YES]; [lineG setColor:nxBlack]; [lineG setWidth:0];
2404                    [(VLine*)lineG setVertices:pts[j] :pts[j]]; start = end = pts[j];
2405                    [[path list] addObject:lineG];
2406                    lineArray[i] = (int)[[path list] count]-1; // replace line index
2407                    for (m=j; m<myPcnt-1; m++) // sort out pt j from pts
2408                        pts[m] = pts[m+1];
2409                    myPcnt--;
2410                }
2411            }
2412            else if ( secondLine && ((s.x == e.x && s.y == e.y) ||     // set point to new/right line !!
2413                                     (start.y == end.y && pts[j].y > end.y)) ) continue;
2414            else if ( secondLine && ((endIsNearer && (start.x != s.x || start.y != s.y)) ||
2415                                     (!endIsNearer && (end.x != e.x || end.y != e.y))) )
2416                doNotRemovePtJ = 1; // only one pt for both lines - for peaks at top /\ !
2417
2418            // search stop pt for second line !!!
2419            if ( fromLeftToRight && secondLine && !doNotRemovePtJ && j+1 < myPcnt )
2420            {
2421                if ( ((endIsNearer && start.x > end.x) || (!endIsNearer && end.x > start.x)) )
2422                {   stopPt = pts[j+1]; stopForLine2 = 1; } // only one pt to connect for lineG !! - other direction
2423                else
2424                {   // get nearest pt to second line - is our stop PT
2425                    indexE = indexS = -1;
2426                    for (k=j+1; k<myPcnt; k++)
2427                    {
2428                        if ( e.y >= s.y && Diff(pts[k].x, e.x) <= 1 && Diff(pts[k].y, e.y) <= 1 &&
2429                            Diff(pts[k].x, e.x) <= Diff(pts[k].x, s.x) && e.y >= s.y )
2430                            //(indexE == -1 || (Diff(pts[k].x, e.x) <= Diff(pts[indexE].x, e.x))) // need right pt
2431                        {   stopPt = pts[k]; indexE = k; endIsNearer2 = 1; }
2432                        else if ( indexE == -1 && s.y >= e.y && // (s.x != e.x || s.y != e.y) &&
2433                                 Diff(pts[k].x, s.x) <= 1 && Diff(pts[k].y, s.y) <= 1 &&
2434                                 Diff(pts[k].x, s.x) <= Diff(pts[k].x, e.x) && s.y >= e.y )
2435                                //(indexS == -1 || (Diff(pts[k].x, s.x) <= Diff(pts[indexS].x, s.x)))
2436                        {   stopPt = pts[k]; indexS = k; endIsNearer2 = 0; }
2437                        else if ( (e.y > s.y && pts[j].x > e.x+1) || (s.y > e.y && pts[j].x > s.x+1) ||
2438                                 (e.y == s.y && pts[j].x > e.x+1 && pts[j].x > s.x+1) )
2439                            break;
2440                    }
2441    //                if ( indexE == -1 && indexS == -1 )
2442    //                    printf("no StopPt found ???\n"); // ??????????????????????????????????????????
2443                    if ( indexE != -1 || indexS != -1 )
2444                        stopForLine2 = 1; // must stop connect to rest pts for second line
2445                }
2446            }
2447
2448            // connect pts to line(s)
2449            if ( fromLeftToRight && !stopForLine2 )
2450            {   int	m;
2451                for (k=j; k<myPcnt; k++)
2452                {
2453                    if ( ( endIsNearer && Diff(pts[k].x,   end.x) <= 1) ||
2454                         (!endIsNearer && Diff(pts[k].x, start.x) <= 1) )
2455                    {   [self connectPtToLine:i :pts[k] :&endIsNearer :lineArray :path :w];
2456                        lineG = [[path list] objectAtIndex:lineArray[i]]; // must set lineG new !!!
2457                        [(VLine*)lineG getVertices:&start :&end]; // must set start / end new !!!
2458                        if ( !doNotRemovePtJ )
2459                        {   for (m=k; m<myPcnt-1; m++) // sort out pt j from pts
2460                                pts[m] = pts[m+1];
2461                            myPcnt--;
2462                            k--;
2463                        }
2464                        else doNotRemovePtJ = 0; // only first pt
2465                    }
2466                    else break;
2467                }
2468            }
2469            else if ( fromLeftToRight && stopForLine2 )
2470            {   int	m;
2471                for (k=j; k<myPcnt; k++)
2472                {
2473                    if ( (pts[k].x != stopPt.x || pts[k].y != stopPt.y) && // do not connect stopPt
2474                         (( endIsNearer && Diff(pts[k].x,   end.x) <= 1) ||
2475                          (!endIsNearer && Diff(pts[k].x, start.x) <= 1)) )
2476                    {   [self connectPtToLine:i :pts[k] :&endIsNearer :lineArray :path :w];
2477                        lineG = [[path list] objectAtIndex:lineArray[i]]; // must set lineG new !!!
2478                        [(VLine*)lineG getVertices:&start :&end]; // must set start / end new !!!
2479                        if ( !doNotRemovePtJ )
2480                        {   for (m=k; m<myPcnt-1; m++) // sort out pt j from pts
2481                            pts[m] = pts[m+1];
2482                            myPcnt--;
2483                            k--;
2484                        }
2485                        else doNotRemovePtJ = 0;
2486                    }
2487                    else break;
2488                }
2489            }
2490            else if ( !fromLeftToRight ) // connect pts from right to left start with k -> first line if we have two lines !
2491            {   int	m;
2492                for (k=j; k>=0; k--)
2493                {
2494                    if ( ( endIsNearer && Diff(pts[k].x,   end.x) <= 1) ||
2495                         (!endIsNearer && Diff(pts[k].x, start.x) <= 1) )
2496                    {   [self connectPtToLine:i :pts[k] :&endIsNearer :lineArray :path :w];
2497                        lineG = [[path list] objectAtIndex:lineArray[i]]; // must set lineG new !!!
2498                        [(VLine*)lineG getVertices:&start :&end]; // must set start / end new !!!
2499                        if ( !doNotRemovePtJ )
2500                        {   for (m=k; m<myPcnt-1; m++) // sort out pt j from pts
2501                                pts[m] = pts[m+1];
2502                            myPcnt--;
2503                        }
2504                        else doNotRemovePtJ = 0;
2505                    }
2506                    else break;
2507                }
2508            }
2509        }
2510        // start new lines - with one not connected pt -> one more the same !!
2511        if ( myPcnt > 0 )
2512        {   int	m, rightPtI=0;
2513
2514            // check if pt row
2515            for (k=0; k<myPcnt-1; k++)
2516            {   if ( Diff(pts[k].x, pts[k+1].x) <= 1 )
2517                {   rightPtI = k+1; }
2518                else
2519                    break;
2520            }
2521            if ( rightPtI && [self pointIsEdge:pts[rightPtI]] )
2522            {
2523                lineG = [VLine line]; [lineG setSelected:YES];
2524                [lineG setColor:nxBlack]; [lineG setWidth:0];
2525                [(VLine*)lineG setVertices:pts[rightPtI] :pts[rightPtI]];
2526                [[path list] addObject:lineG];
2527                lineArray[(*lineCnt)++] = (int)[[path list] count]-1; // add line index to lineArray
2528                for (m=rightPtI; m<myPcnt-1; m++) // sort out pts[r] j from pts
2529                    pts[m] = pts[m+1];
2530                myPcnt--;
2531
2532                lineG = [VLine line];
2533                ( [self pointIsEdge:pts[rightPtI-1]] ) ? [lineG setSelected:YES] : [lineG setSelected:NO];
2534                [lineG setColor:nxBlack]; [lineG setWidth:0];
2535                [(VLine*)lineG setVertices:pts[rightPtI-1] :pts[rightPtI-1]];
2536                [[path list] addObject:lineG];
2537                lineArray[(*lineCnt)++] = (int)[[path list] count]-1; // add line index to lineArray
2538                for (m=rightPtI-1; m<myPcnt-1; m++) // sort out pts[...-1] j from pts
2539                    pts[m] = pts[m+1];
2540                myPcnt--;
2541            }
2542            else
2543            {   lineG = [VLine line]; ( [self pointIsEdge:pts[0]] ) ? [lineG setSelected:YES] : [lineG setSelected:NO];
2544                [lineG setColor:nxBlack]; [lineG setWidth:0];
2545                [(VLine*)lineG setVertices:pts[0] :pts[0]];
2546                [[path list] addObject:lineG];
2547                lineArray[(*lineCnt)++] = (int)[[path list] count]-1; // add line index to lineArray
2548                if ( [self pointIsEdge:pts[0]] )
2549                {
2550                    if ( myPcnt > 1 && Diff(pts[0].x, pts[1].x) <= 1 ) // pts[1] is second line !!!
2551                    {   for (m=0; m<myPcnt-1; m++) // sort out pts[0] j from pts
2552                            pts[m] = pts[m+1];
2553                        myPcnt--;
2554                    }
2555                    lineG = [VLine line];[lineG setSelected:YES];
2556                    [lineG setColor:nxBlack]; [lineG setWidth:0];
2557                    [(VLine*)lineG setVertices:pts[0] :pts[0]];
2558                    [[path list] addObject:lineG];
2559                    lineArray[(*lineCnt)++] = (int)[[path list] count]-1; // add line index to lineArray
2560                }
2561                for (m=0; m<myPcnt-1; m++) // sort out pts[0] j from pts
2562                    pts[m] = pts[m+1];
2563                myPcnt--;
2564            }
2565            startNewLine = 1; // we do not remove lines in second part to connect rest points
2566
2567            // sort line indexes from left line to right line
2568            for (i=0; i<(*lineCnt)-1; i++)
2569            {   VGraphic	*g1=[[path list] objectAtIndex:lineArray[i]];
2570
2571                [(VLine*)g1 getVertices:&start :&end];
2572                for (j=i+1; j<(*lineCnt); j++)
2573                {   VGraphic	*g2=[[path list] objectAtIndex:lineArray[j]];
2574
2575                    [(VLine*)g2 getVertices:&s :&e];
2576                    if ( (e.y > s.y && e.x < ((end.y > start.y) ? (end.x) : (start.x))) ||
2577                         (e.y < s.y && s.x < ((end.y > start.y) ? (end.x) : (start.x))) ||
2578                         (e.y == s.y && s.x < ((end.y > start.y) ? (end.x) : (start.x)) &&
2579                          e.x < ((end.y > start.y) ? (end.x) : (start.x))) )
2580                    {   int	bufI=lineArray[i];
2581                        lineArray[i] = lineArray[j];
2582                        lineArray[j] = bufI;
2583                        g1 = [[path list] objectAtIndex:lineArray[i]];
2584                        [(VLine*)g1 getVertices:&start :&end]; // set g1 new !
2585                    }
2586                }
2587            }
2588        }
2589        else break;
2590    }
2591}
2592
2593/* */
2594- (void)optimizePath:(VPath*)path :(int)w
2595{   int		i1, i2, changeI, startIndex=0, index2=0, yMin, iDiff, openPath = 0;
2596    float	startDistance=MAXCOORD, dist=(w*w), d1, d2, d, l1eY;
2597    float	distHalf/*=(w/2)*(w/2)*/, distQuarter;//=(w/8)*(w/8);
2598    NSPoint	l1S, l1E, l2S, l2E;
2599    VLine	*l1, *l2;
2600
2601    if ( ![[path list] count] )
2602        return;
2603
2604    distHalf = 100; distQuarter = 25; dist = 121;
2605
2606    l1 = [[path list] objectAtIndex:0];
2607    [l1 getVertices:&l1S :&l1E];
2608    yMin = l1S.y;
2609    for (i1 = 0; i1<(int)[[path list] count]-1; i1++)
2610    {	l1=[[path list] objectAtIndex:i1];
2611
2612        startDistance = MAXCOORD;
2613        changeI = i1+1;
2614        [l1 getVertices:&l1S :&l1E];
2615
2616        if ( Diff(l1S.x, l1E.x) == 0 && Diff(l1S.y, l1E.y) == 0 )
2617        {
2618            [[path list] removeObjectAtIndex:i1];
2619            if ( startIndex > i1 )
2620                startIndex--;
2621            i1 = ( startIndex == i1 ) ? (i1 - 1) : (i1 - 2);
2622            continue;
2623        }
2624        l1eY = l1E.y + distHalf;
2625        /* get index2 */
2626		index2 = i1+1;
2627        if ( !openPath && i1 > 50 && (iDiff=((int)[[path list] count]-1 - (i1+1))) > 100 )
2628        {   int	j, testI, l1eYMin = l1E.y - 10, prevTI=iDiff, diff;
2629
2630            testI = iDiff/2.0;
2631            for (j=0; j<iDiff; j++)
2632            {
2633                if ( i1+testI < i1+1 || i1+testI > (int)[[path list] count]-1)
2634                    printf("PathContour.m: -optimizePath: darf nicht sein 2\n");
2635                l2=[[path list] objectAtIndex:i1+testI];
2636                [l2 getVertices:&l2S :&l2E];
2637                if ( Max(l2S.y, l2E.y) < l1eYMin || l2S.y == yMin || l2E.y == yMin )
2638                {
2639                    if ( Diff(Max(l2S.y, l2E.y), l1E.y) < distHalf )
2640                    {   index2 = i1+testI; break; }
2641                    else if ( testI > iDiff-100 )
2642                    {   index2 = i1+testI; break; }
2643                    else // up
2644                    {   diff = Diff(prevTI, testI)/2.0;
2645                        prevTI = testI;
2646                        testI = testI + diff;
2647                    }
2648                }
2649                else if ( testI <= 50 )
2650                {   index2 = i1+1; break; }
2651                else // down
2652                {   diff = Diff(prevTI, testI)/2.0;
2653                    prevTI = testI;
2654                    testI = testI - diff;
2655                }
2656            }
2657            if ( index2 < i1+1 || index2 > (int)[[path list] count]-1 )
2658			{
2659				index2 = i1+1;
2660				printf("PathContour.m: -optimizePath: darf nicht sein\n");
2661			}
2662        }
2663
2664        for (i2=index2; i2<(int)[[path list] count]; i2++)
2665        {   VLine	*l2=[[path list] objectAtIndex:i2];
2666
2667            [l2 getVertices:&l2S :&l2E];
2668            d1 = SqrDistPoints(l1E, l2S); d2 = SqrDistPoints(l1E, l2E);
2669//            if ( (d1 <= dist && d1 < startDistance) || (d2 <= dist && d2 < startDistance) ||)
2670            if ( (d1 < startDistance || d2 < startDistance) ||
2671                ((d1 == startDistance || d2 == startDistance) && ([self pointIsEdge:l2S] || [self pointIsEdge:l2E])) )
2672            {
2673                if ( d2 < d1 )
2674                {   startDistance = d2;
2675                    [l2 setVertices:l2E :l2S]; /* change direction of l2 */
2676                }
2677                else
2678                    startDistance = d1;
2679                changeI = i2;
2680                if ( Diff(startDistance, 0.0) <= 0 )
2681                    break;
2682            }
2683            if ( l2S.y > l1eY && l2E.y > l1eY )
2684                break;
2685        }
2686        if ( startDistance ) /* close hole */
2687        {   l2 = [[path list] objectAtIndex:changeI];
2688            [(VLine*)l2 getVertices:&l2S :&l2E];
2689            if ( (d=SqrDistPoints(l1E, l2S)) && d < distQuarter )
2690            {   if ( [self pointIsEdge:l2S] ) [l1 setVertices:l1S :l2S];
2691                else [l2 setVertices:l1E :l2E];
2692				if ( openPath )
2693					openPath = 0;
2694            }
2695            else
2696            {   VLine	*l3 = [[path list] objectAtIndex:startIndex];
2697                float	d3 = SqrDistPoints(l1E, [l3 pointWithNum:0]);
2698
2699				/* close with l2 */
2700                if ( d && d <= dist && d < d3) // distance to nextG must be smaller than to startG
2701                {   VGraphic	*lineG = [VLine line];
2702                    NSColor	*nxBlack=[NSColor colorWithCalibratedRed:0.0 green:0.0 blue:0.0 alpha:1.0];
2703
2704                    [lineG setColor:nxBlack]; [lineG setWidth:0]; [lineG setSelected:NO];
2705                    [(VLine*)lineG setVertices:l1E :l2S];
2706                    [[path list] insertObject:lineG atIndex:i1+1];
2707                    i1 += 1; changeI += 1;
2708                }
2709                else if ( i1-startIndex == 0 )
2710                {
2711                    /* one single Graphic */
2712                    [[path list] removeObjectAtIndex:i1];
2713                    i1 --;
2714                    continue;
2715                }
2716				/* closeTo startG */
2717                else if ( d3 < d && d3 < distQuarter) // close to startG
2718                {   if ( [self pointIsEdge:[l3 pointWithNum:0]] ) [l1 setVertices:l1S :[l3 pointWithNum:0]];
2719                    else [l3 setVertices:l1E :[l3 pointWithNum:MAXINT]];
2720                    startIndex = i1+1;
2721                }
2722                else if ( d3 < d && d3 < dist) // close to startG
2723                {   VGraphic	*lineG = [VLine line];
2724                    NSColor	*nxBlack=[NSColor colorWithCalibratedRed:0.0 green:0.0 blue:0.0 alpha:1.0];
2725
2726					[lineG setColor:nxBlack]; [lineG setWidth:0]; [lineG setSelected:NO];
2727					[(VLine*)lineG setVertices:l1E :[l3 pointWithNum:0]];
2728					[[path list] insertObject:lineG atIndex:i1+1];
2729					i1 += 1; changeI += 1;
2730                    startIndex = i1+1;
2731                }
2732                else if (d3 < d && d < dist)
2733                    startIndex = i1+1;
2734                else if ( i1-startIndex == 1 )
2735                {
2736                    /* two graphics which cant be closed */
2737                    [[path list] removeObjectAtIndex:i1];
2738                    i1--;
2739                    [[path list] removeObjectAtIndex:i1];
2740                    i1 --;
2741                    continue;
2742                }
2743				else if ( openPath && d3 < d ) // close to StartG
2744				{   VGraphic	*lineG = [VLine line];
2745                    NSColor	*nxBlack=[NSColor colorWithCalibratedRed:0.0 green:0.0 blue:0.0 alpha:1.0];
2746
2747                    [lineG setColor:nxBlack]; [lineG setWidth:0]; [lineG setSelected:NO];
2748                    [(VLine*)lineG setVertices:l1E :[l3 pointWithNum:0]];
2749                    [[path list] insertObject:lineG atIndex:i1+1];
2750                    i1 += 1; changeI += 1;
2751                    startIndex = i1+1;
2752					openPath = 0;
2753                }
2754				else if ( openPath && d < d3 ) // close to l2
2755				{   VGraphic	*lineG = [VLine line];
2756                    NSColor	*nxBlack=[NSColor colorWithCalibratedRed:0.0 green:0.0 blue:0.0 alpha:1.0];
2757
2758                    [lineG setColor:nxBlack]; [lineG setWidth:0]; [lineG setSelected:NO];
2759                    [(VLine*)lineG setVertices:l1E :l2S];
2760                    [[path list] insertObject:lineG atIndex:i1+1];
2761                    i1 += 1; changeI += 1;
2762					openPath = 0;
2763                }
2764				else if ( !openPath && d > dist && d3 > dist )
2765				{	openPath++;
2766					i1--;
2767					continue;
2768				}
2769            }
2770//            if ( !openPath && startDistance > dist )
2771//                startIndex = i1+1;
2772        }
2773		else if ( openPath )
2774			openPath = 0;
2775        /* if the nearest element is not the next_in_list */
2776        if ( changeI != (i1+1) )
2777        {   VGraphic	*gCh=[[path list] objectAtIndex:changeI];
2778
2779            [[path list] removeObject:gCh];
2780            [[path list] insertObject:gCh atIndex:i1+1];
2781        }
2782    }
2783    /* close hole from last to start element */
2784    {   l1=[[path list] objectAtIndex:(int)[[path list] count]-1];
2785        l2= [[path list] objectAtIndex:startIndex];
2786
2787        if ( [[path list] count]-startIndex == 1 )
2788            [[path list] removeObjectAtIndex:(int)[[path list] count]-1];
2789        else
2790        {
2791            [l1 getVertices:&l1S :&l1E];
2792            [l2 getVertices:&l2S :&l2E];
2793            if ( (d=SqrDistPoints(l1E, l2S)) && d < distQuarter )
2794            {   if ( [self pointIsEdge:l2S] ) [l1 setVertices:l1S :l2S];
2795                else [l2 setVertices:l1E :l2E];
2796            }
2797            else if ( d /*&& d <= dist*/ )
2798            {   VGraphic	*lineG = [VLine line];
2799                NSColor	*nxBlack=[NSColor colorWithCalibratedRed:0.0 green:0.0 blue:0.0 alpha:1.0];
2800
2801                [lineG setColor:nxBlack]; [lineG setWidth:0]; [lineG setSelected:NO];
2802                [(VLine*)lineG setVertices:l1E :l2S];
2803                [[path list] addObject:lineG];
2804            }
2805        }
2806    }
2807    /* unite lines with same gradients */
2808    [self smoothenLinesInPath:path];
2809    [self smoothenLinesInPath:path];
2810    [self uniteLinesWithSameGradient:path :w];
2811
2812    return;
2813}
2814
2815/*
2816 * modified: 2010-03-03 (setDirectionCCW:)
2817 *           2008-02-08
2818 * get contour of path using a bitmap algorithm
2819 * return the calculated path
2820 */
2821- (VPath*)contourPath:(VPath*)oPath width:(float)width
2822{   VPath               *path, *oPathCopy;
2823    NSRect              conRect, bounds, rect;
2824    id                  win, conView;
2825    float               w=width+[oPath width], w2, bytes, scale = 1, maxBytes = 110250000, wi, h, s;
2826    int                 x, y, right, height, start, w2Int, bytesPerRowHalf, quality = 2;
2827    NSColor             *nxWhite, *nxBlack;
2828    NSPoint             moveP, center;
2829    NSBitmapImageRep	*bitmapImage;
2830
2831#if DEBUG_CONTUR
2832    NSColor		*nxGray;
2833    nxGray = [NSColor colorWithCalibratedRed:0.335 green:0.335 blue:0.335 alpha:1.0];
2834printf("%s Hour.Min.Sec Start\n", [[[NSCalendarDate date] descriptionWithCalendarFormat:@"%H.%M.%S"] cString]);
2835#endif
2836
2837    nxBlack = [NSColor colorWithCalibratedRed:0.0 green:0.0 blue:0.0 alpha:1.0];
2838    nxWhite = [NSColor colorWithCalibratedRed:1.0 green:1.0 blue:1.0 alpha:1.0];
2839
2840    path = [VPath path];
2841    [path setColor:[oPath color]];
2842    [path setFilled:NO];
2843    [path setWidth:0];
2844    [path setSelected:NO];
2845
2846    if ( !w )
2847        return path;
2848
2849    /* copy self make it white */
2850    oPathCopy = [oPath copy];
2851    [oPathCopy setFilled:YES];
2852    [oPathCopy setWidth:0];
2853
2854    /* calc content rect size / scale factor
2855     * to get not more than 20 MB memory
2856     * the bounds of the path: width*height / 8(bit) * 2(color deepnes)
2857     */
2858    bounds = [oPathCopy bounds];
2859    wi = conRect.size.width = bounds.size.width + 4*Abs(w);
2860    h = conRect.size.height = bounds.size.height + 4*Abs(w); /* need a little space for our contour */
2861
2862    /* need a minimum scale of */
2863    scale = s = 1.0;
2864    conRect.size.width = wi*scale; conRect.size.height = h*scale;	/* last guilty values */
2865    bytes = (wi*scale) * (h*scale);
2866    w2 = Abs(w)*scale/2.0;
2867
2868    while ( bytes < maxBytes && s < 50 /*&& conRect.size.width < 10000 && conRect.size.height < 10000*/ )
2869    {
2870        scale = s;
2871        w2 = Abs(w)*scale/2.0;
2872        conRect.size.width = wi*scale; conRect.size.height = h*scale;	/* last guilty values */
2873        if ( (quality == 2 && w2 > 40) || (quality == 1 && w2 > 30) || (!quality && w2 > 20) ) // 20
2874            break; /* stop scale is great enough */
2875
2876        s += 1.0;
2877        bytes = (wi*s) * (h*s); // 1 byte is one pixel;
2878        if ( wi*s > 10000 || h*s > 10000 )
2879            break; // too big !!!
2880    }
2881    if ( conRect.size.width > 10000 || conRect.size.height > 10000 ) // good bye
2882    {    [oPathCopy release]; return path; }
2883
2884    /* need our half width/minWidth in pixel and scaled */
2885    if ( (w2-((int)w2)) > 0.5 )
2886    {	w2Int = w2 + 1;
2887        conRect.size.width += 6.0; conRect.size.height += 6.0;
2888    }
2889    else
2890    {	w2Int = w2;
2891        conRect.size.width += 4.0; conRect.size.height += 4.0;
2892    }
2893    conRect.origin.x = conRect.origin.y = 10.0;
2894
2895    /* scale oPathCopy */
2896    center.x = bounds.origin.x + bounds.size.width/2.0;
2897    center.y = bounds.origin.y + bounds.size.height/2.0;
2898    [oPathCopy scale:scale :scale withCenter:center];
2899    bounds = [oPathCopy bounds];
2900
2901    /* move oPathCopy to ~0 */
2902    moveP.x = -(bounds.origin.x - 4*w2Int - 2.0);
2903    moveP.y = -(bounds.origin.y - 4*w2Int - 2.0);
2904    [oPathCopy moveBy:moveP];
2905
2906    /* build an offscreen window
2907     * in which we draw the scaled black copy of original path on white background NSBackingStoreBuffered NSBackingStoreRetained
2908     */
2909    win = [[NSWindow alloc] initWithContentRect:conRect styleMask:NSBorderlessWindowMask backing:NSBackingStoreRetained defer:NO];
2910    [win setDynamicDepthLimit:NO];
2911    [win setDepthLimit:NSBestDepth(NSCalibratedWhiteColorSpace, 8, 8, YES, NULL)];
2912//[win setDepthLimit:NSBestDepth(NSCalibratedRGBColorSpace, 8, 24, NO, NULL)]; // test apple
2913
2914    [win setBackgroundColor:( w < 0 ) ? [NSColor grayColor] : [NSColor blackColor]];
2915#if DEBUG_CONTUR
2916[win makeKeyAndOrderFront:self]; /* weglassen wenn nicht gesehen werden soll */
2917#endif
2918    conView = [win contentView];
2919    [conView display];
2920
2921    /* now draw our white scaled path in view
2922     */
2923    [conView lockFocus];
2924
2925#ifdef __APPLE__
2926[[NSGraphicsContext currentContext] setShouldAntialias:NO];
2927#endif
2928
2929    [oPathCopy setFillColor:( w > 0 ) ? [NSColor grayColor] : nxWhite];
2930    [oPathCopy drawWithPrincipal:nil];
2931
2932    // w < 0 -> contour inside path
2933    // w > 0 -> contour outside path
2934    // w == 0 -> white filled black Background
2935    if (w)
2936    {
2937        [oPathCopy setColor:(w < 0) ? nxBlack : nxWhite];
2938        [oPathCopy setFilled:NO];
2939        [oPathCopy setWidth:w2Int*2.0];
2940        [oPathCopy drawWithPrincipal:nil];
2941    }
2942    /* force 8 bit gray -> we must draw one thing gray */
2943    {   VRectangle	*r=[VRectangle rectangle];
2944
2945        [r setVertices:NSMakePoint(1.0,1.0) :NSMakePoint(1.0,1.0)];
2946        [r setFillColor:[NSColor grayColor]];
2947        [r setFilled:YES];
2948        [r drawWithPrincipal:nil];
2949    }
2950    /* get pixel information into data (char string) */
2951    rect.origin = NSZeroPoint;
2952    right = rect.size.width = (int)(conRect.size.width); /* our with scale and bounds calculated width */
2953    height = rect.size.height = (int)(conRect.size.height);
2954
2955//[[NSColor redColor] set]; // test apple
2956//NSRectFill(NSMakeRect(1, 1, 1, 1));
2957
2958    bitmapImage = [[NSBitmapImageRep allocWithZone:[self zone]] initWithFocusedViewRect:rect];
2959
2960    // apple
2961    if ([bitmapImage bitsPerPixel] > 8 || ![bitmapImage isPlanar] || [bitmapImage samplesPerPixel] > 1)
2962    {	NSBitmapImageRep	*abitmap;
2963
2964        if ([bitmapImage bitsPerSample] == 8) // meshed
2965        {   int			ny, width;
2966            int			bpr = [bitmapImage bytesPerRow], spp = 1, abpr;
2967            int			bpp = [bitmapImage bytesPerPlane];
2968            unsigned char	*planes[5];
2969
2970            abitmap = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
2971                                                              pixelsWide:rect.size.width
2972                                                              pixelsHigh:rect.size.height
2973                                                           bitsPerSample:8
2974                                                         samplesPerPixel:1
2975                                                                hasAlpha:NO isPlanar:YES
2976                                                          colorSpaceName:NSCalibratedWhiteColorSpace
2977                                                             bytesPerRow:rect.size.width
2978                                                            bitsPerPixel:8];
2979
2980            data = [abitmap bitmapData];
2981            abpr = [abitmap bytesPerRow];
2982            [bitmapImage getBitmapDataPlanes:planes];
2983
2984            if (![bitmapImage isPlanar])
2985                spp = [bitmapImage bitsPerPixel]/8;
2986            width = bpr / spp; // bytesPerRow / samplesPerPixel
2987            for (y=0, ny=0; y<bpp; y+=bpr, ny+=abpr)
2988            {
2989                for (x=0; x<width; x++)
2990                {
2991                    *((LONG*)(data+ny+x)) = *((LONG*)(planes[0]+y+x*spp));
2992                }
2993            }
2994        }
2995        else
2996        {   [conView unlockFocus];
2997            [win close];
2998            [bitmapImage release];
2999            [oPathCopy release];
3000            return path;
3001        }
3002        [bitmapImage release];
3003        bitmapImage = abitmap;
3004    }
3005    size = [bitmapImage bytesPerPlane];
3006    data = [bitmapImage bitmapData];
3007    bytesPerRow = [bitmapImage bytesPerRow];
3008    bytesPerRowHalf = bytesPerRow/2.0;
3009    {   int	lineArray[bytesPerRowHalf], lineCnt = 0;
3010        NSPoint	*pts;
3011        pts = malloc(right * sizeof(NSPoint));
3012
3013    /* set loop parameters */
3014    right -= (2*w2Int+1);
3015    height -= (2*w2Int+1);
3016
3017#if DEBUG_CONTUR
3018[nxGray set];
3019#endif
3020
3021    /* vectorize contour */
3022    start = 2*w2Int+1;
3023    for (y=start; y<height; y++)
3024    {   int		pCnt=0, byteY, byteX;
3025
3026        byteY = y * bytesPerRow;	/* the height */
3027        byteY = size - byteY - bytesPerRow;
3028        for (x=start; x<right && byteY+x+19 < size; x++)
3029        {
3030            byteX = byteY+x;
3031            if ( *((LONG*)(data+byteX)) == black )
3032            {   if ( *((LONG*)(data+byteX+4)) == black )
3033                {   if ( *((LONG*)(data+byteX+8)) == black )
3034                    {   if ( *((LONG*)(data+byteX+12)) == black )
3035                        {   if ( *((LONG*)(data+byteX+16)) == black )
3036                            {   x += 16; continue; }
3037                            else {   x += 12; continue; }
3038                        }
3039                        else {   x += 8; continue; }
3040                    }
3041                    else {   x += 4; continue; }
3042                }
3043                else {   continue; }
3044            }
3045            else if ( *((LONG*)(data+byteX-bytesPerRow-1)) == -1 && *((LONG*)(data+byteX-1)) == -1 &&
3046                          *((LONG*)(data+byteX+bytesPerRow-1)) == -1 )
3047            {
3048                if ( *((LONG*)(data+byteX-bytesPerRow+3)) == -1 && *((LONG*)(data+byteX+3)) == -1 &&
3049                    *((LONG*)(data+byteX+bytesPerRow+3)) == -1 )
3050                {
3051                    if ( *((LONG*)(data+byteX-bytesPerRow+7)) == -1 && *((LONG*)(data+byteX+7)) == -1 &&
3052                        *((LONG*)(data+byteX+bytesPerRow+7)) == -1 )
3053                    {
3054                        if ( *((LONG*)(data+byteX-bytesPerRow+11)) == -1 && *((LONG*)(data+byteX+11)) == -1 &&
3055                            *((LONG*)(data+byteX+bytesPerRow+11)) == -1 )
3056                        {
3057                            if ( *((LONG*)(data+byteX-bytesPerRow+15)) == -1 && *((LONG*)(data+byteX+15)) == -1 &&
3058                                *((LONG*)(data+byteX+bytesPerRow+15)) == -1 )
3059                            {
3060                                if ( *((LONG*)(data+byteX-bytesPerRow+19)) == -1 && *((LONG*)(data+byteX+19)) == -1 &&
3061                                    *((LONG*)(data+byteX+bytesPerRow+19)) == -1 )
3062                                {   x += 19; continue; }
3063                                else {   x += 15; continue; }
3064                            }
3065                            else {   x += 11; continue; }
3066                        }
3067                        else {   x += 7; continue; }
3068                    }
3069                    else { x += 3; continue; }
3070                }
3071                else {   continue; }
3072            }
3073            if ( *(data+byteX) != white )
3074                continue;
3075            /* l d r u is a black pixel -> one of our pixels */
3076            if ( *(data+byteX-1) == black || *(data+byteX+bytesPerRow) == black ||
3077                *(data+byteX+1) == black || *(data+byteX-bytesPerRow) == black )
3078            {   NSPoint	nxp = {x, y};
3079                pts[pCnt] = nxp;
3080                pCnt++;
3081//#if DEBUG_CONTUR
3082//NSRectFill(NSMakeRect(x, y, 1, 1));
3083//#endif
3084            }
3085        }
3086        if ( pCnt )
3087            [self buildPath:path :pts :pCnt :w :lineArray :&lineCnt];
3088    }
3089    free(pts);
3090    } // lineArray, lineCnt
3091#if DEBUG_CONTUR
3092printf("%s Hour.Min.Sec vor Optimieren\n", [[[NSCalendarDate date] descriptionWithCalendarFormat:@"%H.%M.%S"] cString]);
3093#endif
3094
3095    /* correct path */
3096    /*if ( [[path list] count] )
3097    {   for (x=(int)[[path list] count]-1; x>=0; x--)
3098        {   VGraphic	*lineG = [[path list] objectAtIndex:x]; // nach opt - nur singles !
3099            NSPoint	start, end;
3100            [(VLine*)lineG getVertices:&start :&end];
3101            if ( //(![lineG isSelected] && Diff(start.x, end.x) <= 2 && Diff(start.y, end.y) <= 2) ||
3102                (Diff(start.x, end.x) <= 1 && Diff(start.y, end.y) <= 1) )
3103                [[path list] removeObjectAtIndex:x];
3104        }
3105    }*/
3106    [self optimizePath:path :w2Int];
3107
3108    /* move and scale path to old great */
3109    moveP.x = -moveP.x; moveP.y = -moveP.y;
3110    [path moveBy:moveP];
3111    scale = 1/scale;
3112    [path scale:scale :scale withCenter:center];
3113
3114
3115#if 0
3116{ int i;
3117  NSPoint s, e;
3118
3119  printf("VPath\n");
3120    for (i=0; i<[[path list] count]; i++)
3121    {	Line	*l1=[[path list] objectAtIndex:i];
3122
3123        [l1 getVertices:&s :&e];
3124        printf("%.2f s.x\t %.2f s.y\t %.2f e.x\t %.2f e.y\n", s.x, s.y, e.x, e.y);
3125    }
3126  printf("\n3DLinePath\n");
3127    for (i=0; i<[[linePath list] count]; i++)
3128    {	VLine3D	*l1=[[linePath list] objectAtIndex:i];
3129
3130        [l1 getVertices:&s :&e];
3131        printf("%.2f s.x\t %.2f s.y\t %.2f e.x\t %.2f e.y\n", s.x, s.y, e.x, e.y);
3132    }
3133}
3134#endif
3135    [conView unlockFocus];
3136    [win close];
3137    [bitmapImage release];
3138    [oPathCopy release];
3139#if DEBUG_CONTUR
3140printf("%s Hour.Min.Sec End\n\n", [[[NSCalendarDate date] descriptionWithCalendarFormat:@"%H.%M.%S"] cString]);
3141#endif
3142    [path setDirectionCCW:[oPath isDirectionCCW]];
3143    return path;
3144}
3145
3146- (VPath*)contourImage:(VImage*)image width:(float)width
3147{   VPath               *path;
3148    NSRect              conRect, bounds, rect;
3149    NSSize              imageSize;
3150    id                  win, conView;
3151    float               w=width, w2, scaleX = 1, scaleY = 1;
3152    int                 x, y, right, height, start, w2Int, bytesPerRowHalf;
3153    NSColor             *nxBlack;
3154    NSPoint             moveP, center;
3155    NSBitmapImageRep    *bitmapImage;
3156    unsigned char       color, *data2;
3157#if DEBUG_CONTUR
3158    NSColor             *nxGray, *nxWhite;
3159    nxGray = [NSColor colorWithCalibratedRed:0.335 green:0.335 blue:0.335 alpha:1.0];
3160    nxWhite = [NSColor colorWithCalibratedRed:1.0 green:1.0 blue:1.0 alpha:1.0];
3161    printf("%s Hour.Min.Sec Start\n", [[[NSCalendarDate date] descriptionWithCalendarFormat:@"%H.%M.%S"] cString]);
3162#endif
3163
3164    nxBlack = [NSColor colorWithCalibratedRed:0.0 green:0.0 blue:0.0 alpha:1.0];
3165
3166    path = [VPath path];
3167    [path setColor:nxBlack];
3168    [path setFilled:NO];
3169    [path setWidth:0];
3170    [path setSelected:NO];
3171
3172//    if ( !w )
3173//        return path;
3174
3175    /* get bouns of image size and original size */
3176    bounds.size = [image originalSize];
3177    bounds.origin = [image origin];
3178
3179    imageSize = [image size];
3180    scaleX = bounds.size.width/imageSize.width;
3181    scaleY = bounds.size.height/imageSize.height;
3182
3183    /* need our half width/minWidth in pixel and scaled */
3184    ( scaleX < scaleY ) ? (w2 = Abs(w)*scaleX/2.0) : (w2 = Abs(w)*scaleY/2.0);
3185
3186    ( (w2-((int)w2)) > 0.5 ) ? (w2Int = w2 + 1) : (w2Int = w2);
3187//    if ( !w2Int ) w2Int = 1;
3188
3189    if ( w2Int > 46 ) // must scale origninalSize -> to hold the Verhaeltnisse
3190    {
3191        while ( w2Int > 46 )
3192        {
3193            scaleX -= 1.0; scaleY -= 1.0;
3194            ( scaleX < scaleY ) ? (w2 = Abs(w)*scaleX/2.0) : (w2 = Abs(w)*scaleY/2.0);
3195            ( (w2-((int)w2)) > 0.5 ) ? (w2Int = w2 + 1) : (w2Int = w2);
3196        }
3197        bounds.size.width = imageSize.width*scaleX;
3198        bounds.size.height = imageSize.height*scaleY;
3199    }
3200    conRect.size.width = bounds.size.width + 2*w2Int + 20;
3201    conRect.size.height = bounds.size.height + 2*w2Int + 20; /* need a little space for our contour */
3202    conRect.origin.x = conRect.origin.y = w2Int+10.0;
3203
3204    if ( conRect.size.width > 10000 || conRect.size.height > 10000 ) // good bye
3205         return path;
3206
3207    /* build an offscreen window
3208     * in which we draw the scaled black copy of original path on white background NSBackingStoreBuffered NSBackingStoreRetained
3209     */
3210    win = [[NSWindow alloc] initWithContentRect:conRect styleMask:NSBorderlessWindowMask backing:NSBackingStoreRetained defer:NO];
3211    [win setDynamicDepthLimit:NO];
3212    [win setDepthLimit:NSBestDepth(NSCalibratedWhiteColorSpace, 8, 8, YES, NULL)];
3213
3214    [win setBackgroundColor:[NSColor whiteColor]];
3215#if DEBUG_CONTUR
3216[win makeKeyAndOrderFront:self]; /* weglassen wenn nicht gesehen werden soll */
3217#endif
3218    conView = [win contentView];
3219    [conView display];
3220
3221    /* get copy of image */
3222    [[image image] setSize:bounds.size];
3223
3224    /* now draw our black scaled path in view
3225     */
3226    [conView lockFocus];
3227#ifdef __APPLE__
3228[[NSGraphicsContext currentContext] setShouldAntialias:NO];
3229#endif
3230    [[image image] compositeToPoint:conRect.origin operation:NSCompositeSourceOver]; // NSCompositeCopy
3231
3232    /* get pixel information into data (char string) */
3233    rect.origin = NSZeroPoint;
3234    right = rect.size.width = (int)(conRect.size.width); /* our with scale and bounds calculated width */
3235    height = rect.size.height = (int)(conRect.size.height);
3236
3237    [[NSColor grayColor] set]; NSRectFill(NSMakeRect(2, 2, 1, 1)); // hack to force 8 bit gray bitmap
3238    bitmapImage = [[NSBitmapImageRep allocWithZone:[self zone]] initWithFocusedViewRect:rect];
3239    // apple
3240    if ([bitmapImage bitsPerPixel] > 8 || ![bitmapImage isPlanar] || [bitmapImage samplesPerPixel] > 1)
3241    {	NSBitmapImageRep	*abitmap;
3242
3243        if ([bitmapImage bitsPerSample] == 8) // meshed
3244        {   int             ny, width;
3245            int             bpr = [bitmapImage bytesPerRow], spp = 1, abpr;
3246            int             bpp = [bitmapImage bytesPerPlane];
3247            unsigned char   *planes[5];
3248
3249            abitmap = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
3250                                                              pixelsWide:rect.size.width
3251                                                              pixelsHigh:rect.size.height
3252                                                           bitsPerSample:8
3253                                                         samplesPerPixel:1
3254                                                                hasAlpha:NO isPlanar:YES
3255                                                          colorSpaceName:NSCalibratedWhiteColorSpace
3256                                                             bytesPerRow:rect.size.width
3257                                                            bitsPerPixel:8];
3258
3259            data = [abitmap bitmapData];
3260            abpr = [abitmap bytesPerRow];
3261            [bitmapImage getBitmapDataPlanes:planes];
3262
3263            if (![bitmapImage isPlanar])
3264                spp = [bitmapImage bitsPerPixel]/8;
3265            width = bpr / spp; // bytesPerRow / samplesPerPixel
3266            for (y=0, ny=0; y<bpp; y+=bpr, ny+=abpr)
3267            {
3268                for (x=0; x<width; x++)
3269                {
3270                    *((LONG*)(data+ny+x)) = *((LONG*)(planes[0]+y+x*spp));
3271                }
3272            }
3273        }
3274        else
3275        {   [conView unlockFocus];
3276            [win close];
3277            [bitmapImage release];
3278            return path;
3279        }
3280        [bitmapImage release];
3281        bitmapImage = abitmap;
3282    }
3283    size = [bitmapImage bytesPerPlane];
3284    data = [bitmapImage bitmapData];
3285    bytesPerRow = [bitmapImage bytesPerRow];
3286
3287    /* set loop parameters */
3288    right -= 10.0;
3289    height -= 10.0;
3290
3291#if DEBUG_CONTUR
3292[nxBlack set];
3293#endif
3294
3295    // set not white bytes to black !!!!!!!!!!
3296    start = 10.0; // (gdb) x/100tb data
3297    for (y=start; y<height; y++)
3298    {   int	byteY, byteX;
3299
3300        byteY = size - (y * bytesPerRow) - bytesPerRow; /* the height */
3301
3302        for (x=start; x<right && byteY+x+19 < size; x++)
3303        {
3304            byteX = byteY+x;
3305            if ( *((LONG*)(data+byteX)) == -1 )
3306            {   if ( *((LONG*)(data+byteX+4)) == -1 )
3307                {   if ( *((LONG*)(data+byteX+8)) == -1 )
3308                    {   if ( *((LONG*)(data+byteX+12)) == -1 )
3309                        {   if ( *((LONG*)(data+byteX+16)) == -1 )
3310                            {   x += 16; continue; }
3311                            else {   x += 12; continue; }
3312                        }
3313                        else {   x += 8; continue; }
3314                    }
3315                    else {   x += 4; continue; }
3316                }
3317                else {   continue; }
3318            }
3319            else if ( *((LONG*)(data+byteX-bytesPerRow-1)) == black && *((LONG*)(data+byteX-1)) == black &&
3320                          *((LONG*)(data+byteX+bytesPerRow-1)) == black )
3321            {
3322                if ( *((LONG*)(data+byteX-bytesPerRow+3)) == black && *((LONG*)(data+byteX+3)) == black &&
3323                    *((LONG*)(data+byteX+bytesPerRow+3)) == black )
3324                {
3325                    if ( *((LONG*)(data+byteX-bytesPerRow+7)) == black && *((LONG*)(data+byteX+7)) == black &&
3326                        *((LONG*)(data+byteX+bytesPerRow+7)) == black )
3327                    {
3328                        if ( *((LONG*)(data+byteX-bytesPerRow+11)) == black && *((LONG*)(data+byteX+11)) == black &&
3329                            *((LONG*)(data+byteX+bytesPerRow+11)) == black )
3330                        {
3331                            if ( *((LONG*)(data+byteX-bytesPerRow+15)) == black && *((LONG*)(data+byteX+15)) == black &&
3332                                *((LONG*)(data+byteX+bytesPerRow+15)) == black )
3333                            {
3334                                if ( *((LONG*)(data+byteX-bytesPerRow+19)) == black && *((LONG*)(data+byteX+19)) == black
3335                                    && *((LONG*)(data+byteX+bytesPerRow+19)) == black )
3336                                {   x += 19; continue; }
3337                                else {   x += 15; continue; }
3338                            }
3339                            else {   x += 11; continue; }
3340                        }
3341                        else {   x += 7; continue; }
3342                    }
3343                    else { x += 3; continue; }
3344                }
3345                else {   continue; }
3346            }
3347            if ( *(data+byteX) != white )
3348            {
3349                if ( *(data+byteX) >= whiteStop )
3350                    *(data+byteX) = white; // the color does nt matter
3351                else
3352                    *(data+byteX) = black; // the color does nt matter
3353#if DEBUG_CONTUR
3354//NSRectFill(NSMakeRect(x, y, 1, 1));
3355#endif
3356            }
3357        }
3358    }
3359    // w < 0 -> contour inside path
3360    // w > 0 -> contour outside path
3361//    ( w < 0 ) ? (color = black) : (color = white);
3362    ( w < 0 ) ? (color = white) : (color = black);
3363
3364    data2 = malloc(size * sizeof(unsigned char));
3365    data2 = memcpy(data2, data, size); // copy !! allways the same !!!
3366
3367#if DEBUG_CONTUR
3368if ( w < 0 ) [nxWhite set]; else [nxBlack set];
3369[nxGray set];
3370#endif
3371    start = 10.0; // (gdb) x/100tb data
3372    for (y=start; y<height && w2Int; y++)
3373    {   int	byteY, byteX;
3374
3375        byteY = size - (y * bytesPerRow) - bytesPerRow; /* the height */
3376
3377        for (x=start; x<right && byteY+x+19 < size; x++)
3378        {
3379            byteX = byteY+x;
3380            if ( *((LONG*)(data2+byteX)) == -1 )
3381            {   if ( *((LONG*)(data2+byteX+4)) == -1 )
3382                {   if ( *((LONG*)(data2+byteX+8)) == -1 )
3383                    {   if ( *((LONG*)(data2+byteX+12)) == -1 )
3384                        {   if ( *((LONG*)(data2+byteX+16)) == -1 )
3385                            {   x += 16; continue; }
3386                            else {   x += 12; continue; }
3387                        }
3388                        else {   x += 8; continue; }
3389                    }
3390                    else {   x += 4; continue; }
3391                }
3392                else {   continue; }
3393            }
3394//#if 0
3395            else if ( *((LONG*)(data2+byteX-bytesPerRow-1)) == black && *((LONG*)(data2+byteX-1)) == black &&
3396                          *((LONG*)(data2+byteX+bytesPerRow-1)) == black )
3397            {
3398                if ( *((LONG*)(data2+byteX-bytesPerRow+3)) == black && *((LONG*)(data2+byteX+3)) == black &&
3399                    *((LONG*)(data2+byteX+bytesPerRow+3)) == black )
3400                {
3401                    if ( *((LONG*)(data2+byteX-bytesPerRow+7)) == black && *((LONG*)(data2+byteX+7)) == black &&
3402                        *((LONG*)(data2+byteX+bytesPerRow+7)) == black )
3403                    {
3404                        if ( *((LONG*)(data2+byteX-bytesPerRow+11)) == black && *((LONG*)(data2+byteX+11)) == black &&
3405                            *((LONG*)(data2+byteX+bytesPerRow+11)) == black )
3406                        {
3407                            if ( *((LONG*)(data2+byteX-bytesPerRow+15)) == black && *((LONG*)(data2+byteX+15)) == black &&
3408                                *((LONG*)(data2+byteX+bytesPerRow+15)) == black )
3409                            {
3410                                if ( *((LONG*)(data2+byteX-bytesPerRow+19)) == black && *((LONG*)(data2+byteX+19)) == black
3411                                    && *((LONG*)(data2+byteX+bytesPerRow+19)) == black )
3412                                {   x += 19; continue; }
3413                                else {   x += 15; continue; }
3414                            }
3415                            else {   x += 11; continue; }
3416                        }
3417                        else {   x += 7; continue; }
3418                    }
3419                    else { x += 3; continue; }
3420                }
3421                else {   continue; }
3422            }
3423//#endif
3424            if ( *(data2+byteX) == white )
3425                continue;
3426            /* l d r u is a black pixel -> one of our pixels */
3427            if ( *(data2+byteX-1) == white || *(data2+byteX+bytesPerRow) == white ||
3428                *(data2+byteX+1) == white || *(data2+byteX-bytesPerRow) == white )
3429            {
3430                [self drawArcInDataAt:(byteY+x) radius:w2Int color:color];
3431#if DEBUG_CONTUR
3432PSarc(x, y, w2Int, 0.0, 360.0); PSfill();
3433#endif
3434            }
3435        }
3436    }
3437    free(data2);
3438
3439    [self invertData];
3440
3441    bytesPerRowHalf = bytesPerRow/2.0;
3442    {   int	lineArray[bytesPerRowHalf], lineCnt = 0;
3443        NSPoint	*pts;
3444        pts = malloc(right * sizeof(NSPoint));
3445
3446#if DEBUG_CONTUR
3447[nxBlack set];
3448#endif
3449        /* vectorize contour */
3450        start = 10.0;
3451        for (y=start; y<height; y++)
3452        {   int		pCnt=0, byteY, byteX;
3453
3454            byteY = y * bytesPerRow;	/* the height */
3455            byteY = size - byteY - bytesPerRow;
3456            for (x=start; x<right; x++)
3457            {
3458                byteX = byteY+x;
3459                if ( *((LONG*)(data+byteX)) == black )
3460                {   if ( *((LONG*)(data+byteX+4)) == black )
3461                    {   if ( *((LONG*)(data+byteX+8)) == black )
3462                        {   if ( *((LONG*)(data+byteX+12)) == black )
3463                            {   if ( *((LONG*)(data+byteX+16)) == black )
3464                                {   x += 16; continue; }
3465                                else {   x += 12; continue; }
3466                            }
3467                            else {   x += 8; continue; }
3468                        }
3469                        else {   x += 4; continue; }
3470                    }
3471                    else {   continue; }
3472                }
3473                else if ( *((LONG*)(data+byteX-bytesPerRow-1)) == -1 && *((LONG*)(data+byteX-1)) == -1 &&
3474                            *((LONG*)(data+byteX+bytesPerRow-1)) == -1 )
3475                {
3476                    if ( *((LONG*)(data+byteX-bytesPerRow+3)) == -1 && *((LONG*)(data+byteX+3)) == -1 &&
3477                        *((LONG*)(data+byteX+bytesPerRow+3)) == -1 )
3478                    {
3479                        if ( *((LONG*)(data+byteX-bytesPerRow+7)) == -1 && *((LONG*)(data+byteX+7)) == -1 &&
3480                            *((LONG*)(data+byteX+bytesPerRow+7)) == -1 )
3481                        {
3482                            if ( *((LONG*)(data+byteX-bytesPerRow+11)) == -1 && *((LONG*)(data+byteX+11)) == -1 &&
3483                                *((LONG*)(data+byteX+bytesPerRow+11)) == -1 )
3484                            {
3485                                if ( *((LONG*)(data+byteX-bytesPerRow+15)) == -1 && *((LONG*)(data+byteX+15)) == -1 &&
3486                                    *((LONG*)(data+byteX+bytesPerRow+15)) == -1 )
3487                                {
3488                                    if ( *((LONG*)(data+byteX-bytesPerRow+19)) == -1 && *((LONG*)(data+byteX+19)) == -1 &&
3489                                        *((LONG*)(data+byteX+bytesPerRow+19)) == -1 )
3490                                    {   x += 19; continue; }
3491                                    else {   x += 15; continue; }
3492                                }
3493                                else {   x += 11; continue; }
3494                            }
3495                            else {   x += 7; continue; }
3496                        }
3497                        else { x += 3; continue; }
3498                    }
3499                    else {   continue; }
3500                }
3501                if ( *(data+byteX) != white )
3502                    continue;
3503                /* l d r u is a black pixel -> one of our pixels */
3504                if ( *(data+byteX-1) == black || *(data+byteX+bytesPerRow) == black ||
3505                    *(data+byteX+1) == black || *(data+byteX-bytesPerRow) == black )
3506                {   NSPoint	nxp = {x, y};
3507                    pts[pCnt] = nxp;
3508                    pCnt++;
3509#if DEBUG_CONTUR
3510//NSRectFill(NSMakeRect(x, y, 1, 1));
3511#endif
3512                }
3513            }
3514            if ( pCnt )
3515                [self buildPath:path :pts :pCnt :w :lineArray :&lineCnt];
3516        }
3517        free(pts);
3518    } // lineArray, lineCnt
3519#if DEBUG_CONTUR
3520printf("%s Hour.Min.Sec vor Optimieren\n", [[[NSCalendarDate date] descriptionWithCalendarFormat:@"%H.%M.%S"] cString]);
3521#endif
3522
3523    [self optimizePath:path :w2Int];
3524
3525    /* move and scale path to old greatness */
3526    /* move and scale path and linePath and *fillPath to old great */
3527    moveP.x = -(bounds.origin.x - w2Int - 9.0); // dont know why 9.0 insteat 10.0 is correct - but it is
3528    moveP.y = -(bounds.origin.y - w2Int - 9.0); // w2Int+10.0 -> think: lower left coner of image is IN/AT composite pt
3529    moveP.x = -moveP.x; moveP.y = -moveP.y;
3530
3531    center = bounds.origin;
3532    scaleX = 1.0/scaleX;
3533    scaleY = 1.0/scaleY;
3534    [path moveBy:moveP];
3535    [path scale:scaleX :scaleY withCenter:center];
3536
3537    [conView unlockFocus];
3538    [win close];
3539    [[image image] setSize:imageSize]; // set to old great
3540    [bitmapImage release];
3541#if DEBUG_CONTUR
3542printf("%s Hour.Min.Sec End\n\n", [[[NSCalendarDate date] descriptionWithCalendarFormat:@"%H.%M.%S"] cString]);
3543#endif
3544    return path;
3545}
3546
3547/* modified: 23.02.05
3548 * get contour of list using a bitmap algorithm
3549 * return the calculated path
3550 */
3551- (VPath*)contourList:(NSArray*)oList width:(float)width
3552{   VPath               *path;
3553    NSRect              conRect, bounds=NSZeroRect, rect;
3554    id                  win, conView;
3555    float               w=width, w2, bytes, scale = 1, maxBytes = 110250000, wi, h, s, maxW=0;
3556    int                 i, x, y, right, height, start, w2Int, bytesPerRowHalf, quality = 2;
3557    int                 cnt = [oList count], drawed = 0;
3558    NSColor             *nxWhite, *nxBlack;
3559    NSPoint             moveP, center;
3560    NSBitmapImageRep    *bitmapImage;
3561
3562#if DEBUG_CONTUR
3563    NSColor		*nxGray;
3564    nxGray = [NSColor colorWithCalibratedRed:0.335 green:0.335 blue:0.335 alpha:1.0];
3565printf("%s Hour.Min.Sec Start\n", [[[NSCalendarDate date] descriptionWithCalendarFormat:@"%H.%M.%S"] cString]);
3566#endif
3567
3568    if (!cnt)
3569        return nil;
3570
3571    nxBlack = [NSColor colorWithCalibratedRed:0.0 green:0.0 blue:0.0 alpha:1.0];
3572    nxWhite = [NSColor colorWithCalibratedRed:1.0 green:1.0 blue:1.0 alpha:1.0];
3573
3574    path = [VPath path];
3575    [path setColor:[[oList objectAtIndex:0] color]];
3576    [path setFilled:NO];
3577    [path setWidth:0];
3578    [path setSelected:NO];
3579
3580    /* get Bounds and maxW */
3581    for (i=0; i < cnt; i++)
3582    {	VGraphic    *g = [oList objectAtIndex:i];
3583
3584        if ([g isKindOfClass:[VGroup class]])
3585        {   int	j, gCnt = [(VGroup*)g countRecursive];
3586
3587            for (j=0; j<gCnt; j++)
3588            {   VGraphic    *gg = [(VGroup*)g recursiveObjectAtIndex:j];
3589
3590                if ( [gg width] > maxW )
3591                    maxW = [gg width];
3592                rect = [gg bounds];
3593                bounds = (!bounds.size.width) ? rect : NSUnionRect(rect, bounds);
3594            }
3595        }
3596        else
3597        {   if ( [g width] > maxW )
3598                maxW = [g width];
3599            rect = [g bounds];
3600            bounds = (!bounds.size.width) ? rect : NSUnionRect(rect, bounds);
3601        }
3602    }
3603    /* calc content rect size / scale factor
3604     * to get not more than 20 MB memory
3605     * the bounds of the path: width*height / 8(bit) * 2(color deepnes)
3606     */
3607
3608// (Abs(w)+maxW) ++ maxWidth of objects from list !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!1
3609    wi = conRect.size.width = bounds.size.width + 4*Abs(w+maxW);
3610    h = conRect.size.height = bounds.size.height + 4*Abs(w+maxW); /* need a little space for our contour */
3611
3612    /* need a minimum scale of */
3613    scale = s = 1.0;
3614    conRect.size.width = wi*scale; conRect.size.height = h*scale;	/* last guilty values */
3615    bytes = (wi*scale) * (h*scale);
3616    w2 = Abs(w)*scale/2.0;
3617
3618    while ( bytes < maxBytes && s < 50 /*&& conRect.size.width < 10000 && conRect.size.height < 10000*/ ) // 8000
3619    {
3620        scale = s;
3621        w2 = Abs(w)*scale/2.0;
3622        conRect.size.width = wi*scale; conRect.size.height = h*scale;	/* last guilty values */
3623        if ( (quality == 2 && w2 > 40) || (quality == 1 && w2 > 30) || (!quality && w2 > 20) ) // 20
3624            break; /* stop scale is great enough */
3625
3626        s += 1.0;
3627        bytes = (wi*s) * (h*s); // 1 byte is one pixel;
3628        if ( wi*s > 10000 || h*s > 10000 ) // > 10000
3629            break; // too big !!!
3630    }
3631    if ( conRect.size.width > 10000 || conRect.size.height > 10000 ) // good bye > 10000
3632        return nil;
3633
3634    w2 = Abs(w+maxW)*scale/2.0;
3635    /* need our half width/minWidth in pixel and scaled */
3636    if ( (w2-((int)w2)) > 0.5 )
3637    {	w2Int = w2 + 1;
3638        conRect.size.width += 6.0; conRect.size.height += 6.0;
3639    }
3640    else
3641    {	w2Int = w2;
3642        conRect.size.width += 4.0; conRect.size.height += 4.0;
3643    }
3644    conRect.origin.x = conRect.origin.y = 10.0;
3645
3646    /* center */
3647    center.x = bounds.origin.x + bounds.size.width/2.0;
3648    center.y = bounds.origin.y + bounds.size.height/2.0;
3649
3650    bounds = NSZeroRect;
3651    for (i=0; i < cnt; i++)
3652    {	id	g = [oList objectAtIndex:i];
3653
3654        [g scale:scale :scale withCenter:center];
3655        rect = [g bounds];
3656        bounds = (!bounds.size.width) ? rect : NSUnionRect(rect, bounds);
3657    }
3658
3659    /* move oList to ~0 */
3660    moveP.x = -(bounds.origin.x - 4*w2Int - 2.0);
3661    moveP.y = -(bounds.origin.y - 4*w2Int - 2.0);
3662
3663    for (i=0; i < cnt; i++)
3664        [[oList objectAtIndex:i] moveBy:moveP];
3665
3666    /* build an offscreen window
3667     * in which we draw the scaled black copy of original path on white background NSBackingStoreBuffered NSBackingStoreRetained
3668     */
3669    win = [[NSWindow alloc] initWithContentRect:conRect styleMask:NSBorderlessWindowMask backing:NSBackingStoreRetained defer:NO];
3670    [win setDynamicDepthLimit:NO];
3671    [win setDepthLimit:NSBestDepth(NSCalibratedWhiteColorSpace, 8, 8, YES, NULL)];
3672//[win setDepthLimit:NSBestDepth(NSCalibratedRGBColorSpace, 8, 24, NO, NULL)]; // test apple
3673
3674//    [win setBackgroundColor:( w < 0 ) ? [NSColor grayColor] : [NSColor blackColor]];
3675    [win setBackgroundColor:[NSColor blackColor]];
3676
3677#if DEBUG_CONTUR
3678[win makeKeyAndOrderFront:self]; /* weglassen wenn nicht gesehen werden soll */
3679#endif
3680    conView = [win contentView];
3681    [conView display];
3682
3683    /* now draw our scaled path in view
3684     */
3685    [conView lockFocus];
3686
3687#ifdef __APPLE__
3688[[NSGraphicsContext currentContext] setShouldAntialias:NO];
3689#endif
3690
3691    for (i=0; i < cnt; i++)
3692    {   VGraphic    *g = [oList objectAtIndex:i];
3693        float       gWidth = ([g width]/scale), endW = w + gWidth, oldGWidth = [g width];
3694        int         gFilled = [g filled];
3695
3696        if ([g isKindOfClass:[VGroup class]])
3697        {   int	j, gCnt = [(VGroup*)g countRecursive];
3698
3699            for (j=0; j<gCnt; j++)
3700            {   VGraphic    *gg = [(VGroup*)g recursiveObjectAtIndex:j];
3701                NSColor     *fillColor = nil, *color = [[gg color] retain];
3702
3703                gWidth = ([gg width]/scale);
3704                endW = w + gWidth;
3705                gFilled = oldGWidth = [gg filled];
3706
3707                if ( [gg respondsToSelector:@selector(setFillColor:)] )
3708                    fillColor = [[(VPath*)gg fillColor] retain];
3709
3710                /* need our half width/minWidth in pixel and scaled */
3711                w2 = Abs(w+gWidth)*scale/2.0;
3712                if ([gg isKindOfClass:[VLine class]] &&
3713                    Diff([gg pointWithNum:0].y, [gg pointWithNum:1].y) <= TOLERANCE)
3714                    w2Int = ( (w2-((int)w2)) < 0.2 ) ? (w2-1) : (w2);
3715                else
3716                    w2Int = ( (w2-((int)w2)) > 0.5 ) ? (w2 + 1) : (w2);
3717
3718                if ( gFilled )
3719                {
3720                    [gg setWidth:0];
3721                    [(VPath*)gg setFillColor:( endW > 0 ) ? [NSColor grayColor] : nxWhite];
3722                    [(VPath*)gg drawWithPrincipal:nil];
3723                    drawed++;
3724
3725                    if (w2Int)
3726                    {
3727                        [gg setColor:(endW > 0) ? nxWhite : nxBlack];
3728                        if ( [gg isKindOfClass:[VPath class]] )
3729                            [(VPath*)gg setFilled:NO optimize:NO];
3730                        else
3731                            [gg setFilled:NO];
3732                        [gg setWidth:w2Int*2.0];
3733                        [gg drawWithPrincipal:nil];
3734                    }
3735                }
3736                else // stroked object
3737                {   BOOL fillObj = ([gg respondsToSelector:@selector(setFillColor:)]) ? YES : NO;
3738
3739                    if ( fillObj )
3740                    {   [gg setWidth:0];
3741                        [(VPath*)gg setFillColor:( endW > 0 || endW < 0 ) ? nxBlack : nxWhite];
3742                        [(VPath*)gg drawWithPrincipal:nil];
3743                        drawed++;
3744                    }
3745                    if (w2Int)
3746                    {   [gg setColor:(endW > 0 || endW < 0) ? nxWhite : nxBlack];
3747                        if ( [gg isKindOfClass:[VPath class]] )
3748                            [(VPath*)gg setFilled:NO optimize:NO];
3749                        else
3750                            [gg setFilled:NO];
3751                        [gg setWidth:w2Int*2.0];
3752                        [gg drawWithPrincipal:nil];
3753                        drawed++;
3754                    }
3755                }
3756                /* set all values back to old */
3757                [gg setWidth:oldGWidth];
3758                [gg setColor:color];
3759                if ( [gg respondsToSelector:@selector(setFillColor:)] )
3760                {
3761                    [(VPath*)gg setFillColor:fillColor];
3762                    if ( [gg isKindOfClass:[VPath class]] )
3763                        [(VPath*)gg setFilled:gFilled optimize:NO];
3764                    else
3765                        [gg setFilled:gFilled];
3766                }
3767            }
3768        }
3769        else
3770        {   NSColor	*fillColor = nil, *color = [[g color] retain];
3771
3772            if ( [g respondsToSelector:@selector(setFillColor:)] )
3773                fillColor = [[(VPath*)g fillColor] retain];
3774
3775            /* need our half width/minWidth in pixel and scaled */
3776            w2 = Abs(w+gWidth)*scale/2.0;
3777            if ([g isKindOfClass:[VLine class]] &&
3778                Diff([g pointWithNum:0].y, [g pointWithNum:1].y) <= TOLERANCE)
3779                w2Int = ( (w2-((int)w2)) < 0.2 ) ? (w2-1) : (w2);
3780            else
3781                w2Int = ( (w2-((int)w2)) > 0.5 ) ? (w2 + 1) : (w2);
3782
3783            if ( gFilled )
3784            {
3785                [g setWidth:0];
3786                [(VPath*)g setFillColor:( endW > 0 ) ? [NSColor grayColor] : nxWhite];
3787                [(VPath*)g drawWithPrincipal:nil];
3788                drawed++;
3789
3790                if (w2Int) // w2Int
3791                {
3792                    [g setColor:(endW > 0) ? nxWhite : nxBlack];
3793                    if ( [g isKindOfClass:[VPath class]] )
3794                        [(VPath*)g setFilled:NO optimize:NO];
3795                    else
3796                        [g setFilled:NO];
3797                    [g setWidth:w2Int*2.0]; // w2Int*2.0
3798                    [g drawWithPrincipal:nil];
3799                }
3800            }
3801            else // stroked object
3802            {   BOOL fillObj = ([g respondsToSelector:@selector(setFillColor:)]) ? YES : NO;
3803
3804                if ( fillObj )
3805                {   [g setWidth:0];
3806                    [(VPath*)g setFillColor:( endW > 0 || endW < 0 ) ? nxBlack : nxWhite];
3807                    [(VPath*)g drawWithPrincipal:nil];
3808                    drawed++;
3809                }
3810                if (w2Int)
3811                {   [g setColor:(endW > 0 || endW < 0) ? nxWhite : nxBlack];
3812                    if ( [g isKindOfClass:[VPath class]] )
3813                        [(VPath*)g setFilled:NO optimize:NO];
3814                    else
3815                        [g setFilled:NO];
3816                    [g setWidth:w2Int*2.0];
3817                    [g drawWithPrincipal:nil];
3818                    drawed++;
3819                }
3820            }
3821            /* set all values back to old */
3822            [g setWidth:oldGWidth];
3823            [g setColor:color];
3824            if ( [g respondsToSelector:@selector(setFillColor:)] )
3825            {
3826                [(VPath*)g setFillColor:fillColor];
3827                if ( [g isKindOfClass:[VPath class]] )
3828                    [(VPath*)g setFilled:gFilled optimize:NO];
3829                else
3830                    [g setFilled:gFilled];
3831            }
3832        }
3833    }
3834    if ( !drawed )
3835    {   [conView unlockFocus];
3836        [win close];
3837        return nil;
3838    }
3839    /* force 8 bit gray -> we must draw one thing gray */
3840    {   VRectangle	*r=[VRectangle rectangle];
3841
3842        [r setVertices:NSMakePoint(1.0,1.0) :NSMakePoint(1.0,1.0)];
3843        [r setFillColor:[NSColor grayColor]];
3844        [r setFilled:YES];
3845        [r drawWithPrincipal:nil];
3846    }
3847
3848    /* get pixel information into data (char string) */
3849    rect.origin = NSZeroPoint;
3850    right = rect.size.width = (int)(conRect.size.width); /* our with scale and bounds calculated width */
3851    height = rect.size.height = (int)(conRect.size.height);
3852
3853//[[NSColor redColor] set]; // test apple
3854//NSRectFill(NSMakeRect(1, 1, 1, 1));
3855
3856    bitmapImage = [[NSBitmapImageRep allocWithZone:[self zone]] initWithFocusedViewRect:rect];
3857
3858    // apple
3859    if ([bitmapImage bitsPerPixel] > 8 || ![bitmapImage isPlanar] || [bitmapImage samplesPerPixel] > 1)
3860    {	NSBitmapImageRep	*abitmap;
3861
3862        if ([bitmapImage bitsPerSample] == 8) // meshed
3863        {   int			ny, width;
3864            int			bpr = [bitmapImage bytesPerRow], spp = 1, abpr;
3865            int			bpp = [bitmapImage bytesPerPlane];
3866            unsigned char	*planes[5];
3867
3868            abitmap = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
3869                                                              pixelsWide:rect.size.width
3870                                                              pixelsHigh:rect.size.height
3871                                                           bitsPerSample:8
3872                                                         samplesPerPixel:1
3873                                                                hasAlpha:NO isPlanar:YES
3874                                                          colorSpaceName:NSCalibratedWhiteColorSpace
3875                                                             bytesPerRow:rect.size.width
3876                                                            bitsPerPixel:8];
3877
3878            data = [abitmap bitmapData];
3879            abpr = [abitmap bytesPerRow];
3880            [bitmapImage getBitmapDataPlanes:planes];
3881
3882            if (![bitmapImage isPlanar])
3883                spp = [bitmapImage bitsPerPixel]/8;
3884            width = bpr / spp; // bytesPerRow / samplesPerPixel
3885            for (y=0, ny=0; y<bpp; y+=bpr, ny+=abpr)
3886            {
3887                for (x=0; x<width; x++)
3888                {
3889                    *((LONG*)(data+ny+x)) = *((LONG*)(planes[0]+y+x*spp));
3890                }
3891            }
3892        }
3893        else
3894        {   [conView unlockFocus];
3895            [win close];
3896            [bitmapImage release];
3897            return nil;
3898        }
3899        [bitmapImage release];
3900        bitmapImage = abitmap;
3901    }
3902    size = [bitmapImage bytesPerPlane];
3903    data = [bitmapImage bitmapData];
3904    bytesPerRow = [bitmapImage bytesPerRow];
3905    bytesPerRowHalf = bytesPerRow/2.0;
3906    {   int	lineArray[bytesPerRowHalf], lineCnt = 0;
3907        NSPoint	*pts;
3908        pts = malloc(right * sizeof(NSPoint));
3909
3910    /* set loop parameters */
3911    right -= (2*w2Int+1);
3912    height -= (2*w2Int+1);
3913
3914#if DEBUG_CONTUR
3915[nxGray set];
3916#endif
3917
3918    /* vectorize contour */
3919    start = 2*w2Int+1;
3920    for (y=start; y<height; y++)
3921    {   int		pCnt=0, byteY, byteX;
3922
3923        byteY = y * bytesPerRow;	/* the height */
3924        byteY = size - byteY - bytesPerRow;
3925        for (x=start; x<right && byteY+x+19 < size; x++)
3926        {
3927            byteX = byteY+x;
3928            if ( *((LONG*)(data+byteX)) == black )
3929            {   if ( *((LONG*)(data+byteX+4)) == black )
3930                {   if ( *((LONG*)(data+byteX+8)) == black )
3931                    {   if ( *((LONG*)(data+byteX+12)) == black )
3932                        {   if ( *((LONG*)(data+byteX+16)) == black )
3933                            {   x += 16; continue; }
3934                            else {   x += 12; continue; }
3935                        }
3936                        else {   x += 8; continue; }
3937                    }
3938                    else {   x += 4; continue; }
3939                }
3940                else {   continue; }
3941            }
3942            else if ( *((LONG*)(data+byteX-bytesPerRow-1)) == -1 && *((LONG*)(data+byteX-1)) == -1 &&
3943                          *((LONG*)(data+byteX+bytesPerRow-1)) == -1 )
3944            {
3945                if ( *((LONG*)(data+byteX-bytesPerRow+3)) == -1 && *((LONG*)(data+byteX+3)) == -1 &&
3946                    *((LONG*)(data+byteX+bytesPerRow+3)) == -1 )
3947                {
3948                    if ( *((LONG*)(data+byteX-bytesPerRow+7)) == -1 && *((LONG*)(data+byteX+7)) == -1 &&
3949                        *((LONG*)(data+byteX+bytesPerRow+7)) == -1 )
3950                    {
3951                        if ( *((LONG*)(data+byteX-bytesPerRow+11)) == -1 && *((LONG*)(data+byteX+11)) == -1 &&
3952                            *((LONG*)(data+byteX+bytesPerRow+11)) == -1 )
3953                        {
3954                            if ( *((LONG*)(data+byteX-bytesPerRow+15)) == -1 && *((LONG*)(data+byteX+15)) == -1 &&
3955                                *((LONG*)(data+byteX+bytesPerRow+15)) == -1 )
3956                            {
3957                                if ( *((LONG*)(data+byteX-bytesPerRow+19)) == -1 && *((LONG*)(data+byteX+19)) == -1 &&
3958                                    *((LONG*)(data+byteX+bytesPerRow+19)) == -1 )
3959                                {   x += 19; continue; }
3960                                else {   x += 15; continue; }
3961                            }
3962                            else {   x += 11; continue; }
3963                        }
3964                        else {   x += 7; continue; }
3965                    }
3966                    else { x += 3; continue; }
3967                }
3968                else {   continue; }
3969            }
3970            if ( *(data+byteX) != white )
3971                continue;
3972            /* l d r u is a black pixel -> one of our pixels */
3973            if ( *(data+byteX-1) == black || *(data+byteX+bytesPerRow) == black ||
3974                *(data+byteX+1) == black || *(data+byteX-bytesPerRow) == black )
3975            {   NSPoint	nxp = {x, y};
3976                pts[pCnt] = nxp;
3977                pCnt++;
3978#if DEBUG_CONTUR
3979//NSRectFill(NSMakeRect(x, y, 1, 1));
3980#endif
3981            }
3982        }
3983        if ( pCnt )
3984            [self buildPath:path :pts :pCnt :w :lineArray :&lineCnt];
3985    }
3986    free(pts);
3987    } // lineArray, lineCnt
3988#if DEBUG_CONTUR
3989printf("%s Hour.Min.Sec vor Optimieren\n", [[[NSCalendarDate date] descriptionWithCalendarFormat:@"%H.%M.%S"] cString]);
3990#endif
3991
3992    /* correct path */
3993    /*if ( [[path list] count] )
3994    {   for (x=(int)[[path list] count]-1; x>=0; x--)
3995        {   VGraphic	*lineG = [[path list] objectAtIndex:x]; // nach opt - nur singles !
3996            NSPoint	start, end;
3997            [(VLine*)lineG getVertices:&start :&end];
3998            if ( //(![lineG isSelected] && Diff(start.x, end.x) <= 2 && Diff(start.y, end.y) <= 2) ||
3999                (Diff(start.x, end.x) <= 1 && Diff(start.y, end.y) <= 1) )
4000                [[path list] removeObjectAtIndex:x];
4001        }
4002    }*/
4003    [self optimizePath:path :w2Int];
4004
4005    /* move and scale path AND oList to old great */
4006    moveP.x = -moveP.x; moveP.y = -moveP.y;
4007    [path moveBy:moveP];
4008    scale = 1/scale;
4009    [path scale:scale :scale withCenter:center];
4010
4011    for (i=0; i < cnt; i++)
4012        [[oList objectAtIndex:i] moveBy:moveP];
4013    for (i=0; i < cnt; i++)
4014    {   VGraphic	*g = [oList objectAtIndex:i];
4015
4016        [g scale:scale :scale withCenter:center];
4017        [g setDirty:NO];
4018    }
4019
4020#if 0
4021{ int i;
4022  NSPoint s, e;
4023
4024  printf("VPath\n");
4025    for (i=0; i<[[path list] count]; i++)
4026    {	Line	*l1=[[path list] objectAtIndex:i];
4027
4028        [l1 getVertices:&s :&e];
4029        printf("%.2f s.x\t %.2f s.y\t %.2f e.x\t %.2f e.y\n", s.x, s.y, e.x, e.y);
4030    }
4031  printf("\n3DLinePath\n");
4032    for (i=0; i<[[linePath list] count]; i++)
4033    {	VLine3D	*l1=[[linePath list] objectAtIndex:i];
4034
4035        [l1 getVertices:&s :&e];
4036        printf("%.2f s.x\t %.2f s.y\t %.2f e.x\t %.2f e.y\n", s.x, s.y, e.x, e.y);
4037    }
4038}
4039#endif
4040    [conView unlockFocus];
4041    [win close];
4042    [bitmapImage release];
4043#if DEBUG_CONTUR
4044printf("%s Hour.Min.Sec End\n\n", [[[NSCalendarDate date] descriptionWithCalendarFormat:@"%H.%M.%S"] cString]);
4045#endif
4046    return path;
4047}
4048
4049@end
4050