/* PathContour.m
 * Object to build contour of paths and images using a raster algorithm (scan)
 *
 * Copyright (C) 2000-2015 by Cenon GmbH
 * Author:   Ilonka Fleischmann
 *
 * created:  2000-02-23
 * modified: 2015-09-02 (-contourImage:with:- contourPath::, -contourList::, conRect.size < 8000 instead 10000)
 *           2015-03-05 (-contourImage:with:- contourPath::, -contourList::, -invertData LONG casts corrected)
 *           2015-01-08 (-contourImage:with:- contourPath::, -contourList:: retina display factor recognized)
 *           2011-04-06 (-contourImage:with: whiteStop for jpg - white tolerances)
 *           2010-03-03 (-contourPath:with: setDirectionCCW:)
 *           2008-04-18 (optimizePath close now)
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the Cenon Public License as
 * published by Cenon GmbH. Among other things, the
 * License requires that the copyright notices and this notice
 * be preserved on all copies.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the Cenon Public License for more details.
 *
 * You should have received a copy of the Cenon Public License along
 * with this program; see the file LICENSE. If not, write to Cenon.
 *
 * Cenon GmbH, Schwabstr. 45, 72108 Rottenburg a.N., Germany
 * eMail: info@Cenon.com
 * http://www.Cenon.de
 */

#include <AppKit/AppKit.h>
#include <VHFShared/types.h>
#include <VHFShared/vhfCommonFunctions.h>
#include "../DocView.h"		// ???
#include "VGraphic.h"
#include "PathContour.h"

#define DEBUG_CONTUR        0
#define DEBUG_CONTUR_TIME	0
#define DEBUG_CONTUR_2      0

/* Private methods
*/
@interface PathContour(PrivateMethods)


@end

@implementation PathContour

//static NSBitmapImageRep	*bitmapImageRep;
static int              size, bytesPerRow;
static unsigned char	*data, black = 0, white = 255, whiteStop = 240;
static int
Arc2cnt = 5,
Arc2y[5] = {-2, -1, 0, 1, 2}, Arc2x[5] = {-2, -2, -2, -2, -2},
Arc2rowcnt[5] = {5, 5, 5, 5, 5},
Arc3cnt = 7,
Arc3y[7] = {-3, -2, -1, 0, 1, 2, 3},
Arc3x[7] = {-3, -3, -3, -3, -3, -3, -3},
Arc3rowcnt[7] = {7, 7, 7, 7, 7, 7, 7},
Arc4cnt = 9,
Arc4y[9] = {-4, -3, -2, -1, 0, 1, 2, 3, 4},
Arc4x[9] = {-3, -4, -4, -4, -4, -4, -4, -4, -3},
Arc4rowcnt[9] = {7, 9, 9, 9, 9, 9, 9, 9, 7};

static int
Arc5cnt = 11,
Arc5y[11] = {-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5},
Arc5x[11] = {-3, -4, -5, -5, -5, -5, -5, -5, -5, -4, -3},
Arc5rowcnt[11] = {7,9,11,11,11,11,11,11,11,9,7},
Arc6cnt = 13,
Arc6y[13] = {-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6},
Arc6x[13] = {-3,-5,-5,-6,-6,-6,-6,-6,-6,-6,-5,-5,-3},
Arc6rowcnt[13] = {7,11,11,13,13,13,13,13,13,13,11,11,7},
Arc7cnt = 15,
Arc7y[15] = {-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7},
Arc7x[15] = {-3,-5,-6,-6,-7,-7,-7,-7,-7,-7,-7,-6,-6,-5,-3},
Arc7rowcnt[15] = {7,11,13,13,15,15,15,15,15,15,15,13,13,11,7},
Arc8cnt = 17,
Arc8y[17] = {-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8},
Arc8x[17] = {-3,-5,-6,-7,-7,-8,-8,-8,-8,-8,-8,-8,-7,-7,-6,-5,-3},
Arc8rowcnt[17] = {7,11,13,15,15,17,17,17,17,17,17,17,15,15,13,11,7},
Arc9cnt = 19,
Arc9y[19] = {-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9}, 
Arc9x[19] = {-4,-6,-7,-8,-8,-9,-9,-9,-9,-9,-9,-9,-9,-9,-8,-8,-7,-6,-4},
Arc9rowcnt[19] = {9,13,15,17,17,19,19,19,19,19,19,19,19,19,17,17,15,13,9},
Arc10cnt = 21,
Arc10y[21] = {-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10},
Arc10x[21] = {-5,-6,-8,-8,-9,-10,-10,-10,-10,-10,-10,-10,-10,-10,-10,-10,-9,-8,-8,-6,-5},
Arc10rowcnt[21] = {11,13,17,17,19,21,21,21,21,21,21,21,21,21,21,21,19,17,17,13,11},
Arc11cnt = 23,
Arc11y[23] = {-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11},
Arc11x[23] = {-5,-6,-8,-9,-9,-10,-11,-11,-11,-11,-11,-11,-11,-11,-11,-11,-11,-10,-9,-9,-8,-6,-5},
Arc11rowcnt[23] = {11,13,17,19,19,21,23,23,23,23,23,23,23,23,23,23,23,21,19,19,17,13,11},
Arc12cnt = 25,
Arc12y[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},
Arc12x[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},
Arc12rowcnt[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},
Arc13cnt = 27,
Arc13y[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},
Arc13x[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},
Arc13rowcnt[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},
Arc14cnt = 29,
Arc14y[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},
Arc14x[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},
Arc14rowcnt[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},
Arc15cnt = 31,
Arc15y[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},
Arc15x[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},
Arc15rowcnt[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},
Arc16cnt = 33,
Arc16y[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},
Arc16x[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},
Arc16rowcnt[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},
Arc17cnt = 35,
Arc17y[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},
Arc17x[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},
Arc17rowcnt[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},
Arc18cnt = 37,
Arc18y[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},
Arc18x[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},
Arc18rowcnt[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},
Arc19cnt = 39,
Arc19y[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},
Arc19x[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},
Arc19rowcnt[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},
Arc20cnt = 41,
Arc20y[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},
Arc20x[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},
Arc20rowcnt[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},
Arc21cnt = 43,
Arc21y[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},
Arc21x[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},
Arc21rowcnt[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},
Arc22cnt = 45,
Arc22y[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},
Arc22x[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},
Arc22rowcnt[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},
Arc23cnt = 47,
Arc23y[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},
Arc23x[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},
Arc23rowcnt[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},
Arc24cnt = 49,
Arc24y[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},
Arc24x[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},
Arc24rowcnt[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},
Arc25cnt = 51,
Arc25y[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},
Arc25x[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},
Arc25rowcnt[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},
Arc26cnt = 53,
Arc26y[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},
Arc26x[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},
Arc26rowcnt[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},
Arc27cnt = 55,
Arc27y[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},
Arc27x[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},
Arc27rowcnt[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},
Arc28cnt = 57,
Arc28y[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},
Arc28x[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},
Arc28rowcnt[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},
Arc29cnt = 59,
Arc29y[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},
Arc29x[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},
Arc29rowcnt[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},
Arc30cnt = 61,
Arc30y[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},
Arc30x[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},
Arc30rowcnt[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},
Arc31cnt = 63,
Arc31y[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},
Arc31x[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},
Arc31rowcnt[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},
Arc32cnt = 65,
Arc32y[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},
Arc32x[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},
Arc32rowcnt[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},
Arc33cnt = 67,
Arc33y[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},
Arc33x[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},
Arc33rowcnt[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},
Arc34cnt = 69,
Arc34y[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},
Arc34x[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},
Arc34rowcnt[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},
Arc35cnt = 71,
Arc35y[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},
Arc35x[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},
Arc35rowcnt[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},
Arc36cnt = 73,
Arc36y[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},
Arc36x[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},
Arc36rowcnt[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},
Arc37cnt = 75,
Arc37y[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},
Arc37x[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},
Arc37rowcnt[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},
Arc38cnt = 77,
Arc38y[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},
Arc38x[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},
Arc38rowcnt[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},
Arc39cnt = 79,
Arc39y[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},
Arc39x[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},
Arc39rowcnt[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},
Arc40cnt = 81,
Arc40y[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},
Arc40x[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},
Arc40rowcnt[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},
Arc41cnt = 83,
Arc41y[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},
Arc41x[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},
Arc41rowcnt[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},
Arc42cnt = 85,
Arc42y[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},
Arc42x[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},
Arc42rowcnt[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},
Arc43cnt = 87,
Arc43y[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},
Arc43x[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},
Arc43rowcnt[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},
Arc44cnt = 89,
Arc44y[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},
Arc44x[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},
Arc44rowcnt[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},
Arc45cnt = 91,
Arc45y[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},
Arc45x[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},
Arc45rowcnt[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},
Arc46cnt = 93,
Arc46y[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},
Arc46x[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},
Arc46rowcnt[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};

/*
 * 4 2 6
 * 0 8 1
 * 5 3 7
 */

/* pixel(nxp) has left, right, up or down a white pixel at its side -> return YES
 */
#define SameGradients(grad, grad0)	\
( ((Diff(grad.y, 0)<TOLERANCE || Diff(grad0.y, 0)<TOLERANCE) && grad.x != 0 && grad0.x != 0 && \
    Diff(grad.y/grad.x, grad0.y/grad0.x) < 0.01 && ((grad.x<0 && grad0.x<0) || (grad.x>0 && grad0.x>0))) || \
  ((Diff(grad.x, 0)<TOLERANCE || Diff(grad0.x, 0)<TOLERANCE) && grad.y != 0 && grad0.y != 0 && \
    Diff(grad.x/grad.y, grad0.x/grad0.y) < 0.01 && ((grad.y<0 && grad0.y<0) || (grad.y>0 && grad0.y>0))) || \
  (Abs(grad.x) < Abs(grad.y) && grad.y != 0 && grad0.y != 0 && ((grad.y<0 && grad0.y<0) || (grad.y>0 && grad0.y>0)) &&\
   Diff(grad.x, 0)>TOLERANCE && Diff(grad0.x, 0)>TOLERANCE && Diff(grad.x/grad.y, grad0.x/grad0.y) < 0.03) || \
  (Abs(grad.x) > Abs(grad.y) && grad.x != 0 && grad0.x != 0 && ((grad.x<0 && grad0.x<0) || (grad.x>0 && grad0.x>0)) &&\
   Diff(grad.y, 0)>TOLERANCE && Diff(grad0.y, 0)>TOLERANCE && Diff(grad.y/grad.x, grad0.y/grad0.x) < 0.03) || \
  (Diff(grad.x, 0.0)>TOLERANCE && Diff(grad0.x, 0.0)>TOLERANCE && grad.y != 0 && grad0.y != 0 && \
   Diff(grad.x/grad.y, grad0.x/grad0.y) < 0.01 && \
   ((grad.x < 0 && grad0.x < 0) || (grad.x > 0 && grad0.x > 0) || \
    (grad.y < 0 && grad0.y < 0) || (grad.y > 0 && grad0.y > 0))) || \
  (Diff(grad.y, 0.0)>TOLERANCE && Diff(grad0.y, 0.0)>TOLERANCE && grad.x != 0 && grad0.x != 0 && \
   Diff(grad.y/grad.x, grad0.y/grad0.x) < 0.01 && \
   ((grad.x < 0 && grad0.x < 0) || (grad.x > 0 && grad0.x > 0) || \
    (grad.y < 0 && grad0.y < 0) || (grad.y > 0 && grad0.y > 0))) )

#define NearlySameGradients(grad, grad0)	\
( ((Diff(grad.y, 0)<TOLERANCE || Diff(grad0.y, 0)<TOLERANCE) && grad.x != 0 && grad0.x != 0 && \
    Diff(grad.y/grad.x, grad0.y/grad0.x) < 0.3 && ((grad.x<0 && grad0.x<0) || (grad.x>0 && grad0.x>0))) || \
  ((Diff(grad.x, 0)<TOLERANCE || Diff(grad0.x, 0)<TOLERANCE) && grad.y != 0 && grad0.y != 0 && \
    Diff(grad.x/grad.y, grad0.x/grad0.y) < 0.3 && ((grad.y<0 && grad0.y<0) || (grad.y>0 && grad0.y>0))) || \
  (Abs(grad.x) < Abs(grad.y) && grad.y != 0 && grad0.y != 0 && ((grad.y<0 && grad0.y<0) || (grad.y>0 && grad0.y>0)) &&\
   Diff(grad.x, 0)>TOLERANCE && Diff(grad0.x, 0)>TOLERANCE && Diff(grad.x/grad.y, grad0.x/grad0.y) < 0.3) || \
  (Abs(grad.x) > Abs(grad.y) && grad.x != 0 && grad0.x != 0 && ((grad.x<0 && grad0.x<0) || (grad.x>0 && grad0.x>0)) &&\
   Diff(grad.y, 0)>TOLERANCE && Diff(grad0.y, 0)>TOLERANCE && Diff(grad.y/grad.x, grad0.y/grad0.x) < 0.3) || \
  (Diff(grad.x, 0.0)>TOLERANCE && Diff(grad0.x, 0.0)>TOLERANCE && grad.y != 0 && grad0.y != 0 && \
   Diff(grad.x/grad.y, grad0.x/grad0.y) < 0.25 && \
   ((grad.x < 0 && grad0.x < 0) || (grad.x > 0 && grad0.x > 0) || \
    (grad.y < 0 && grad0.y < 0) || (grad.y > 0 && grad0.y > 0))) || \
  (Diff(grad.y, 0.0)>TOLERANCE && Diff(grad0.y, 0.0)>TOLERANCE && grad.x != 0 && grad0.x != 0 && \
   Diff(grad.y/grad.x, grad0.y/grad0.x) < 0.25 && \
   ((grad.x < 0 && grad0.x < 0) || (grad.x > 0 && grad0.x > 0) || \
    (grad.y < 0 && grad0.y < 0) || (grad.y > 0 && grad0.y > 0))) )

#define NNSameGradients(grad, grad0)	\
( ((Diff(grad.y, 0)<TOLERANCE || Diff(grad0.y, 0)<TOLERANCE) && grad.x != 0 && grad0.x != 0 && \
    Diff(grad.y/grad.x, grad0.y/grad0.x) < 0.5 && ((grad.x<0 && grad0.x<0) || (grad.x>0 && grad0.x>0))) || \
  ((Diff(grad.x, 0)<TOLERANCE || Diff(grad0.x, 0)<TOLERANCE) && grad.y != 0 && grad0.y != 0 && \
    Diff(grad.x/grad.y, grad0.x/grad0.y) < 0.5 && ((grad.y<0 && grad0.y<0) || (grad.y>0 && grad0.y>0))) || \
  (Abs(grad.x) < Abs(grad.y) && grad.y != 0 && grad0.y != 0 && ((grad.y<0 && grad0.y<0) || (grad.y>0 && grad0.y>0)) &&\
   Diff(grad.x, 0)>TOLERANCE && Diff(grad0.x, 0)>TOLERANCE && Diff(grad.x/grad.y, grad0.x/grad0.y) < 0.5) || \
  (Abs(grad.x) > Abs(grad.y) && grad.x != 0 && grad0.x != 0 && ((grad.x<0 && grad0.x<0) || (grad.x>0 && grad0.x>0)) &&\
   Diff(grad.y, 0)>TOLERANCE && Diff(grad0.y, 0)>TOLERANCE && Diff(grad.y/grad.x, grad0.y/grad0.x) < 0.5) || \
  (Diff(grad.x, 0.0)>TOLERANCE && Diff(grad0.x, 0.0)>TOLERANCE && grad.y != 0 && grad0.y != 0 && \
   Diff(grad.x/grad.y, grad0.x/grad0.y) < 0.5 && \
   ((grad.x < 0 && grad0.x < 0) || (grad.x > 0 && grad0.x > 0) || \
    (grad.y < 0 && grad0.y < 0) || (grad.y > 0 && grad0.y > 0))) || \
  (Diff(grad.y, 0.0)>TOLERANCE && Diff(grad0.y, 0.0)>TOLERANCE && grad.x != 0 && grad0.x != 0 && \
   Diff(grad.y/grad.x, grad0.y/grad0.x) < 0.5 && \
   ((grad.x < 0 && grad0.x < 0) || (grad.x > 0 && grad0.x > 0) || \
    (grad.y < 0 && grad0.y < 0) || (grad.y > 0 && grad0.y > 0))) )

#define NNNNSameGradients(grad, grad0)	\
( ((Diff(grad.y, 0)<TOLERANCE || Diff(grad0.y, 0)<TOLERANCE) && grad.x != 0 && grad0.x != 0 && \
    Diff(grad.y/grad.x, grad0.y/grad0.x) < 0.65 && ((grad.x<0 && grad0.x<0) || (grad.x>0 && grad0.x>0))) || \
  ((Diff(grad.x, 0)<TOLERANCE || Diff(grad0.x, 0)<TOLERANCE) && grad.y != 0 && grad0.y != 0 && \
    Diff(grad.x/grad.y, grad0.x/grad0.y) < 0.65 && ((grad.y<0 && grad0.y<0) || (grad.y>0 && grad0.y>0))) || \
  (Abs(grad.x) < Abs(grad.y) && grad.y != 0 && grad0.y != 0 && ((grad.y<0 && grad0.y<0) || (grad.y>0 && grad0.y>0)) &&\
   Diff(grad.x, 0)>TOLERANCE && Diff(grad0.x, 0)>TOLERANCE && Diff(grad.x/grad.y, grad0.x/grad0.y) < 0.65) || \
  (Abs(grad.x) > Abs(grad.y) && grad.x != 0 && grad0.x != 0 && ((grad.x<0 && grad0.x<0) || (grad.x>0 && grad0.x>0)) &&\
   Diff(grad.y, 0)>TOLERANCE && Diff(grad0.y, 0)>TOLERANCE && Diff(grad.y/grad.x, grad0.y/grad0.x) < 0.65) || \
  (Diff(grad.x, 0.0)>TOLERANCE && Diff(grad0.x, 0.0)>TOLERANCE && grad.y != 0 && grad0.y != 0 && \
   Diff(grad.x/grad.y, grad0.x/grad0.y) < 0.65 && \
   ((grad.x < 0 && grad0.x < 0) || (grad.x > 0 && grad0.x > 0) || \
    (grad.y < 0 && grad0.y < 0) || (grad.y > 0 && grad0.y > 0))) || \
  (Diff(grad.y, 0.0)>TOLERANCE && Diff(grad0.y, 0.0)>TOLERANCE && grad.x != 0 && grad0.x != 0 && \
   Diff(grad.y/grad.x, grad0.y/grad0.x) < 0.65 && \
   ((grad.x < 0 && grad0.x < 0) || (grad.x > 0 && grad0.x > 0) || \
    (grad.y < 0 && grad0.y < 0) || (grad.y > 0 && grad0.y > 0))) )

- (void)invertData
{   int			i;
    unsigned char	everything=255;

    for (i=0; i<size; i++)
    {   if (*(data+i) != white && *(data+i) != black)
            *(data+i) = (*(data+i) >= whiteStop) ? (white) : (black);
        *(data+i) ^= everything;
    }
}

/* modified: 02.02.00
 * 
 */
-(void)drawArcInDataAt:(int)byteX radius:(int)radius color:(unsigned char)col
{   int		j;

    switch (radius)
    {
        case 0: return;
        case 1:
            *(data+byteX-bytesPerRow-1) = col;
            *(data+byteX-1) = col;
            *(data+byteX+bytesPerRow-1) = col;
            *(data+byteX-bytesPerRow) = col;
            *(data+byteX) = col;
            *(data+byteX+bytesPerRow) = col;
            *(data+byteX-bytesPerRow+1) = col;
            *(data+byteX+1) = col;
            *(data+byteX+bytesPerRow+1) = col;
            break;
        case 2:
            for (j=0; j<Arc2cnt; j++)
                memset((data+byteX+(Arc2y[j]*bytesPerRow)+(Arc2x[j])), col, Arc2rowcnt[j]);
            break;
        case 3:
            for (j=0; j<Arc3cnt; j++)
                memset((data+byteX+(Arc3y[j]*bytesPerRow)+(Arc3x[j])), col, Arc3rowcnt[j]);
            break;
        case 4:
            for (j=0; j<Arc4cnt; j++)
                memset((data+byteX+(Arc4y[j]*bytesPerRow)+(Arc4x[j])), col, Arc4rowcnt[j]);
            break;
        case 5:
            for (j=0; j<Arc5cnt; j++)
                memset((data+byteX+(Arc5y[j]*bytesPerRow)+(Arc5x[j])), col, Arc5rowcnt[j]);
            break;
        case 6:
            for (j=0; j<Arc6cnt; j++)
                memset((data+byteX+(Arc6y[j]*bytesPerRow)+(Arc6x[j])), col, Arc6rowcnt[j]);
            break;
        case 7:
            for (j=0; j<Arc7cnt; j++)
                memset((data+byteX+(Arc7y[j]*bytesPerRow)+(Arc7x[j])), col, Arc7rowcnt[j]);
            break;
        case 8:
            for (j=0; j<Arc8cnt; j++)
                memset((data+byteX+(Arc8y[j]*bytesPerRow)+(Arc8x[j])), col, Arc8rowcnt[j]);
            break;
        case 9:
            for (j=0; j<Arc9cnt; j++)
                memset((data+byteX+(Arc9y[j]*bytesPerRow)+(Arc9x[j])), col, Arc9rowcnt[j]);
            break;
        case 10:
            for (j=0; j<Arc10cnt; j++)
                memset((data+byteX+(Arc10y[j]*bytesPerRow)+(Arc10x[j])), col, Arc10rowcnt[j]);
            break;
        case 11:
            for (j=0; j<Arc11cnt; j++)
                memset((data+byteX+(Arc11y[j]*bytesPerRow)+(Arc11x[j])), col, Arc11rowcnt[j]);
            break;
        case 12:
            for (j=0; j<Arc12cnt; j++)
                memset((data+byteX+(Arc12y[j]*bytesPerRow)+(Arc12x[j])), col, Arc12rowcnt[j]);
            break;
        case 13:
            for (j=0; j<Arc13cnt; j++)
                memset((data+byteX+(Arc13y[j]*bytesPerRow)+(Arc13x[j])), col, Arc13rowcnt[j]);
            break;
        case 14:
            for (j=0; j<Arc14cnt; j++)
                memset((data+byteX+(Arc14y[j]*bytesPerRow)+(Arc14x[j])), col, Arc14rowcnt[j]);
            break;
        case 15:
            for (j=0; j<Arc15cnt; j++)
                memset((data+byteX+(Arc15y[j]*bytesPerRow)+(Arc15x[j])), col, Arc15rowcnt[j]+1);
            break;
        case 16:
            for (j=0; j<Arc16cnt; j++)
                memset((data+byteX+(Arc16y[j]*bytesPerRow)+(Arc16x[j])), col, Arc16rowcnt[j]+1);
            break;
        case 17:
            for (j=0; j<Arc17cnt; j++)
                memset((data+byteX+(Arc17y[j]*bytesPerRow)+(Arc17x[j])), col, Arc17rowcnt[j]+1);
            break;
        case 18:
            for (j=0; j<Arc18cnt; j++)
                memset((data+byteX+(Arc18y[j]*bytesPerRow)+(Arc18x[j])), col, Arc18rowcnt[j]+1);
            break;
        case 19:
            for (j=0; j<Arc19cnt; j++)
                memset((data+byteX+(Arc19y[j]*bytesPerRow)+(Arc19x[j])), col, Arc19rowcnt[j]+1);
            break;
        case 20:
            for (j=0; j<Arc20cnt; j++)
                memset((data+byteX+(Arc20y[j]*bytesPerRow)+(Arc20x[j])), col, Arc20rowcnt[j]+1);
            break;
        case 21:
            for (j=0; j<Arc21cnt; j++)
                memset((data+byteX+(Arc21y[j]*bytesPerRow)+(Arc21x[j])), col, Arc21rowcnt[j]+1);
            break;
        case 22:
            for (j=0; j<Arc22cnt; j++)
                memset((data+byteX+(Arc22y[j]*bytesPerRow)+(Arc22x[j])), col, Arc22rowcnt[j]+1);
            break;
        case 23:
            for (j=0; j<Arc23cnt; j++)
                memset((data+byteX+(Arc23y[j]*bytesPerRow)+(Arc23x[j])), col, Arc23rowcnt[j]+1);
            break;
        case 24:
            for (j=0; j<Arc24cnt; j++)
                memset((data+byteX+(Arc24y[j]*bytesPerRow)+(Arc24x[j])), col, Arc24rowcnt[j]+1);
            break;
        case 25:
            for (j=0; j<Arc25cnt; j++)
                memset((data+byteX+(Arc25y[j]*bytesPerRow)+(Arc25x[j])), col, Arc25rowcnt[j]+1);
            break;
        case 26:
            for (j=0; j<Arc26cnt; j++)
                memset((data+byteX+(Arc26y[j]*bytesPerRow)+(Arc26x[j])), col, Arc26rowcnt[j]+1);
            break;
        case 27:
            for (j=0; j<Arc27cnt; j++)
                memset((data+byteX+(Arc27y[j]*bytesPerRow)+(Arc27x[j])), col, Arc27rowcnt[j]+1);
            break;
        case 28:
            for (j=0; j<Arc28cnt; j++)
                memset((data+byteX+(Arc28y[j]*bytesPerRow)+(Arc28x[j])), col, Arc28rowcnt[j]+1);
            break;
        case 29:
            for (j=0; j<Arc29cnt; j++)
                memset((data+byteX+(Arc29y[j]*bytesPerRow)+(Arc29x[j])), col, Arc29rowcnt[j]+1);
            break;
        case 30:
            for (j=0; j<Arc30cnt; j++)
                memset((data+byteX+(Arc30y[j]*bytesPerRow)+(Arc30x[j])), col, Arc30rowcnt[j]+1);
            break;
        case 31:
            for (j=0; j<Arc31cnt; j++)
                memset((data+byteX+(Arc31y[j]*bytesPerRow)+(Arc31x[j])), col, Arc31rowcnt[j]+1);
            break;
        case 32:
            for (j=0; j<Arc32cnt; j++)
                memset((data+byteX+(Arc32y[j]*bytesPerRow)+(Arc32x[j])), col, Arc32rowcnt[j]+1);
            break;
        case 33:
            for (j=0; j<Arc33cnt; j++)
                memset((data+byteX+(Arc33y[j]*bytesPerRow)+(Arc33x[j])), col, Arc33rowcnt[j]+1);
            break;
        case 34:
            for (j=0; j<Arc34cnt; j++)
                memset((data+byteX+(Arc34y[j]*bytesPerRow)+(Arc34x[j])), col, Arc34rowcnt[j]+1);
            break;
        case 35:
            for (j=0; j<Arc35cnt; j++)
                memset((data+byteX+(Arc35y[j]*bytesPerRow)+(Arc35x[j])), col, Arc35rowcnt[j]+1);
            break;
       case 36:
            for (j=0; j<Arc36cnt; j++)
                memset((data+byteX+(Arc36y[j]*bytesPerRow)+(Arc36x[j])), col, Arc36rowcnt[j]+1);
            break;
       case 37:
            for (j=0; j<Arc37cnt; j++)
                memset((data+byteX+(Arc37y[j]*bytesPerRow)+(Arc37x[j])), col, Arc37rowcnt[j]+1);
            break;
       case 38:
            for (j=0; j<Arc38cnt; j++)
                memset((data+byteX+(Arc38y[j]*bytesPerRow)+(Arc38x[j])), col, Arc38rowcnt[j]+1);
            break;
       case 39:
            for (j=0; j<Arc39cnt; j++)
                memset((data+byteX+(Arc39y[j]*bytesPerRow)+(Arc39x[j])), col, Arc39rowcnt[j]+1);
            break;
       case 40:
            for (j=0; j<Arc40cnt; j++)
                memset((data+byteX+(Arc40y[j]*bytesPerRow)+(Arc40x[j])), col, Arc40rowcnt[j]+1);
            break;
       case 41:
            for (j=0; j<Arc41cnt; j++)
                memset((data+byteX+(Arc41y[j]*bytesPerRow)+(Arc41x[j])), col, Arc41rowcnt[j]+1);
            break;
       case 42:
            for (j=0; j<Arc42cnt; j++)
                memset((data+byteX+(Arc42y[j]*bytesPerRow)+(Arc42x[j])), col, Arc42rowcnt[j]+1);
            break;
       case 43:
            for (j=0; j<Arc43cnt; j++)
                memset((data+byteX+(Arc43y[j]*bytesPerRow)+(Arc43x[j])), col, Arc43rowcnt[j]+1);
            break;
       case 44:
            for (j=0; j<Arc44cnt; j++)
                memset((data+byteX+(Arc44y[j]*bytesPerRow)+(Arc44x[j])), col, Arc44rowcnt[j]+1);
            break;
       case 45:
            for (j=0; j<Arc45cnt; j++)
                memset((data+byteX+(Arc45y[j]*bytesPerRow)+(Arc45x[j])), col, Arc45rowcnt[j]+1);
            break;
       case 46:
            for (j=0; j<Arc46cnt; j++)
                memset((data+byteX+(Arc46y[j]*bytesPerRow)+(Arc46x[j])), col, Arc46rowcnt[j]+1);
            break;
        default: // calculate with a loop
            printf("arcs greater 46 not yet implemented :-)");
    }
}

#define NoEdgeGradients(grad, grad0)	\
( ((Diff(grad.y, 0)<TOLERANCE || Diff(grad0.y, 0)<TOLERANCE) && Diff(grad.y/grad.x, grad0.y/grad0.x) < 1.5 && \
   ((grad.x<0 && grad0.x<0) || (grad.x>0 && grad0.x>0))) || \
  ((Diff(grad.x, 0)<TOLERANCE || Diff(grad0.x, 0)<TOLERANCE) && Diff(grad.x/grad.y, grad0.x/grad0.y) < 1.5 && \
   ((grad.y<0 && grad0.y<0) || (grad.y>0 && grad0.y>0))) || \
  (Abs(grad.x) < Abs(grad.y) && grad.y != 0 && grad0.y != 0 && ((grad.y<0 && grad0.y<0) || (grad.y>0 && grad0.y>0)) &&\
   Diff(grad.x, 0)>TOLERANCE && Diff(grad0.x, 0)>TOLERANCE && Diff(grad.x/grad.y, grad0.x/grad0.y) < 1.5) || \
  (Abs(grad.x) > Abs(grad.y) && grad.x != 0 && grad0.x != 0 && ((grad.x<0 && grad0.x<0) || (grad.x>0 && grad0.x>0)) &&\
   Diff(grad.y, 0)>TOLERANCE && Diff(grad0.y, 0)>TOLERANCE && Diff(grad.y/grad.x, grad0.y/grad0.x) < 1.5) || \
  (Diff(grad.x, 0.0)>TOLERANCE && Diff(grad0.x, 0.0)>TOLERANCE && Diff(grad.x/grad.y, grad0.x/grad0.y) < 1.5 && \
   ((grad.x < 0 && grad0.x < 0) || (grad.x > 0 && grad0.x > 0) || \
    (grad.y < 0 && grad0.y < 0) || (grad.y > 0 && grad0.y > 0))) || \
  (Diff(grad.y, 0.0)>TOLERANCE && Diff(grad0.y, 0.0)>TOLERANCE && Diff(grad.y/grad.x, grad0.y/grad0.x) < 1.5 && \
   ((grad.x < 0 && grad0.x < 0) || (grad.x > 0 && grad0.x > 0) || \
    (grad.y < 0 && grad0.y < 0) || (grad.y > 0 && grad0.y > 0))) )

-(BOOL)noEdgeOrGapBetweenLines:(VGraphic*)l1 :(VGraphic*)l2
{   NSPoint	l1s, l1e, l2s, l2e, grad1, grad2;

        [(VLine*)l1 getVertices:&l1s :&l1e];
        grad1.x = l1e.x - l1s.x; grad1.y = l1e.y - l1s.y;
        [(VLine*)l2 getVertices:&l2s :&l2e];
        grad2.x = l2e.x - l2s.x; grad2.y = l2e.y - l2s.y;

        if ( SqrDistPoints(l1e, l2s) < 5 && NNSameGradients(grad1, grad2) ) // NoEdgeGradients
            return YES;
        return NO;
}

-(BOOL)noEdgeOrGapBetweenGraphics:(VGraphic*)l1 :(VGraphic*)l2
{   NSPoint	l1s, l1e, l2s, l2e, grad1, grad2, p1, p2, pm;

    if ( [l1 isKindOfClass:[VLine class]] )
    {   [(VLine*)l1 getVertices:&l1s :&l1e];
        grad1.x = l1e.x - l1s.x; grad1.y = l1e.y - l1s.y;
    }
    else
    {   [(VCurve*)l1 getVertices:&l1s :&p1 :&p2 :&l1e];
        pm = CenterPoint(p1, p2);
        grad1.x = l1e.x - pm.x; grad1.y = l1e.y - pm.y;
    }

    if ( [l2 isKindOfClass:[VLine class]] )
    {   [(VLine*)l2 getVertices:&l2s :&l2e];
        grad2.x = l2e.x - l2s.x; grad2.y = l2e.y - l2s.y;
    }
    else
    {   [(VCurve*)l2 getVertices:&l2s :&p1 :&p2 :&l2e];
        pm = CenterPoint(p1, p2);
        grad2.x = pm.x - l2s.x; grad2.y = pm.y - l2s.y;
    }
    if ( SqrDistPoints(l1e, l2s) < TOLERANCE && SameGradients(grad1, grad2) )
        return YES;
    return NO;
}

- (void)uniteCurvesToLines:(VPath*)path :(int)w
{   int			i, j, k, lineCnt=0, curveCnt=0;
    NSPoint		ls, le, l1e, l2s, l2e, p1, p2;
    VGraphic		*lineG, *l1, *l2;
    NSMutableArray	*myList;
    NSColor		*nxBlack = [NSColor colorWithCalibratedRed:0.0 green:0.0 blue:0.0 alpha:1.0];

    myList = [[[NSMutableArray allocWithZone:[self zone]] init] autorelease];

    if ( ![[path list] count] )
        return;

    /* collect curves (NO edge between!!!) and test if they are on a line
     * remove curves and add line
     */
    for (i=0; i<(int)[[path list] count]; i++)
    {	id	g1 = [[path list] objectAtIndex:i], g2;
        NSPoint	s, e;
        int	noEdge = 0, onlyThreeTimes = 0;

        if ( i < (int)[[path list] count]-1 )
     	{   g2 = [[path list] objectAtIndex:i+1];
            noEdge = [self noEdgeOrGapBetweenGraphics:g1 :g2];
        }
        else
        {   g2 = [[path list] objectAtIndex:i-1];
            noEdge = [self noEdgeOrGapBetweenGraphics:g2 :g1];
            if ( !noEdge && lineCnt > 3 )
                [myList addObject:[[path list] objectAtIndex:i]];
        }
        if ( noEdge && i < (int)[[path list] count]-1 )
        {   lineCnt++;
            continue;
        }
        else if ( lineCnt <= 3 )
        {   for (j=0; j<=lineCnt; j++)
                [myList addObject:[[path list] objectAtIndex:i-j]];
            if ( i == (int)[[path list] count]-2 )
                [myList addObject:g2];
            lineCnt=0;
            continue;
        }
        /* set lineG */
        l1=[[path list] objectAtIndex:i-lineCnt];
        l2=[[path list] objectAtIndex:i];
        if ( [l1 isKindOfClass:[VLine class]] )
            [(VLine*)l1 getVertices:&ls :&l1e];
        else
            [(VCurve*)l1 getVertices:&ls :&p1 :&p2 :&l1e];

        if ( [l2 isKindOfClass:[VLine class]] )
            [(VLine*)l2 getVertices:&l2s :&le];
        else
            [(VCurve*)l2 getVertices:&l2s :&p1 :&p2 :&le];
        lineG = [VLine line];
        [lineG setColor:nxBlack]; [lineG setWidth:0]; [lineG setSelected:NO];
        [(VLine*)lineG setVertices:ls :le];
        onlyThreeTimes = 0;

        /* test curves */
        for (j=i-lineCnt, k=0; k<lineCnt+1; k++, j++)
        {   VGraphic	*lg=[[path list] objectAtIndex:j];
            float	tol = 9.0;

            if ( [lg isKindOfClass:[VLine class]] )
            {   [(VLine*)lg getVertices:&s :&e];
                if ( (sqrDistancePointLine(&ls, &le, &s) <= tol) && (sqrDistancePointLine(&ls, &le, &e) <= tol) )
                    curveCnt++;
                else if ( !curveCnt && onlyThreeTimes < 4 )
                {   VGraphic	*lg=[[path list] objectAtIndex:i-lineCnt];
                    [myList addObject:lg];
                    /* correct lineG */
                    lg = [[path list] objectAtIndex:i-lineCnt+1];
                    [(VLine*)lg getVertices:&l2s :&l2e];
                    [(VLine*)lineG setVertices:l2s :le];
                    lineCnt --; k = -1;
                    onlyThreeTimes++;
                }
                else
                    break;
            }
            else
            {   [(VCurve*)lg getVertices:&s :&p1 :&p2 :&e];
                if ( (sqrDistancePointLine(&ls, &le, &s) <= tol) && (sqrDistancePointLine(&ls, &le, &e) <= tol)
                    && (sqrDistancePointLine(&ls, &le, &p1) <= tol) && (sqrDistancePointLine(&ls, &le, &p2) <= tol) )
                    curveCnt++;
                else if ( !curveCnt && onlyThreeTimes < 4 )
                {   VGraphic	*lg=[[path list] objectAtIndex:i-lineCnt];
                    [myList addObject:lg];
                    /* correct lineG */
                    lg = [[path list] objectAtIndex:i-lineCnt+1];
                    [(VCurve*)lg getVertices:&l2s :&p1 :&p2 :&l2e];
                    [(VLine*)lineG setVertices:l2s :le];
                    lineCnt --; k = -1;
                    onlyThreeTimes++;
                }
                else
                    break;
            }
        }
        /* build line from curves (curveCnt) */
        if ( curveCnt > 1 )
        {
            if ( curveCnt < lineCnt )
            {
                g2=[[path list] objectAtIndex:i-lineCnt+curveCnt];
                if ( [g2 isKindOfClass:[VLine class]] )
                    [(VLine*)g2 getVertices:&l2s :&l2e];
                else
                    [(VCurve*)g2 getVertices:&l2s :&p1 :&p2 :&l2e];
                [(VLine*)lineG setVertices:ls :l2e];
            }
            [myList addObject:lineG];

            if ( curveCnt < lineCnt )
            {   for (j=i-lineCnt+curveCnt+1, k=curveCnt; k<lineCnt; k++, j++)
                {   VGraphic	*lg=[[path list] objectAtIndex:j];
                    [myList addObject:lg];
                }
            }
        }
        else
        {
            for (j=i-lineCnt, k=0; k<lineCnt+1; k++, j++)
            {   VGraphic	*lg=[[path list] objectAtIndex:j];
                [myList addObject:lg];
            }
        }
        lineCnt=0;
        curveCnt=0;
    }
    /* list to path */
    [path setList:myList]; /* optimize list also */
}

-(BOOL)noEdgeOrGapBetweenCurves:(VGraphic*)l1 :(VGraphic*)l2
{   NSPoint	l1s, l1e, l2s, l2e, grad1, grad2, p1, p2;

    [(VCurve*)l1 getVertices:&l1s :&p1 :&p2 :&l1e];
    grad1.x = l1e.x - p2.x; grad1.y = l1e.y - p2.y;

    [(VCurve*)l2 getVertices:&l2s :&p1 :&p2 :&l2e];
    grad2.x = p1.x - l2s.x; grad2.y = p1.y - l2s.y;

    if ( SqrDistPoints(l1e, l2s) < TOLERANCE && SameGradients(grad1, grad2) )
        return YES;
    return NO;
}

/* never used ?
 */
- (void)unite3CurvesTo1Curve:(VPath*)path
{   int			i, j, k, lineCnt=0;
    NSMutableArray	*myList;

    myList = [[[NSMutableArray allocWithZone:[self zone]] init] autorelease];

    if ( ![[path list] count] )
        return;

    /* collect curves (NO edge between!!!) and test if they are on a line
     * remove curves and add line
     */
    for (i=0; i<(int)[[path list] count]; i++)
    {	id	g1 = [[path list] objectAtIndex:i], g2;
        int	noEdge = 0;

        if ( i < (int)[[path list] count]-1 )
     	{   g2 = [[path list] objectAtIndex:i+1];
            if ( [g1 isKindOfClass:[VCurve class]] && [g2 isKindOfClass:[VCurve class]] )
                noEdge = [self noEdgeOrGapBetweenCurves:g1 :g2];
            else noEdge = 0;
        }
        else
        {   g2 = [[path list] objectAtIndex:i-1];
            if ( [g1 isKindOfClass:[VCurve class]] && [g2 isKindOfClass:[VCurve class]] )
                noEdge = [self noEdgeOrGapBetweenCurves:g2 :g1];
            else noEdge = 0;
            if ( !noEdge && lineCnt > 3 )
                [myList addObject:[[path list] objectAtIndex:i]];
        }
        if ( noEdge && i < (int)[[path list] count]-1 )
        {   lineCnt++;
            continue;
        }
        else if ( lineCnt <= 3 )
        {   for (j=0; j<=lineCnt; j++)
                [myList addObject:[[path list] objectAtIndex:i-j]];
            if ( i == (int)[[path list] count]-2 )
                [myList addObject:g2];
            lineCnt=0;
            continue;
        }
        /* set lineG */

        /* unite curves - allways three */
//        for (j=i-lineCnt, k=0; k<lineCnt+1; k+=3, j++)
        for (j=i-lineCnt, k=0; k<lineCnt+1-2; k+=3, j+=3)
        {   VGraphic    *c1 = [[path list] objectAtIndex:j];
            VGraphic    *c2 = [[path list] objectAtIndex:j+1];
            VGraphic    *c3 = [[path list] objectAtIndex:j+2];
            NSPoint     s1, c1p1, c1p2, e1, s2, c2p1, c2p2, e2, s3, c3p1, c3p2, e3;

            [(VCurve*)c1 getVertices:&s1 :&c1p1 :&c1p2 :&e1];
            [(VCurve*)c2 getVertices:&s2 :&c2p1 :&c2p2 :&e2];
            [(VCurve*)c3 getVertices:&s3 :&c3p1 :&c3p2 :&e3];
            [(VCurve*)c1 calcVerticesFromPoints:s1 :e1 :e2 :e3];
            [myList addObject:c1];
        }
        for ( ; k<lineCnt+1; k++, j++ ) // FIXME: is it correct to start at j ?
        {   VGraphic	*lg = [[path list] objectAtIndex:j];
            [myList addObject:lg];
        }
        lineCnt = 0;
    }
    /* list to path */
    [path setList:myList]; /* optimize list also */
}

- (void)uniteLinesWithSameGradient2:(VPath*)path :(int)w
{   int		i, j, k, lineCnt=0;
    NSPoint	s1, e1, s2, e2, grad1, grad2;

    if ( ![[path list] count] )
        return;

    // unite realy vertical lines !
    for (i=0; i<(int)[[path list] count]-1; i++)
    {	VGraphic	*l1=[[path list] objectAtIndex:i];
        VGraphic	*l2=[[path list] objectAtIndex:i+1];

        [(VLine*)l1 getVertices:&s1 :&e1];
        [(VLine*)l2 getVertices:&s2 :&e2];
        if ( e1.x == s1.x && e2.x == s2.x && e1.x == s2.x && e1.y == s2.y )
        {
            [(VLine*)l1 setVertices:s1 :e2]; /* l1 go now until l2 end */
            [[path list] removeObjectAtIndex:i+1]; /*[l2 release];*/
            i--;
        }
    }

    for (i=0; i<(int)[[path list] count]; i++)
    {	id	g1 = [[path list] objectAtIndex:i], g2;
        int	noEdge = 0;

        if ( i < (int)[[path list] count]-1 )
     	{   g2 = [[path list] objectAtIndex:i+1];
            [(VLine*)g1 getVertices:&s1 :&e1];
            grad1.x = e1.x - s1.x; grad1.y = e1.y - s1.y;
            [(VLine*)g2 getVertices:&s2 :&e2];
            grad2.x = e2.x - s2.x; grad2.y = e2.y - s2.y;
            if ( [self noEdgeOrGapBetweenLines:g1 :g2] && NearlySameGradients(grad1, grad2) )
                noEdge = 1.0;
            else
                noEdge = 0.0;
        }
        else
        {   g2 = [[path list] objectAtIndex:i-1];
            [(VLine*)g1 getVertices:&s1 :&e1];
            grad1.x = e1.x - s1.x; grad1.y = e1.y - s1.y;
            [(VLine*)g2 getVertices:&s2 :&e2];
            grad2.x = e2.x - s2.x; grad2.y = e2.y - s2.y;
            if ( [self noEdgeOrGapBetweenLines:g2 :g1] && NearlySameGradients(grad1, grad2) )
                noEdge = 1.0;
            else
                noEdge = 0.0;
        }
        if ( noEdge && i < (int)[[path list] count]-1 )
        {   lineCnt++;
            continue;
        }
        else if ( lineCnt <= 3 )
        {   lineCnt=0;
            continue;
        }
        /* unite lines - allways two */
        for (j=i-lineCnt, k=0; k<lineCnt+1-1 && lineCnt > 3; k+=2, j++)
        {   VGraphic	*l1=[[path list] objectAtIndex:j];
            VGraphic	*l2=[[path list] objectAtIndex:j+1];

            [(VLine*)l1 getVertices:&s1 :&e1];
            [(VLine*)l2 getVertices:&s2 :&e2];
            [(VLine*)l1 setVertices:s1 :e2]; /* l1 go now until l2 end */
            [[path list] removeObjectAtIndex:j+1];
            i--;
        }
        lineCnt = 0;
    }
}

/* build from n f[] values (t[] are the distance between f[] values)
 * splineSize calcf[] interpolated values (x or y)
 */
void cubicSplineC(int n, double t[], double f[], int splineSize, double calcf[])
{   int i,j;
    double a[n], b[n], c[n], delta_t[n], D[n], m[n], k[n];
    double bh, dh, e, h, wt, dt;

    for (i=1; i<n; i++)
    {
        delta_t[i] = t[i]-t[i-1];
        D[i] = (f[i]-f[i-1])/delta_t[i];
    }
    m[0] = delta_t[2];
    delta_t[0] = t[2]-t[0];
    h = delta_t[1];
    k[0] = ((h + 2*delta_t[0])*D[1]*delta_t[2]+h*h*D[2])/delta_t[0];
    for (i=1; i<(n-1); i++)
    {
        h = -delta_t[i+1]/m[i-1];
        k[i] = h*k[i-1]+3*(delta_t[i]*D[i+1]+delta_t[i+1]*D[i]);
        m[i] = h *delta_t[i-1] + 2* (delta_t[i] + delta_t[i+1]);
    }
    h = t[n-1]-t[n-3];
    dh = delta_t[n-1];
    k[n-1] = ((dh+h+h)*D[n-1]*delta_t[n-2] + dh*dh*D[n-2])/h;
    h = -h/m[n-2];
    m[n-1] = delta_t[n-2];
    m[n-1] = h*delta_t[n-2] + m[n-1];
    a[n-1] = (h*k[n-2]+k[n-1])/m[n-1];
    for (i=n-2; i>=0; i--)
        a[i] = (k[i]-delta_t[i]*a[i+1])/m[i];
    for (i=1; i<n; i++)
    {
        dh = D[i]; bh = delta_t[i];
        e = a[i-1]+a[i]-dh-dh;
        b[i-1] = 2*(dh-a[i-1]-e)/bh;
        c[i-1] = 6*e/(bh*bh);
    }
    wt = 0; j=0;
    dt = t[n-1]/(double)(splineSize-1);
    for (i=0; i<splineSize; i++)
    {
        while ( (t[j+1]<wt) && (j<splineSize) )
            j++;
        h = wt - t[j];
        calcf[i] = f[j]+h*(a[j]+h*(b[j]+h*c[j]/3)/2);
        wt = wt+dt;
    }
    calcf[splineSize-1] = f[n-1];
}

-(void)addCurvesFromBSplineToList:(NSMutableArray*)listle :(int)cnt :(NSPoint*)bSplinePts
{   NSPoint	b[3*cnt+1];
    long	m, k;
    NSColor	*nxBlack=[NSColor colorWithCalibratedRed:0.0 green:0.0 blue:0.0 alpha:1.0];

    m = cnt; // m = Anzahl der Gewichtspunkte der BSpline
    m--; // m Gewichtspunkte ergeben m-1 Polynome oder Kurvenzuege bzw Bezier-Kurven

    b[0] = bSplinePts[0];
    b[3*m] = bSplinePts[m];
    // Bezierpunkte b[i] aus Gewichtspunkten berechnen
    for (k=1; k<=m; k++) /* calc all p1 of curves */
    {
        b[3*k-2].x = (2.0*bSplinePts[k-1].x + bSplinePts[k].x) / 3.0;
        b[3*k-2].y = (2.0*bSplinePts[k-1].y + bSplinePts[k].y) / 3.0;
    }
    for (k=1; k<=m-1; k++) /* calc p3 of curves */
    {
        b[3*k].x = (bSplinePts[k-1].x + 4.0*bSplinePts[k].x + bSplinePts[k+1].x) / 6.0;
        b[3*k].y = (bSplinePts[k-1].y + 4.0*bSplinePts[k].y + bSplinePts[k+1].y) / 6.0;
    }
    for (k=0; k<=m-1; k++) /* calc all p2 of curves */
    {
        b[3*k+2].x = (bSplinePts[k].x + 2.0*bSplinePts[k+1].x) / 3.0;
        b[3*k+2].y = (bSplinePts[k].y + 2.0*bSplinePts[k+1].y) / 3.0;
    }
    // jeweils Endpunkt der letzten VCurve als Anfangspunkt in die naechste Kurve uebernehmen!
    for (k=3; k<=3*m; k+=3)
    {	VGraphic	*curveG = [VCurve curve];

        [curveG setColor:nxBlack];
        [curveG setWidth:0];
        [(VCurve*)curveG setVertices:b[k-3] :b[k-2] :b[k-1] :b[k]]; /* p0 p1 p2 p3 */
        [listle addObject:curveG];
    }
}

- (void)linesToCurvesInPath:(VPath*)path :(int)w
{   int			i, j, k, lineCnt=0;
    NSPoint		ls, le;
    NSMutableArray	*myList;

    if ( [[path list] count] < 2 )
        return;

    myList = [[[NSMutableArray allocWithZone:[self zone]] init] autorelease];

    /* unite lines with same gradients */
    [self uniteLinesWithSameGradient2:path :w];
//return;

    if ( [[path list] count] < 2 )
        return;

    /* build bSplines from lines and than curves from bSplines */

    /* collect 3/4 lines (NO edge between!!!) and make a bSpline->curve from it
     * remove lines and add curves
     */
    for (i=0; i<(int)[[path list] count]; i++)
    {	id	g1 = [[path list] objectAtIndex:i], g2;
        int	noEdge = 0, sameLength = 0, len1, len2, addLastGraphic=0;
        NSPoint	s1, e1, s2, e2;

        if ( i < (int)[[path list] count]-1 )
     	{   g2 = [[path list] objectAtIndex:i+1];
            noEdge = [self noEdgeOrGapBetweenLines:g1 :g2];
            [(VLine*)g1 getVertices:&s1 :&e1];
            [(VLine*)g2 getVertices:&s2 :&e2];
            len1 = SqrDistPoints(s1, e1);
            len2 = SqrDistPoints(s2, e2);
            ( Diff(len1, len2) <= 25 ) ? (sameLength = 1) : (sameLength = 0);
        }
        else
        {   g2 = [[path list] objectAtIndex:i-1];
            noEdge = [self noEdgeOrGapBetweenLines:g2 :g1];
            [(VLine*)g1 getVertices:&s1 :&e1];
            [(VLine*)g2 getVertices:&s2 :&e2];
            ( Diff(SqrDistPoints(s1, e1), SqrDistPoints(s2, e2)) <= 25 ) ? (sameLength = 1) : (sameLength = 0);
            if ( (!noEdge || !sameLength) && lineCnt >= 3 )
            {   addLastGraphic = 1; i--; } // lineCnt from previous i !!!!
//                [myList addObject:[[path list] objectAtIndex:i]];
        }
        if ( noEdge && sameLength && i < (int)[[path list] count]-1 ) // sameLength !!!
        {   lineCnt++;
            continue;
        }
        else if ( lineCnt < 3 )
//            for (j=0; j<=lineCnt; j++)
        {   for (j=lineCnt; j>=0; j--) // hold sort of list !!!
                [myList addObject:[[path list] objectAtIndex:i-j]];
            if ( i == (int)[[path list] count]-2 )
            {   [myList addObject:g2];
                break; // ende !!!
            }
            lineCnt=0;
            continue;
        }

        /* if ( lineCnt > 3 ) */
        {   double	x[lineCnt+2], y[lineCnt+2], t[lineCnt+2]; /* x,y coordinates our linePts and t */
            double	ax, ay, dd;
            int	splineSize = (lineCnt+1.0 > 3) ? (lineCnt+1.0) : (4);
//            int	splineSize = (Even((lineCnt+1))) ? (lineCnt+2.0) : (lineCnt+1.0);
            NSPoint	bSplinePts[splineSize+1];
            double	calcfx[splineSize+1], calcfy[splineSize+1];

            /* build spline through points */
//printf("\n%i", lineCnt);
            /* fill x,y value Arrays and calc t values - lineCnt+1 lines -> lineCnt + 2 pts
                  * with dist = 1/3*(dx+dy+2*max{dx,dy}) (euclid) */
            for (j=i-lineCnt, k=0; k<lineCnt+1; k++, j++)
            {   VGraphic	*lg=[[path list] objectAtIndex:j];

                [(VLine*)lg getVertices:&ls :&le];
                x[k] = ls.x;
                y[k] = ls.y;
//printf("linePts:\t%.2f x\t%.2f y\n", ls.x, ls.y);
                if ( k == lineCnt ) /* last line we need also the end */
                {   x[k+1] = le.x;
                    y[k+1] = le.y;
//printf("linePts:\t%.2f x\t%.2f y\n", le.x, le.y);
                    break;
                }
            }
//printf("\n\n");

            t[0] = 0.0;
            for (j=1; j<lineCnt+2; j++) /* we have lineCnt+1 lines -> lineCnt+2 t values to points */
            {   ax = Abs(x[j]-x[j-1]);
                ay = Abs(y[j]-y[j-1]);
                dd = ax + ay;
                if ( ax > ay ) dd = dd + 2.0*ax;
                else           dd = dd + 2.0*ay;
                t[j] = t[j-1] + dd/3.0;
            }
            /* calc interpolation values*/
            cubicSplineC(lineCnt+2, t, x, splineSize, calcfx);
            cubicSplineC(lineCnt+2, t, y, splineSize, calcfy);
            for (j=0; j<splineSize; j++)
            {   bSplinePts[j].x = calcfx[j];
                bSplinePts[j].y = calcfy[j];
//printf("splinePts:\t%.2f x\t%.2f y\n", bSplinePts[j].x, bSplinePts[j].y);
if ( calcfx[j] < 0 || calcfy[j] < 0 )
    printf("oh no 2\n");
            }
//printf("\n");
            /* build curves from bSpline */
            [self addCurvesFromBSplineToList:myList :splineSize :bSplinePts];
            if ( addLastGraphic )
            {   [myList addObject:[[path list] objectAtIndex:(int)[[path list] count]-1]]; // to hold sort of list
                i++; // correct i !
            }
            lineCnt = 0;
        }
    }
    /* list to path */
    [path setList:myList]; /* optimize list also */
}



- (float)distanceParallelLines:(VLine*)l1 :(VLine*)l2 :(int)fillDist
{   NSPoint	l1S, l1E, l2S, l2E;
    float	xDistS, xDistE, yDist, dist, d1, d2;

    [l1 getVertices:&l1S :&l1E];
    [l2 getVertices:&l2S :&l2E];

    xDistS = Diff(l1E.x, l2S.x);
    xDistE = Diff(l1E.x, l2E.x);
    yDist = Diff(l1E.y, l2S.y);

    if ( Diff(yDist, fillDist) < TOLERANCE && (xDistS < 5 || xDistE < 5) )
    {
        if ( xDistE < 5 )
            [l2 setVertices:l2E :l2S]; /* change direction */
        dist = 0;
    }
    else
    {   if ( (d1=SqrDistPoints(l1E, l2S)) < (d2=SqrDistPoints(l1E, l2E)) )
            dist = d1;
        else
        {   [l2 setVertices:l2E :l2S]; /* change direction */
            dist = d2;
        }
    }
    return dist;
}
#if 0
- (void)uniteLinesWithSameGradient:(VPath*)path :(int)w
{   int		i, j, k, m, uniteUntil = 0;
    NSPoint	l1S, l1E, l2S, l2E, l3S, l3E, mPts[1000], tp; // FIX ME - malloc points
    float	maxDiff = 0.25, sqrDist = 10, maxLen = (w+1)*(w+1); // maxDiff was 0.35 mit mPts;

    if ( ![[path list] count] )
        return;
//return;
    /* unite short lines all other */
    for (i=0; i<(int)[[path list] count]-1; i++)
    {	VGraphic	*l1=[[path list] objectAtIndex:i];
        VGraphic	*l2=[[path list] objectAtIndex:i+1];
        NSPoint		lastEndPt;
        float		d1, d2, d3, dl1, dl2, dl3, angleDiff = 15, angle1, angle2, lastAngle=0;
        int		mCnt = 0;
        BOOL		curveAhead = NO;

        [(VLine*)l1 getVertices:&l1S :&l1E];
        [(VLine*)l2 getVertices:&l2S :&l2E];
//        mPts[mCnt++] = CenterPoint(l1S, l1E);
        mPts[mCnt++] = l1E;
//        mPts[mCnt++] = CenterPoint(l2S, l2E);
        mPts[mCnt++] = l2S;
        dl1 = SqrDistPoints(l1S, l1E);
        dl2 = SqrDistPoints(l2S, l2E);
        sqrDist = SqrDistPoints(l1E, l2S);
        lastEndPt = l2E;

if (mCnt > 999)
    NSLog(@"PathContour.m: -uniteLinesWith... mPts Ueberlauf");

        if ( sqrDist > 5 || (l1S.y == l1E.y && Diff(l1S.x, l1E.x) > w*2.0) || /*dl1 > maxLen ||*/
             (d1 = pointOnLineClosestToPoint(l1S, l2E, mPts[mCnt-1], &tp)) > maxDiff )
            continue;
        if ( /*dl2 > maxLen ||*/ (l2S.y == l2E.y && Diff(l2S.x, l2E.x) > w*2.0) ||
             (d2 = pointOnLineClosestToPoint(l1S, l2E, mPts[mCnt-1], &tp)) > maxDiff )
            continue;

        angle1 = [(VLine*)l1 angle];
        lastAngle = angle2 = [(VLine*)l2 angle];
        if ( Diff(angle1, angle2) > angleDiff && Diff(Diff(angle1, angle2), 360.0) > angleDiff )
            continue;

        for (j=i+2 ;j<(int)[[path list] count]; j++)
        {   VGraphic	*l3=[[path list] objectAtIndex:j];
            float	angle3;

            [(VLine*)l3 getVertices:&l3S :&l3E];
//            mPts[mCnt++] = CenterPoint(l3S, l3E);
            mPts[mCnt++] = l3S;

            dl3 = SqrDistPoints(l3S, l3E);
            sqrDist = SqrDistPoints(lastEndPt, l3S);
            lastEndPt = l3E;

            angle3 = [(VLine*)l3 angle];
            if ( (Diff(lastAngle, angle3) > angleDiff && Diff(Diff(lastAngle, angle3), 360.0) > angleDiff) ||
                 (l3S.y == l3E.y && Diff(l3S.x, l3E.x) > w*2.0) )
            {   curveAhead = YES;
                uniteUntil = j - 1;
                break;
            }
            lastAngle = angle3;

            /* check all mPts start at end */
            for (m=mCnt-1; m >= 0; m--)
            {
                if ( (Diff(lastAngle, angle3) > angleDiff && Diff(Diff(lastAngle, angle3), 360.0) > angleDiff) ||
                          /*dl3 > maxLen ||*/ sqrDist > 5 ||
                          (d3 = pointOnLineClosestToPoint(l1S, l3E, mPts[m], &tp)) > maxDiff )
                {
                    curveAhead = YES;
                    uniteUntil = j - 1; // j - (mCnt - ((!m) ? (1):(m)));
                    break;
                }
            }
            if ( curveAhead )
            {
                break;
            }
       }

        if ( !curveAhead )
            uniteUntil = [[path list] count]-1;
        /* unite lines until j-(mCnt-m) ????????? */
        if ( Diff(uniteUntil, i) >= 1 )
        {   VGraphic	*uline=[[path list] objectAtIndex:uniteUntil];

            [(VLine*)uline getVertices:&l3S :&l3E];
            [(VLine*)l1 setVertices:l1S :l3E];
            for (k=uniteUntil; k > i; k--)
            {
                if ( k < [[path list] count] )
                    [[path list] removeObjectAtIndex:k];
                else
                    NSLog(@"falscher index");
            }
        }
    }
}
#endif
#if 0
- (void)uniteLinesWithSameGradient:(VPath*)path :(int)w
{   int		i, j, k, curveI=-1;
    NSPoint	l1S, l1E, l2S, l2E, l3S, l3E, l4S, l4E;
    float	angleDiff = 6.0, angleD1 = 0.01, angleD2 = 0.02;
    BOOL	curveAhead = NO;

    if ( ![[path list] count] )
        return;

    for (i=0; i<(int)[[path list] count]-1; i++)
    {	VGraphic	*l1=[[path list] objectAtIndex:i];
        VGraphic	*l2=[[path list] objectAtIndex:i+1];
        float		angle1, angle2, aVals[10];
        int		aCnt = 0;

        [(VLine*)l1 getVertices:&l1S :&l1E];
        [(VLine*)l2 getVertices:&l2S :&l2E];
        angle1 = [(VLine*)l1 angle];
        angle2 = [(VLine*)l2 angle];
        aVals[aCnt++] = angle1;

        if ( curveAhead == YES && i <= curveI && l1E.x == l2S.x && l1E.y == l2S.y &&
             (Diff(angle1, angle2) < angleD1 || Diff(Diff(angle1, angle2), 360.0) < angleD1) )
        {
            [(VLine*)l1 setVertices:l1S :l2E]; /* l1 go now until l2 end */
            [[path list] removeObjectAtIndex:i+1];
            i--;
            continue;
        }
        else if ( curveAhead == YES && i <= curveI )
            continue;
        else if ( curveAhead == YES )
        {   curveAhead = NO;
            curveI = -1;
        }

        if ( Diff(angle1, angle2) > angleD2 && Diff(Diff(angle1, angle2), 360.0) > angleD2 )
            aVals[aCnt++] = angle2;
        if ( l1E.x == l2S.x && l1E.y == l2S.y &&
             (Diff(angle1, angle2) < angleDiff || Diff(Diff(angle1, angle2), 360.0) < angleDiff) )
        {
            for (j=i+1 ;j<(int)[[path list] count]-1; j++)
            {	VGraphic	*l3=[[path list] objectAtIndex:j];
                VGraphic	*l4=[[path list] objectAtIndex:j+1];
                float		angle3, angle4;

                [(VLine*)l3 getVertices:&l3S :&l3E];
                [(VLine*)l4 getVertices:&l4S :&l4E];
                angle3 = [(VLine*)l3 angle];
                angle4 = [(VLine*)l4 angle];
                if ( l3E.x == l4S.x && l3E.y == l4S.y &&
                     (Diff(angle3, angle4) < angleDiff || Diff(Diff(angle3, angle4), 360.0) < angleDiff) )
                {
                    if ( Diff(aVals[0], angle4) > angleD2 && Diff(Diff(aVals[0], angle4), 360.0) > angleD2 )
                    {
                        /* new different Angle */
                        if ( aCnt > 1 &&
                             Diff(aVals[1], angle4) > angleD2 && Diff(Diff(aVals[1], angle4), 360.0) > angleD2 )
                        {
//                            if ( aCnt > 2 &&
//                                 ((Diff(aVals[2], angle4) > angleD2 &&
//                                 Diff(Diff(aVals[2], angle4), 360.0) > angleD2) ||
//                                 ( Diff(j, i) < 9 )) )
                            {
                                /* aCnt ist 3 ist maximum - bis hier uniten */
                                if ( Diff(j, i) >= 9 )
                                {
                                    [(VLine*)l1 setVertices:l1S :l3E];
                                    for (k=j; k > i; k--)
                                        [[path list] removeObjectAtIndex:k];

                                    aCnt = 10.0; // so we do not unite until end
                                    break;
                                }
                                /* 4. different Value OR 3 inside 8 lines - curve ahead - no line */
                                curveAhead = YES;
                                curveI = j;
                                break;
                            }
/*                            else if ( aCnt == 2 )
                            {   aVals[aCnt++] = angle4;
                                continue;
                            }
                            else
                                continue;
*/
                        }
                        else if ( aCnt == 1 )
                        {   aVals[aCnt++] = angle4;
                            continue;
                        }
                        else
                            continue;
                    }
                    else
                        continue;
                }
                /* unite all lines until j,  if less / or 3 values */
                else if ( (aCnt < 3 && Diff(j, i) > 6) || (aCnt < 4 && Diff(j, i) >= 9) )
                {   VLine	*lj = [[path list] objectAtIndex:j];
                    NSPoint	lje = [lj pointWithNum:MAXINT];

                    [(VLine*)l1 setVertices:l1S :lje];
                    for (k=j; k > i; k--)
                        [[path list] removeObjectAtIndex:k];

                    aCnt = 10.0; // so we do not unite until end
                    break;
                }
                else /* else unite only with an angleDiff of angleD1 */
                {
                    /* 4. different Value OR 3 inside 8 lines - curve ahead - no line */
                    curveAhead = YES;
                    curveI = j;
                    break;
                }
            }
            /* unite all lines until list end,  if less / or 3 values */
            if ( curveAhead == NO &&
                 ((aCnt < 3 && Diff([[path list] count], i) > 6) ||
                  (aCnt < 4 && Diff([[path list] count], i) >= 9)) )
            {	VLine	*ll = [[path list] objectAtIndex:[[path list] count]-1];
                NSPoint	lle = [ll pointWithNum:MAXINT];

                [(VLine*)l1 setVertices:l1S :lle];
                for (j=[[path list] count]-1; j > i; j--)
                    [[path list] removeObjectAtIndex:j];

                return;
            }
            /* unite l1 and l2 if angle diff smaller angleD1 */
            else if ( curveAhead == YES &&
                      (Diff(angle1, angle2) < angleD1 || Diff(Diff(angle1, angle2), 360.0) < angleD1) )
            {
                [(VLine*)l1 setVertices:l1S :l2E]; /* l1 go now until l2 end */
                [[path list] removeObjectAtIndex:i+1];
                i--;
            }
        }
    }
}
#endif

// OLD
- (void)uniteLinesWithSameGradient:(VPath*)path :(int)w
{   int		i, sqrDist=(w/2.0)*(w/2.0);
    NSPoint	grad1, grad2; // grad3;
    NSPoint	l1S, l1E, l2S, l2E; //, l3S, l3E;

    if ( ![[path list] count] )
        return;

    // unite realy vertical lines !
    for (i=0; i<(int)[[path list] count]-1; i++)
    {	VGraphic	*l1=[[path list] objectAtIndex:i];
        VGraphic	*l2=[[path list] objectAtIndex:i+1];

        [(VLine*)l1 getVertices:&l1S :&l1E];
        [(VLine*)l2 getVertices:&l2S :&l2E];
        if ( l1E.x == l1S.x && l2E.x == l2S.x && l1E.x == l2S.x && l1E.y == l2S.y )
        {
            [(VLine*)l1 setVertices:l1S :l2E]; /* l1 go now until l2 end */
            [[path list] removeObjectAtIndex:i+1]; /*[l2 release];*/
            i--;
        }
    }

    for (i=0; i<(int)[[path list] count]-1; i++)
    {	VGraphic	*l1=[[path list] objectAtIndex:i];
        VGraphic	*l2=[[path list] objectAtIndex:i+1];

        [(VLine*)l1 getVertices:&l1S :&l1E];
        [(VLine*)l2 getVertices:&l2S :&l2E];
        grad1.x = l1E.x - l1S.x; grad1.y = l1E.y - l1S.y;
        grad2.x = l2E.x - l2S.x; grad2.y = l2E.y - l2S.y;
        if ( l1E.x == l2S.x && l1E.y == l2S.y && SameGradients(grad1, grad2) && SqrDistPoints(l2S, l2E) < sqrDist && SqrDistPoints(l1S, l1E) < sqrDist )
        {
            [(VLine*)l1 setVertices:l1S :l2E]; /* l1 go now until l2 end */
            [[path list] removeObjectAtIndex:i+1]; /*[l2 release];*/
            i--;
        }
    }
#if 0
    for (i=0; i<(int)[[path list] count]-2; i++)
    {	VGraphic	*l1=[[path list] objectAtIndex:i];
        VGraphic	*l2=[[path list] objectAtIndex:i+1];
        VGraphic	*l3=[[path list] objectAtIndex:i+2];

        [(VLine*)l1 getVertices:&l1S :&l1E];
        [(VLine*)l2 getVertices:&l2S :&l2E];
        [(VLine*)l3 getVertices:&l3S :&l3E];
        grad1.x = l1E.x - l1S.x; grad1.y = l1E.y - l1S.y;
        grad2.x = l2E.x - l2S.x; grad2.y = l2E.y - l2S.y;
        grad3.x = l3E.x - l3S.x; grad3.y = l3E.y - l3S.y;
        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
             /*&& (SameGradients(grad1, grad2) || SameGradients(grad3, grad2))*/ )
        {
            [(VLine*)l1 setVertices:l1S :l3E]; /* l1 go now until l3 end */
            [[path list] removeObjectAtIndex:i+2]; /*[l3 release];*/
            [[path list] removeObjectAtIndex:i+1]; /*[l2 release];*/
            i--;
        }
    }
#endif
    return;
}

#if 0
- (void)smoothenLinesInPath:(VPath*)path :(int)w
{   int		i, j, k, lineCnt=0;
    NSPoint	s1, e1, s2, e2, mPrev;
    float	angle1, angle2, angleDiff1 = 13.0, angleDiff2 = 5.0, angleDiffE = 27.0;
    float	curAngleDiff = angleDiff1, aDiff = 0.0, sqrDist = 0.0, firstA = -1.0;

    if ( [[path list] count] < 2 )
        return;

    for (i=0; i<(int)[[path list] count]; i++)
    {	id	g1 = [[path list] objectAtIndex:i], g2;
        int	noEdge = 0;

        if ( i < (int)[[path list] count]-1 )
     	{   g2 = [[path list] objectAtIndex:i+1];
            [(VLine*)g1 getVertices:&s1 :&e1];
            [(VLine*)g2 getVertices:&s2 :&e2];
            angle1 = [(VLine*)g1 angle];
            angle2 = [(VLine*)g2 angle];
            aDiff = Diff(angle1, angle2);
            sqrDist = SqrDistPoints(e1, s2);
            /* angleDiff < 0-7 */
            if ( (s1.y == e1.y && Diff(s1.x, e1.x) > w) || (s2.y == e2.y && Diff(s2.x, e2.x) > w) )
            {   noEdge = 0.0;
                curAngleDiff = angleDiffE;
            }
            else if (sqrDist < 5 && (aDiff < angleDiff1 || Diff(aDiff, 360.0) < angleDiff1))
            {
                if (curAngleDiff == angleDiff1 || curAngleDiff == angleDiffE)
                {   noEdge = 1.0;
                    curAngleDiff = angleDiff1;
                    if (!lineCnt)
                        firstA = angle1;
                }
                else if (curAngleDiff == angleDiff2 && // angleDiff < 5-7
                         aDiff > angleDiff2 && Diff(aDiff, 360.0) > angleDiff2)
                    noEdge = 1.0;
                else
                {   noEdge = 0.0;
                    curAngleDiff = angleDiff1;
                }
            }
            /* angleDiff < 8-20 */
            else if (sqrDist < 5 && (aDiff < angleDiffE || Diff(aDiff, 360.0) < angleDiffE))
            {
                if (curAngleDiff == angleDiff2)
                {   noEdge = 1.0;
                    if (!lineCnt)
                        firstA = angle1;
                }
                else
                {   noEdge = 0.0;
                    curAngleDiff = angleDiff2;
                }
            }
            /* angleDiff > 20 */
            else
            {   noEdge = 0.0;
                curAngleDiff = angleDiffE;
            }
        }
        else
        {   g2 = [[path list] objectAtIndex:i-1];
            [(VLine*)g1 getVertices:&s1 :&e1];
            [(VLine*)g2 getVertices:&s2 :&e2];
            angle1 = [(VLine*)g1 angle];
            angle2 = [(VLine*)g2 angle];
            aDiff = Diff(angle1, angle2);
            sqrDist = SqrDistPoints(e2, s1);
            /* angleDiff < 0-7 */
            if ( (s1.y == e1.y && Diff(s1.x, e1.x) > w) || (s2.y == e2.y && Diff(s2.x, e2.x) > w) )
            {   noEdge = 0.0;
                curAngleDiff = angleDiffE;
            }
            else if (sqrDist < 5 && (aDiff < angleDiff1 || Diff(aDiff, 360.0) < angleDiff1))
            {
                if (curAngleDiff == angleDiff1 || curAngleDiff == angleDiffE)
                {   noEdge = 1.0;                    
                    curAngleDiff = angleDiff1;
                    if (!lineCnt)
                        firstA = angle1;
                }
                else if (curAngleDiff == angleDiff2 && // angleDiff < 5-7
                         aDiff > angleDiff2 && Diff(aDiff, 360.0) > angleDiff2)
                    noEdge = 1.0;
                else
                {   noEdge = 0.0;
                    curAngleDiff = angleDiff1;
                }
            }
            /* angleDiff < 8-20 */
            else if (sqrDist < 5 && (aDiff < angleDiffE || Diff(aDiff, 360.0) < angleDiffE))
            {
                if (curAngleDiff == angleDiff2)
                    noEdge = 1.0;
                else
                {   noEdge = 0.0;
                    curAngleDiff = angleDiff2;
                }
            }
            /* angleDiff > 20 */
            else
            {   noEdge = 0.0;
                curAngleDiff = angleDiffE;
            }
        }
        if ( noEdge && i < (int)[[path list] count]-1 )
        {   lineCnt++;
            continue;
        }
        else if ( lineCnt <= 3 ) /*|| Diff(firstA, angle1) > angleDiff1*/
        {   lineCnt=0;
            continue;
        }
        mPrev.x = mPrev.y = -1;
        /* smoothen lines - allways ??? */
        for (j=i-lineCnt, k=0; k<lineCnt+1-1 && lineCnt > 3; k+=2, j+=2)
        {   VGraphic	*l1=[[path list] objectAtIndex:j];
            VGraphic	*l2=[[path list] objectAtIndex:j+1];
            NSPoint     m1, m2;

            [(VLine*)l1 getVertices:&s1 :&e1];
            [(VLine*)l2 getVertices:&s2 :&e2];
            m1 = CenterPoint(s1, e1);
            m2 = CenterPoint(s2, e2);
            if ( mPrev.x == -1 && mPrev.y == -1 ) // first
                [(VLine*)l1 setVertices:s1 :m1];
            else
                [(VLine*)l1 setVertices:mPrev :m1];
            [(VLine*)l2 setVertices:m1 :m2];
            mPrev = m2;
            if ( k >= lineCnt+1-3 ) // last
            {	VGraphic	*lineG=[VLine line];
                NSColor	*nxBlack = [NSColor colorWithCalibratedRed:0.0 green:0.0 blue:0.0 alpha:1.0];
                [lineG setColor:nxBlack]; [lineG setWidth:0]; [lineG setSelected:NO];

                if ( j+2 == lineCnt )
                {   VGraphic	*l3=[[path list] objectAtIndex:j+2];
                    NSPoint	s3, e3, m3;

                    [(VLine*)l3 getVertices:&s3 :&e3];
                    m3 = CenterPoint(s3, e3);
                    [(VLine*)l3 setVertices:m2 :m3];
                    [(VLine*)lineG setVertices:m3 :e3];
                    [[path list] insertObject:lineG atIndex:j+3];
                }
                else
                {   [(VLine*)lineG setVertices:m2 :e2];
                    [[path list] insertObject:lineG atIndex:j+2];
                }
                i++;
                lineCnt++; // one line more !!!
            }
        }
        /* smoothen lines - allways ------------- second time */
        mPrev.x = mPrev.y = -1;
        for (j=i-lineCnt, k=0; k<lineCnt+1-1 && lineCnt > 3; k+=2, j+=2)
        {   VGraphic	*l1=[[path list] objectAtIndex:j];
            VGraphic	*l2=[[path list] objectAtIndex:j+1];
            NSPoint     m1, m2;

            [(VLine*)l1 getVertices:&s1 :&e1];
            [(VLine*)l2 getVertices:&s2 :&e2];
            m1 = CenterPoint(s1, e1);
            m2 = CenterPoint(s2, e2);
            if ( mPrev.x == -1 && mPrev.y == -1 ) // first
                [(VLine*)l1 setVertices:s1 :m1];
            else
                [(VLine*)l1 setVertices:mPrev :m1];
            [(VLine*)l2 setVertices:m1 :m2];
            mPrev = m2;
            if ( k >= lineCnt+1-3 ) // last
            {	VGraphic	*lineG=[VLine line];
                NSColor	*nxBlack = [NSColor colorWithCalibratedRed:0.0 green:0.0 blue:0.0 alpha:1.0];
                [lineG setColor:nxBlack]; [lineG setWidth:0]; [lineG setSelected:NO];

                if ( j+2 == lineCnt )
                {   VGraphic	*l3=[[path list] objectAtIndex:j+2];
                    NSPoint	s3, e3, m3;

                    [(VLine*)l3 getVertices:&s3 :&e3];
                    m3 = CenterPoint(s3, e3);
                    [(VLine*)l3 setVertices:m2 :m3];
                    [(VLine*)lineG setVertices:m3 :e3];
                    [[path list] insertObject:lineG atIndex:j+3];
                }
                else
                {   [(VLine*)lineG setVertices:m2 :e2];
                    [[path list] insertObject:lineG atIndex:j+2];
                }
                i++;
            }
        }
#if 0
        if ( Diff(firstA, angle1) < angleDiff1 ) // line i hope
        {
            /* smoothen lines ------------- third time */
            mPrev.x = mPrev.y = -1;
            for (j=i-lineCnt, k=0; k<lineCnt+1-1 && lineCnt > 3; k+=2, j+=2)
            {   VGraphic	*l1=[[path list] objectAtIndex:j];
                VGraphic	*l2=[[path list] objectAtIndex:j+1];
                NSPoint     m1, m2;

                [(VLine*)l1 getVertices:&s1 :&e1];
                [(VLine*)l2 getVertices:&s2 :&e2];
                m1 = CenterPoint(s1, e1);
                m2 = CenterPoint(s2, e2);
                if ( mPrev.x == -1 && mPrev.y == -1 ) // first
                    [(VLine*)l1 setVertices:s1 :m1];
                else
                    [(VLine*)l1 setVertices:mPrev :m1];
                [(VLine*)l2 setVertices:m1 :m2];
                mPrev = m2;
                if ( k >= lineCnt+1-3 ) // last
                {	VGraphic	*lineG=[VLine line];
                    NSColor	*nxBlack = [NSColor colorWithCalibratedRed:0.0 green:0.0 blue:0.0 alpha:1.0];
                    [lineG setColor:nxBlack]; [lineG setWidth:0]; [lineG setSelected:NO];

                    if ( j+2 == lineCnt )
                    {   VGraphic	*l3=[[path list] objectAtIndex:j+2];
                        NSPoint	s3, e3, m3;

                        [(VLine*)l3 getVertices:&s3 :&e3];
                        m3 = CenterPoint(s3, e3);
                        [(VLine*)l3 setVertices:m2 :m3];
                        [(VLine*)lineG setVertices:m3 :e3];
                        [[path list] insertObject:lineG atIndex:j+3];
                    }
                    else
                    {   [(VLine*)lineG setVertices:m2 :e2];
                        [[path list] insertObject:lineG atIndex:j+2];
                    }
                    i++;
                }
            }
        }
#endif
        lineCnt = 0;
    }
}
#endif

// OLD
- (void)smoothenLinesInPath:(VPath*)path
{   int		i, j, k, lineCnt=0;
    NSPoint	s1, e1, s2, e2, grad1, grad2, mPrev;

    if ( [[path list] count] < 2 )
        return;

    for (i=0; i<(int)[[path list] count]; i++)
    {	id	g1 = [[path list] objectAtIndex:i], g2;
        int	noEdge = 0;

        if ( i < (int)[[path list] count]-1 )
     	{   g2 = [[path list] objectAtIndex:i+1];
            [(VLine*)g1 getVertices:&s1 :&e1];
            grad1.x = e1.x - s1.x; grad1.y = e1.y - s1.y;
            [(VLine*)g2 getVertices:&s2 :&e2];
            grad2.x = e2.x - s2.x; grad2.y = e2.y - s2.y;
            if ( SqrDistPoints(e1, s2) < 5 && NNNNSameGradients(grad1, grad2) ) // [self noEdgeOrGapBetweenLines:g1 :g2] 
                noEdge = 1.0;
            else
                noEdge = 0.0;
        }
        else
        {   g2 = [[path list] objectAtIndex:i-1];
            [(VLine*)g1 getVertices:&s1 :&e1];
            grad1.x = e1.x - s1.x; grad1.y = e1.y - s1.y;
            [(VLine*)g2 getVertices:&s2 :&e2];
            grad2.x = e2.x - s2.x; grad2.y = e2.y - s2.y;
            if ( SqrDistPoints(e2, s1) < 5 && NNNNSameGradients(grad1, grad2) ) //  && [self noEdgeOrGapBetweenLines:g2 :g1]
                noEdge = 1.0;
            else
                noEdge = 0.0;
        }
        if ( noEdge && i < (int)[[path list] count]-1 )
        {   lineCnt++;
            continue;
        }
        else if ( lineCnt <= 3 )
        {   lineCnt=0;
            continue;
        }
        mPrev.x = mPrev.y = -1;
        /* smoothen lines - allways ??? */
        for (j=i-lineCnt, k=0; k<lineCnt+1-1 && lineCnt > 3; k+=2, j+=2)
        {   VGraphic	*l1=[[path list] objectAtIndex:j];
            VGraphic	*l2=[[path list] objectAtIndex:j+1];
            NSPoint     m1, m2;

            [(VLine*)l1 getVertices:&s1 :&e1];
            [(VLine*)l2 getVertices:&s2 :&e2];
            m1 = CenterPoint(s1, e1);
            m2 = CenterPoint(s2, e2);
            if ( mPrev.x == -1 && mPrev.y == -1 ) // first
                [(VLine*)l1 setVertices:s1 :m1];
            else
                [(VLine*)l1 setVertices:mPrev :m1];
            [(VLine*)l2 setVertices:m1 :m2];
            mPrev = m2;
            if ( k >= lineCnt+1-3 ) // last
            {	VGraphic	*lineG=[VLine line];
                NSColor	*nxBlack = [NSColor colorWithCalibratedRed:0.0 green:0.0 blue:0.0 alpha:1.0];
                [lineG setColor:nxBlack]; [lineG setWidth:0]; [lineG setSelected:NO];
                [(VLine*)lineG setVertices:m2 :e2];
                [[path list] insertObject:lineG atIndex:j+2];
                i++;
            }
        }
        lineCnt = 0;
    }
}

/* modified:	30.01.00
 * go on building the path with these new points
 */
- (BOOL)pointIsEdge:(NSPoint)pt
{   int			byteY, byteX;
    unsigned char	byte, lbyte, rbyte, ubyte, dbyte, ulbyte, urbyte, dlbyte, drbyte;
    unsigned char	uullbyte, uurrbyte, ddllbyte, ddrrbyte, uulbyte, uurbyte, ddlbyte, ddrbyte;
    unsigned char	llbyte, rrbyte, uubyte, ddbyte, ullbyte, urrbyte, dllbyte, drrbyte;
    unsigned char	uuulllbyte, uuullbyte, uuulbyte, uuubyte, uuurbyte, uuurrbyte, uuurrrbyte;
    unsigned char	uulllbyte, uurrrbyte, ulllbyte, urrrbyte, lllbyte, rrrbyte, dlllbyte, drrrbyte, ddlllbyte;
    unsigned char	ddrrrbyte, dddlllbyte, dddllbyte, dddlbyte, dddbyte, dddrbyte, dddrrbyte, dddrrrbyte;

    byteY = pt.y * bytesPerRow;	/* the height */
    byteY = size - byteY - bytesPerRow;
    byteX = byteY + pt.x; /* the width in bytes */
    byte = *(data+byteX);

//    if ( byte != white )
//        return NO;

    lbyte = *(data+(byteX-1));			rbyte = *(data+(byteX+1));
    dbyte = *(data+byteX+bytesPerRow);		ubyte = *(data+byteX-bytesPerRow);
    ulbyte = *(data+(byteX-1) - bytesPerRow);	urbyte = *(data+(byteX+1) - bytesPerRow);
    dlbyte = *(data+(byteX-1) + bytesPerRow);	drbyte = *(data+(byteX+1) + bytesPerRow);

    uullbyte = *(data+(byteX-2)-(2*bytesPerRow));	uurrbyte = *(data+(byteX+2)-(2*bytesPerRow));
    ddllbyte = *(data+(byteX-2)+(2*bytesPerRow));	ddrrbyte = *(data+(byteX+2)+(2*bytesPerRow));
    uulbyte = *(data+(byteX-1)-(2*bytesPerRow));	uurbyte = *(data+(byteX+1)-(2*bytesPerRow));
    ddlbyte = *(data+(byteX-1)+(2*bytesPerRow));	ddrbyte = *(data+(byteX+1)+(2*bytesPerRow));
    uubyte = *(data+byteX-(2*bytesPerRow));		ddbyte = *(data+byteX+(2*bytesPerRow));
    llbyte = *(data+(byteX-2));				rrbyte = *(data+(byteX+2));
    ullbyte = *(data+(byteX-2) - bytesPerRow);		urrbyte = *(data+(byteX+2) - bytesPerRow);
    dllbyte = *(data+(byteX-2) + bytesPerRow);		drrbyte = *(data+(byteX+2) + bytesPerRow);

    uuulllbyte = *(data+(byteX-3)-(3*bytesPerRow));	uuurrrbyte = *(data+(byteX+3)-(3*bytesPerRow));
    uuullbyte = *(data+(byteX-2)-(3*bytesPerRow));	uuurrbyte = *(data+(byteX+2)-(3*bytesPerRow));
    uuulbyte = *(data+(byteX-1)-(3*bytesPerRow));	uuurbyte = *(data+(byteX+1)-(3*bytesPerRow));
    uuubyte = *(data+byteX-(3*bytesPerRow));		dddbyte = *(data+byteX+(3*bytesPerRow));
    lllbyte = *(data+(byteX-3));			rrrbyte = *(data+(byteX+3));
    dddlbyte = *(data+(byteX-1)+(3*bytesPerRow));	dddrbyte = *(data+(byteX+1)+(3*bytesPerRow));
    dddllbyte = *(data+(byteX-2)+(3*bytesPerRow));	dddrrbyte = *(data+(byteX+2)+(3*bytesPerRow));
    dddlllbyte = *(data+(byteX-3)+(3*bytesPerRow));	dddrrrbyte = *(data+(byteX+3)+(3*bytesPerRow));
    ulllbyte = *(data+(byteX-3) - bytesPerRow);		urrrbyte = *(data+(byteX+3) - bytesPerRow);
    dlllbyte = *(data+(byteX-3) + bytesPerRow);		drrrbyte = *(data+(byteX+3) + bytesPerRow);
    uulllbyte = *(data+(byteX-3)-(2*bytesPerRow));	uurrrbyte = *(data+(byteX+3)-(2*bytesPerRow));
    ddlllbyte = *(data+(byteX-3)+(2*bytesPerRow));	ddrrrbyte = *(data+(byteX+3)+(2*bytesPerRow));

    if ( !rbyte && !dbyte )
    {
        if ( !uuurbyte && !uuurrbyte && !uuurrrbyte && !uurrrbyte && !urrrbyte && !rrrbyte && !drrrbyte && !ddrrrbyte &&
            !dddrrrbyte && !dddrrbyte && !dddrbyte && !dddbyte && !dddlbyte && !dddllbyte &&
            !uurbyte && !uurrbyte && !urbyte && !urrbyte && !rrbyte && !drbyte && !drrbyte && !ddrbyte && !ddrrbyte &&
            !ddbyte && !ddlbyte )
            return YES;
        if ( !dlllbyte && !ddlllbyte && !dddlllbyte && !dddllbyte && !dddlbyte && !dddbyte && !dddrbyte && !dddrrbyte &&
            !dddrrrbyte && !ddrrrbyte && !drrrbyte && !rrrbyte && !urrrbyte && !uurrrbyte &&
            !urrbyte && !rrbyte && !drbyte && !drrbyte && !ddrbyte && !ddrrbyte && !ddbyte && !ddlbyte && !dlbyte &&
            !dllbyte && !ddllbyte )
            return YES;
    }
    if ( !rbyte && !ubyte )
    {
        if ( !uuullbyte && !uuulbyte && !uuubyte && !uuurbyte && !uuurrbyte && !uuurrrbyte && !uurrrbyte && !urrrbyte &&
            !rrrbyte && !drrrbyte && ddrrrbyte && !dddrrrbyte && !dddrrbyte && !dddrbyte &&
            !uulbyte && !uubyte && !uurbyte && !uurrbyte && !urbyte && !urrbyte && !rrbyte && !drbyte && !drrbyte &&
            !ddrbyte && !ddrrbyte )
            return YES;
        if ( !ulllbyte && !uulllbyte && !uuulllbyte && !uuullbyte && !uuulbyte && !uuubyte && !uuurbyte && !uuurrbyte &&
            !uuurrrbyte && !uurrrbyte && !urrrbyte && !rrrbyte && !drrrbyte && !ddrrrbyte &&
            !uullbyte && !ullbyte && !uulbyte && !ulbyte && !uubyte && !uurbyte && !uurrbyte &&!urbyte && !urrbyte &&
            !rrbyte && !drrbyte )
            return YES;
    }
    if ( !lbyte && !ubyte )
    {
        if ( !urrrbyte && !uurrrbyte && !uuurrrbyte && !uuurrbyte && !uuurbyte && !uuubyte && !uuulbyte && !uuullbyte &&
            !uuulllbyte && !uulllbyte && !ulllbyte && !lllbyte && !dlllbyte && !ddlllbyte &&
            !uullbyte && !uulbyte && !uubyte && !uurbyte && !uurrbyte && !urbyte && !urrbyte && !ulbyte && !ullbyte &&
            !llbyte && !dllbyte )
            return YES;
        if ( !uuurrbyte && !uuurbyte && !uuubyte && !uuulbyte && !uuullbyte && !uuulllbyte && !uulllbyte && !ulllbyte &&
            !lllbyte && !dlllbyte && !ddlllbyte && !dddlllbyte && !dddllbyte && !dddlbyte &&
            !uullbyte && !uulbyte && !uubyte && !uurbyte && !ulbyte && !ullbyte && !llbyte && !dllbyte && !dlbyte &&
            !ddllbyte && !ddlbyte )
            return YES;
    }
    if ( !lbyte && !dbyte )
    {
        if ( !uuulbyte && !uuullbyte && !uuulllbyte && !uulllbyte && !ulllbyte && !lllbyte && !dlllbyte && !ddlllbyte &&
            !dddlllbyte && !dddllbyte && !dddlbyte && !dddbyte && !dddrbyte && !dddrrbyte &&
            !uullbyte && !uulbyte && !ullbyte && !ulbyte && !llbyte && !dllbyte && !dlbyte && !ddllbyte && !ddlbyte &&
            !ddrbyte && !ddbyte )
            return YES;
        if ( !uulllbyte && !ulllbyte && !lllbyte && !dlllbyte && !ddlllbyte && !dddlllbyte && !dddllbyte && !dddlbyte &&
            !dddbyte && !dddrbyte && !dddrrbyte && !dddrrrbyte && !ddrrrbyte && !drrrbyte &&
            !ullbyte && !llbyte && !dllbyte && !dlbyte && !drbyte && !drrbyte && !ddllbyte && !ddlbyte && !ddbyte &&
            !ddrbyte && !ddrrbyte )
            return YES;
    }
    // the same++ for white !!!
    if ( rbyte==white && dbyte==white && ubyte==white )
    {
        if ( white==uubyte && white==uuubyte && white==dlbyte && white==ddllbyte && white==dddlllbyte &&
            white==uuurbyte && white==uuurrbyte && white==uuurrrbyte && white==uurrrbyte && white==urrrbyte &&
            white==rrrbyte && white==drrrbyte && white==ddrrrbyte && white==dddrrrbyte && white==dddrrbyte &&
            white==dddrbyte && white==dddbyte && white==dddlbyte && white==dddllbyte && white==uurbyte &&
            white==uurrbyte && white==urbyte && white==urrbyte && white==rrbyte && white==drbyte && white==drrbyte &&
            white==ddrbyte && white==ddrrbyte && white==ddbyte && white==ddlbyte )
            return YES;
        if ( white==ddbyte && white==dddbyte && white==uuulllbyte && white==uullbyte && white==ulbyte &&
            white==uuullbyte && white==uuulbyte && white==uuubyte && white==uuurbyte && white==uuurrbyte &&
            white==uuurrrbyte && white==uurrrbyte && white==urrrbyte && white==rrrbyte && white==drrrbyte &&
            ddrrrbyte && white==dddrrrbyte && white==dddrrbyte && white==dddrbyte && white==uulbyte &&
            white==uubyte && white==uurbyte && white==uurrbyte && white==urbyte && white==urrbyte && white==rrbyte &&
            white==drbyte && white==drrbyte && white==ddrbyte && white==ddrrbyte )
            return YES;
    }
    if ( white==rbyte && white==ubyte && white==lbyte )
    {
        if ( white==rrbyte && white==rrrbyte && white==dlbyte && ddllbyte && dddlllbyte &&
            white==urrrbyte && white==uurrrbyte && white==uuurrrbyte && white==uuurrbyte && white==uuurbyte &&
            white==uuubyte && white==uuulbyte && white==uuullbyte && white==uuulllbyte && white==uulllbyte &&
            white==ulllbyte && white==lllbyte && white==dlllbyte && white==ddlllbyte && white==uullbyte &&
            white==uulbyte && white==uubyte && white==uurbyte && white==uurrbyte && white==urbyte && white==urrbyte &&
            white==ulbyte && white==ullbyte && white==llbyte && white==dllbyte )
            return YES;
        if ( white==llbyte && white==lllbyte && white==drbyte && white==ddrrbyte && dddrrrbyte &&
            white==ulllbyte && white==uulllbyte && white==uuulllbyte && white==uuullbyte && white==uuulbyte &&
            white==uuubyte && white==uuurbyte && white==uuurrbyte && white==uuurrrbyte && white==uurrrbyte &&
            white==urrrbyte && white==rrrbyte && white==drrrbyte && white==ddrrrbyte && white==uullbyte &&
            white==ullbyte && white==uulbyte && white==ulbyte && white==uubyte && white==uurbyte && white==uurrbyte &&
            white==urbyte && white==urrbyte && white==rrbyte && white==drrbyte )
            return YES;
    }
    if ( white==lbyte && white==ubyte && white==dbyte )
    {
        if ( white==uubyte && white==uuubyte && white==drbyte && white==ddrrbyte && dddrrrbyte &&
            white==uuulbyte && white==uuullbyte && white==uuulllbyte && white==uulllbyte && white==ulllbyte &&
            white==lllbyte && white==dlllbyte && white==ddlllbyte && white==dddlllbyte && white==dddllbyte &&
            white==dddlbyte && white==dddbyte && white==dddrbyte && white==dddrrbyte && white==uullbyte &&
            white==uulbyte && white==ullbyte && white==ulbyte && white==llbyte && white==dllbyte && white==dlbyte &&
            white==ddllbyte && white==ddlbyte && white==ddrbyte && white==ddbyte )
            return YES;
        if ( white==ddbyte && white==dddbyte && white==ulbyte && white==uullbyte && white==uuulllbyte &&
            white==uuurrbyte && white==uuurbyte && white==uuubyte && white==uuulbyte && white==uuullbyte &&
            white==uuulllbyte && white==uulllbyte && white==ulllbyte && white==lllbyte && white==dlllbyte &&
            white==ddlllbyte && white==dddlllbyte && white==dddllbyte && white==dddlbyte && white==uullbyte &&
            white==uulbyte && white==uubyte && white==uurbyte && white==ulbyte && white==ullbyte && white==llbyte &&
            white==dllbyte && white==dlbyte && white==ddllbyte && white==ddlbyte )
            return YES;
    }
    if ( white==lbyte && white==dbyte && white==rbyte )
    {
        if ( white==llbyte && white==lllbyte && white==urbyte && white==uurrbyte && white==uuurrrbyte &&
            white==dlllbyte && white==ddlllbyte && white==dddlllbyte && white==dddllbyte && white==dddlbyte &&
            white==dddbyte && white==dddrbyte && white==dddrrbyte && white==dddrrrbyte && white==ddrrrbyte &&
            white==drrrbyte && white==rrrbyte && white==urrrbyte && white==uurrrbyte && white==urrbyte &&
            white==rrbyte && white==drbyte && white==drrbyte && white==ddrbyte && white==ddrrbyte && white==ddbyte &&
            white==ddlbyte && white==dlbyte && white==dllbyte && white==ddllbyte )
            return YES;
        if ( white==rrbyte && white==rrrbyte && white==ulbyte && white==uullbyte && white==uuulllbyte &&
            white==uulllbyte && white==ulllbyte && white==lllbyte && white==dlllbyte && white==ddlllbyte &&
            white==dddlllbyte && white==dddllbyte && white==dddlbyte && white==dddbyte && white==dddrbyte &&
            white==dddrrbyte && white==dddrrrbyte && white==ddrrrbyte && white==drrrbyte && white==ullbyte &&
            white==llbyte && white==dllbyte && white==dlbyte && white==drbyte && white==drrbyte && white==ddllbyte &&
            white==ddlbyte && white==ddbyte && white==ddrbyte && white==ddrrbyte )
            return YES;
    }

    if ( !lbyte && !dbyte && !rbyte )
    {   unsigned char	ullllbyte, llllbyte, dllllbyte, urrrrbyte, rrrrbyte, drrrrbyte;

        llllbyte = *(data+(byteX-4));			rrrrbyte = *(data+(byteX+4));
        ullllbyte = *(data+(byteX-4) - bytesPerRow);	urrrrbyte = *(data+(byteX+4) - bytesPerRow);
        dllllbyte = *(data+(byteX-4) + bytesPerRow);	drrrrbyte = *(data+(byteX+4) + bytesPerRow);

        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 )
            return YES;
    }
    if ( !lbyte && !ubyte && !rbyte )
    {   unsigned char	ullllbyte, llllbyte, dllllbyte, urrrrbyte, rrrrbyte, drrrrbyte;

        llllbyte = *(data+(byteX-4));			rrrrbyte = *(data+(byteX+4));
        ullllbyte = *(data+(byteX-4) - bytesPerRow);	urrrrbyte = *(data+(byteX+4) - bytesPerRow);
        dllllbyte = *(data+(byteX-4) + bytesPerRow);	drrrrbyte = *(data+(byteX+4) + bytesPerRow);

        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 )
            return YES;
    }
    if ( !ubyte && !dbyte && !rbyte )
    {   unsigned char	uuuubyte, ddddbyte, uuuulbyte, uuuurbyte, ddddlbyte, ddddrbyte;

        uuuubyte = *(data+byteX-(4*bytesPerRow));	ddddbyte = *(data+byteX+(4*bytesPerRow));
        uuuulbyte = *(data+(byteX-1)-(4*bytesPerRow));	uuuurbyte = *(data+(byteX+1)-(4*bytesPerRow));
        ddddlbyte = *(data+(byteX-1)+(4*bytesPerRow));	ddddrbyte = *(data+(byteX+1)+(4*bytesPerRow));

        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 )
            return YES;
    }
    if ( !ubyte && !dbyte && !lbyte )
    {   unsigned char	uuuubyte, ddddbyte, uuuulbyte, uuuurbyte, ddddlbyte, ddddrbyte;

        uuuubyte = *(data+byteX-(4*bytesPerRow));	ddddbyte = *(data+byteX+(4*bytesPerRow));
        uuuulbyte = *(data+(byteX-1)-(4*bytesPerRow));	uuuurbyte = *(data+(byteX+1)-(4*bytesPerRow));
        ddddlbyte = *(data+(byteX-1)+(4*bytesPerRow));	ddddrbyte = *(data+(byteX+1)+(4*bytesPerRow));

        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 )
            return YES;
    }
//white
    return NO;
}

- (void)connectPtToLine:(int)indexL :(NSPoint)pt :(int*)endIsNearer :(int*)lineArray :(VPath*)path :(float)w
{   int	edge=0;
    float	minLineLength=81, minLineLenHV=7, len;
    NSPoint	start, end;
    VGraphic	*lineG = [[path list] objectAtIndex:lineArray[indexL]];

    if ( Abs(w) < 0.29 ) // < 0.1 mm
    {   minLineLength = 25; minLineLenHV = 5; }
    if ( Abs(w) >= 0.29 ) // >= 0.1 mm
    {   minLineLength = 36; minLineLenHV = 5; }
    if ( Abs(w) >= 0.86 ) // >= 0.3 mm
    {   minLineLength = 49; minLineLenHV = 5; }
    if ( Abs(w) >= 1.42 ) // >= 0.5 mm
    {   minLineLength = 64; minLineLenHV = 6; }
    if ( Abs(w) >= 2.83 ) // >= 1.0 mm
    {   minLineLength = 81; minLineLenHV = 7; }
    if ( Abs(w) >= 5.6 ) // >= 2.0 mm
    {   minLineLength = 100; minLineLenHV = 8; }

    [(VLine*)lineG getVertices:&start :&end];
    ( *endIsNearer ) ? (len=SqrDistPoints(start, pt)) : (len=SqrDistPoints(end, pt));
    //lenOld = SqrDistPoints(start, end);
    if ( [self pointIsEdge:pt] )
        edge = 1;
    if ( start.x == end.x && start.y == end.y ) // have at least started a new line
    {
        if ( edge && ![self pointIsEdge:start] )
        {   [lineG setSelected:YES];
            [(VLine*)lineG setVertices:pt :pt];
        }
        else [(VLine*)lineG setVertices:start :pt];
    }
    else if ( (start.x == end.x && Diff(start.y, end.y) >= minLineLenHV) ||
             (start.y == end.y && Diff(start.x, end.x) >= minLineLenHV) )
    {   // vertical lines not so long !
        if ( /*len > lenOld &&*/ ((len <= minLineLength && start.x == end.x && pt.x == start.x)
                                 || (start.y == end.y && pt.y == start.y)) )
        {
            if ( [lineG isSelected] &&
                ((!(*endIsNearer)  && [self pointIsEdge:start]) || (endIsNearer && [self pointIsEdge:end])) )
            {   // else we would change the edge !
                lineG = [VLine line];
                [lineG setSelected:YES]; [lineG setColor:[NSColor blackColor]]; [lineG setWidth:0];
                [(VLine*)lineG setVertices:pt :pt];
                [[path list] addObject:lineG]; *endIsNearer = 1;
                lineArray[indexL] = (int)[[path list] count]-1; // replace value at indexL with new line index
            }
            else // connect
            {   if ( *endIsNearer ) [(VLine*)lineG setVertices:start :pt];
                else		   [(VLine*)lineG setVertices:pt :end]; // here other direction is ok
                if ( edge )
                {   [lineG setSelected:YES];
                    lineG = [VLine line]; [lineG setSelected:YES];
                    [lineG setColor:[NSColor blackColor]]; [lineG setWidth:0];
                    [(VLine*)lineG setVertices:pt :pt]; *endIsNearer = 1;
                    [[path list] addObject:lineG];
                    lineArray[indexL] = (int)[[path list] count]-1; // replace value at indexL with new line index
                }
            }
        }
        else // if ( len <= lenOld )
        {   lineG = [VLine line]; ( edge ) ? [lineG setSelected:YES] : [lineG setSelected:NO];
            [lineG setColor:[NSColor blackColor]]; [lineG setWidth:0];
            if ( *endIsNearer ) [(VLine*)lineG setVertices:end :pt];
            else	      { [(VLine*)lineG setVertices:start :pt]; *endIsNearer = 1; }
            [[path list] addObject:lineG];
            lineArray[indexL] = (int)[[path list] count]-1; // replace value at indexL with new line index
        }
    }
    else // no vertical / horicontal line
    {
        if ( /*len > lenOld &&*/ len <= minLineLength )
        {
            if ( [lineG isSelected] && // start or end is edge point - do not change !!!
                ((!(*endIsNearer)  && [self pointIsEdge:start]) || (*endIsNearer && [self pointIsEdge:end])) )
            {   // else we would change the edge !
                lineG = [VLine line];
                [lineG setSelected:YES]; [lineG setColor:[NSColor blackColor]]; [lineG setWidth:0];
                [(VLine*)lineG setVertices:pt :pt]; *endIsNearer = 1;
                [[path list] addObject:lineG];
                lineArray[indexL] = (int)[[path list] count]-1; // replace value at indexL with new line index
            }
            else
            {   if ( *endIsNearer ) [(VLine*)lineG setVertices:start :pt];
                else		  { [(VLine*)lineG setVertices:end :pt]; *endIsNearer = 1; }// change direction !
                if ( edge )
                {   [lineG setSelected:YES];
                    lineG = [VLine line];
                    [lineG setSelected:YES]; [lineG setColor:[NSColor blackColor]]; [lineG setWidth:0];
                    [(VLine*)lineG setVertices:pt :pt]; *endIsNearer = 1;
                    [[path list] addObject:lineG];
                    lineArray[indexL] = (int)[[path list] count]-1; // replace value at indexL with new line index
                }
            }
        }
#if 0
                else if ( len <= lenOld )
                {   lineG = [VLine line]; ( edge ) ? [lineG setSelected:YES] : [lineG setSelected:NO];
                    [lineG setColor:[NSColor blackColor]]; [lineG setWidth:0];
                    [(VLine*)lineG setVertices:pt :pt]; *endIsNearer = 1;
                    [[path list] addObject:lineG];
                    lineArray[indexL] = (int)[[path list] count]-1; // replace value at indexL with new line index
                    return;
                }
#endif
        else
        {
            if ( [lineG isSelected] &&
                ((!(*endIsNearer)  && [self pointIsEdge:start]) || (endIsNearer && [self pointIsEdge:end])) )
            {   // else we would change the edge !
                lineG = [VLine line];
                [lineG setSelected:YES]; [lineG setColor:[NSColor blackColor]]; [lineG setWidth:0];
                [(VLine*)lineG setVertices:pt :pt]; *endIsNearer = 1;
                [[path list] addObject:lineG];
                lineArray[indexL] = (int)[[path list] count]-1; // replace value at indexL with new line index
            }
            else
            {   if ( edge )
                {   if ( *endIsNearer ) { [(VLine*)lineG setVertices:start :pt]; end=pt; }
                    else	       { [(VLine*)lineG setVertices:end :pt]; start = pt; }
                    [lineG setSelected:YES];
                }
                lineG = [VLine line]; ( edge ) ? [lineG setSelected:YES] : [lineG setSelected:NO];
                [lineG setColor:[NSColor blackColor]]; [lineG setWidth:0];
                if ( *endIsNearer ) [(VLine*)lineG setVertices:end :pt];
                else		   { [(VLine*)lineG setVertices:start :pt]; *endIsNearer = 1; }
                [[path list] addObject:lineG];
                lineArray[indexL] = (int)[[path list] count]-1; // replace value at indexL with new line index
            }
        }
    }
}

/* modified:	2008-02-08
 * go on building the path with these new points
 */
- (void)buildPath:(VPath*)path :(NSPoint*)pts :(int)pCnt :(float)w :(int*)lineArray :(int*)lineCnt
{   int         i, j, k, myPcnt=pCnt, startNewLine = 0; // lineArray[pCnt*2], lineCnt=0
    NSPoint     start, end, s, e;
    VGraphic    *lineG, *lineG2;
    NSColor     *nxBlack = [NSColor colorWithCalibratedRed:0.0 green:0.0 blue:0.0 alpha:1.0];

    if ( ![[path list] count] && pCnt)
    {
        if ( pCnt > 1 && Diff(pts[0].x, pts[1].x) <= 1 ) // waagerechte ?
        {   for (i=0; i<2; i++)
            {   lineG = [VLine line]; ( [self pointIsEdge:pts[0]] ) ? [lineG setSelected:YES] : [lineG setSelected:NO];
                [lineG setColor:nxBlack]; [lineG setWidth:0];
                [(VLine*)lineG setVertices:pts[0] :pts[0]];
                [[path list] addObject:lineG];
                lineArray[(*lineCnt)++] = i;
                for (k=0; k<myPcnt-1; k++)
                    pts[k] = pts[k+1];
                myPcnt--;
            }
        }
        else // start two lines !
        {   for (i=0; i<2; i++)
            {   lineG = [VLine line]; ( [self pointIsEdge:pts[0]] ) ? [lineG setSelected:YES] : [lineG setSelected:NO];
                [lineG setColor:nxBlack]; [lineG setWidth:0];
                [(VLine*)lineG setVertices:pts[0] :pts[0]];
                [[path list] addObject:lineG];
                lineArray[(*lineCnt)++] = i;
            }
            for (k=0; k<myPcnt-1; k++)
                pts[k] = pts[k+1];
            myPcnt--;
        }
    }

    while ( myPcnt > 0 )
    {
        // connect pts to lines
        for (i=0; i<(*lineCnt); i++)
        {   int	endIsNearer=-1, indexE=-1, indexS=-1, secondLine=0, endIsNearer2=0;
            int	fromLeftToRight=1, stopForLine2 = 0, secDiff=0, doNotRemovePtJ = 0, rowDiff=0;
            NSPoint	stopPt = NSZeroPoint, lastRowPt;

            if ( myPcnt <= 0 && startNewLine )
                break; // else we must remove lines with no point !!

            lineG=[[path list] objectAtIndex:lineArray[i]];
            [(VLine*)lineG getVertices:&start :&end];
            // first get nearest pt to lineG
            for (j=0; j<myPcnt; j++)
            {
                if ( indexS == -1 && end.y >= start.y && // indexS allways set -> do not set indexE !!!
                    Diff(pts[j].x, end.x) <= 1 && Diff(pts[j].y, end.y) <= 1 &&
                    Diff(pts[j].x, end.x) <= Diff(pts[j].x, start.x) && end.y >= start.y &&
                    ((indexE == -1 || (Diff(pts[j].x, end.x) < Diff(pts[indexE].x, end.x))) ||
                    (indexE != -1 && Diff(pts[j].x, end.x) == Diff(pts[indexE].x, end.x) && end.x > start.x)) )
                    // line from le to ri -> prefer ri pt
                {   indexE = j; endIsNearer = 1; }
                else if ( indexE == -1 && start.y >= end.y && // (start.x != end.x || start.y != end.y) &&
                          Diff(pts[j].x, start.x) <= 1 && Diff(pts[j].y, start.y) <= 1 &&
                          Diff(pts[j].x, start.x) <= Diff(pts[j].x, end.x) && start.y >= end.y &&
                          ((indexS == -1 || (Diff(pts[j].x, start.x) < Diff(pts[indexS].x, start.x))) ||
                           (indexS != -1 && Diff(pts[j].x, start.x) == Diff(pts[indexS].x, start.x) && start.x > end.x)) )
                {   indexS = j; endIsNearer = 0; }
                else if ( (end.y > start.y && pts[j].x > end.x+1) || (start.y > end.y && pts[j].x > start.x+1) ||
                          (end.y == start.y && pts[j].x > end.x+1 && pts[j].x > start.x+1) )
                    break;
            }
            if ( indexE == -1 && indexS == -1 )
            {   int	m;
                if ( !(start.x == end.x && start.y == end.y && start.y == pts[0].y) && !startNewLine )
                {   for (m=i; m<(*lineCnt)-1; m++) // sort out line from lineArray
                        lineArray[m] = lineArray[m+1];
                    (*lineCnt)--;
                    i--; // else we jump over one line
                }
                continue;
            }
            ( endIsNearer ) ? (j = indexE) : (j=indexS); // must set j !!!!!!!!!!!!!!!!!!!

            // check if pt row
            rowDiff = 0;
            for (k=j; k<myPcnt-1 && i<(*lineCnt)-1; k++)
            {   if ( Diff(pts[k].x, pts[k+1].x) <= 1 )
                {   rowDiff = (k+1)-j; lastRowPt = pts[k+1]; }
                else break;
            }
            rowDiff += 2; // min of two - if one pt and two lines !!

            // look for a second line right of lineG with rowDist distance
            if ( i < (*lineCnt)-1 )
            {   NSPoint	tp;
                lineG2 = [[path list] objectAtIndex:lineArray[i+1]];
                [(VLine*)lineG2 getVertices:&s :&e];
                if ( s.y > e.y ) tp = s;
                else if ( e.y > s.y ) tp = e;
                else tp = e; // if ( pts[j].x <= s.x && pts[j].x <= e.x ) - only possible !
                if ( ( endIsNearer && (secDiff=Diff(  end.x, tp.x)) <= rowDiff) ||
                     (!endIsNearer && (secDiff=Diff(start.x, tp.x)) <= rowDiff) )
                {   secondLine = 1; secDiff += 2;
                    endIsNearer2 = 1; // allways the end
                }
            }
            // set connect direction and j if necessary !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
            // pts on both sides of pts[j]
            if ( ((!secondLine && j-1 >= 0 && Diff(pts[j-1].x, pts[j].x) <= 1) ||
                  (secondLine && j-1 >= 0 && Diff(pts[j-1].x, pts[j].x) <= secDiff)) &&
                 ((!secondLine && j+1 < myPcnt && Diff(pts[j+1].x, pts[j].x) <= 1) ||
                  (secondLine && j+1 < myPcnt && Diff(pts[j+1].x, pts[j].x) <= secDiff)) )
            {
                // look for direction of line ???
                if ( (endIsNearer && end.x <= start.x) || (!endIsNearer && start.x <= end.x) ||
                    (secondLine && e.x <= s.x) )
                    fromLeftToRight = 0; // start right - at j
                else if ( (endIsNearer && end.x > start.x) || (!endIsNearer && start.x > end.x) ||
                          (secondLine && e.x > s.x) )
                    fromLeftToRight = 1; // start left - at j until stopPt !!
            }
            // pts left of pts[j]
            else if ( (!secondLine && j-1 >= 0 && Diff(pts[j-1].x, pts[j].x) <= 1) ||
                    (secondLine && j-1 >= 0 && Diff(pts[j-1].x, pts[j].x) <= secDiff) )
            {
                fromLeftToRight = 0;
                if ( secondLine && Diff(pts[j].x, pts[j-1].x) <= 1 )
                    doNotRemovePtJ = 1; // need j also for second line
                else if ( secondLine )
                    j = j-1; // must connect one pt to second line !
                if ( !secondLine && ((endIsNearer && start.x < end.x) || (!endIsNearer && end.x < start.x)) &&
                    [self pointIsEdge:pts[j]] ) // direction change !!
                {   int	m;
                    lineG = [VLine line]; // start a new line !!!
                    [lineG setSelected:YES]; [lineG setColor:nxBlack]; [lineG setWidth:0];
                    [(VLine*)lineG setVertices:pts[j] :pts[j]]; start = end = pts[j];
                    [[path list] addObject:lineG];
                    lineArray[i] = (int)[[path list] count]-1; // replace line index
                    for (m=j; m<myPcnt-1; m++) // sort out pt j from pts
                        pts[m] = pts[m+1];
                    myPcnt--;
                }
            }
            // pts right of pts[j]
            else if ( (!secondLine && j+1 < myPcnt && Diff(pts[j+1].x, pts[j].x) <= 1) ||
                    (secondLine && j+1 < myPcnt && Diff(pts[j+1].x, pts[j].x) <= secDiff) )
            {
                fromLeftToRight = 1;
                if ( !secondLine && ((endIsNearer && start.x > end.x) || (!endIsNearer && end.x > start.x)) &&
                    [self pointIsEdge:pts[j]] )
                {   int	m;
                    lineG = [VLine line]; // start a new line !!!
                    [lineG setSelected:YES]; [lineG setColor:nxBlack]; [lineG setWidth:0];
                    [(VLine*)lineG setVertices:pts[j] :pts[j]]; start = end = pts[j];
                    [[path list] addObject:lineG];
                    lineArray[i] = (int)[[path list] count]-1; // replace line index
                    for (m=j; m<myPcnt-1; m++) // sort out pt j from pts
                        pts[m] = pts[m+1];
                    myPcnt--;
                }
            }
            else if ( secondLine && ((s.x == e.x && s.y == e.y) ||     // set point to new/right line !!
                                     (start.y == end.y && pts[j].y > end.y)) ) continue;
            else if ( secondLine && ((endIsNearer && (start.x != s.x || start.y != s.y)) ||
                                     (!endIsNearer && (end.x != e.x || end.y != e.y))) )
                doNotRemovePtJ = 1; // only one pt for both lines - for peaks at top /\ !

            // search stop pt for second line !!!
            if ( fromLeftToRight && secondLine && !doNotRemovePtJ && j+1 < myPcnt )
            {
                if ( ((endIsNearer && start.x > end.x) || (!endIsNearer && end.x > start.x)) )
                {   stopPt = pts[j+1]; stopForLine2 = 1; } // only one pt to connect for lineG !! - other direction
                else
                {   // get nearest pt to second line - is our stop PT
                    indexE = indexS = -1;
                    for (k=j+1; k<myPcnt; k++)
                    {
                        if ( e.y >= s.y && Diff(pts[k].x, e.x) <= 1 && Diff(pts[k].y, e.y) <= 1 &&
                            Diff(pts[k].x, e.x) <= Diff(pts[k].x, s.x) && e.y >= s.y )
                            //(indexE == -1 || (Diff(pts[k].x, e.x) <= Diff(pts[indexE].x, e.x))) // need right pt
                        {   stopPt = pts[k]; indexE = k; endIsNearer2 = 1; }
                        else if ( indexE == -1 && s.y >= e.y && // (s.x != e.x || s.y != e.y) &&
                                 Diff(pts[k].x, s.x) <= 1 && Diff(pts[k].y, s.y) <= 1 &&
                                 Diff(pts[k].x, s.x) <= Diff(pts[k].x, e.x) && s.y >= e.y )
                                //(indexS == -1 || (Diff(pts[k].x, s.x) <= Diff(pts[indexS].x, s.x))) 
                        {   stopPt = pts[k]; indexS = k; endIsNearer2 = 0; }
                        else if ( (e.y > s.y && pts[j].x > e.x+1) || (s.y > e.y && pts[j].x > s.x+1) ||
                                 (e.y == s.y && pts[j].x > e.x+1 && pts[j].x > s.x+1) )
                            break;
                    }
    //                if ( indexE == -1 && indexS == -1 )
    //                    printf("no StopPt found ???\n"); // ??????????????????????????????????????????
                    if ( indexE != -1 || indexS != -1 )
                        stopForLine2 = 1; // must stop connect to rest pts for second line
                }
            }

            // connect pts to line(s)
            if ( fromLeftToRight && !stopForLine2 )
            {   int	m;
                for (k=j; k<myPcnt; k++)
                {
                    if ( ( endIsNearer && Diff(pts[k].x,   end.x) <= 1) ||
                         (!endIsNearer && Diff(pts[k].x, start.x) <= 1) )
                    {   [self connectPtToLine:i :pts[k] :&endIsNearer :lineArray :path :w];
                        lineG = [[path list] objectAtIndex:lineArray[i]]; // must set lineG new !!!
                        [(VLine*)lineG getVertices:&start :&end]; // must set start / end new !!!
                        if ( !doNotRemovePtJ )
                        {   for (m=k; m<myPcnt-1; m++) // sort out pt j from pts
                                pts[m] = pts[m+1];
                            myPcnt--;
                            k--;
                        }
                        else doNotRemovePtJ = 0; // only first pt
                    }
                    else break;
                }
            }
            else if ( fromLeftToRight && stopForLine2 )
            {   int	m;
                for (k=j; k<myPcnt; k++)
                {
                    if ( (pts[k].x != stopPt.x || pts[k].y != stopPt.y) && // do not connect stopPt
                         (( endIsNearer && Diff(pts[k].x,   end.x) <= 1) ||
                          (!endIsNearer && Diff(pts[k].x, start.x) <= 1)) )
                    {   [self connectPtToLine:i :pts[k] :&endIsNearer :lineArray :path :w];
                        lineG = [[path list] objectAtIndex:lineArray[i]]; // must set lineG new !!!
                        [(VLine*)lineG getVertices:&start :&end]; // must set start / end new !!!
                        if ( !doNotRemovePtJ )
                        {   for (m=k; m<myPcnt-1; m++) // sort out pt j from pts
                            pts[m] = pts[m+1];
                            myPcnt--;
                            k--;
                        }
                        else doNotRemovePtJ = 0;
                    }
                    else break;
                }
            }
            else if ( !fromLeftToRight ) // connect pts from right to left start with k -> first line if we have two lines !
            {   int	m;
                for (k=j; k>=0; k--)
                {
                    if ( ( endIsNearer && Diff(pts[k].x,   end.x) <= 1) ||
                         (!endIsNearer && Diff(pts[k].x, start.x) <= 1) )
                    {   [self connectPtToLine:i :pts[k] :&endIsNearer :lineArray :path :w];
                        lineG = [[path list] objectAtIndex:lineArray[i]]; // must set lineG new !!!
                        [(VLine*)lineG getVertices:&start :&end]; // must set start / end new !!!
                        if ( !doNotRemovePtJ )
                        {   for (m=k; m<myPcnt-1; m++) // sort out pt j from pts
                                pts[m] = pts[m+1];
                            myPcnt--;
                        }
                        else doNotRemovePtJ = 0;
                    }
                    else break;
                }
            }
        }
        // start new lines - with one not connected pt -> one more the same !!
        if ( myPcnt > 0 )
        {   int	m, rightPtI=0;

            // check if pt row
            for (k=0; k<myPcnt-1; k++)
            {   if ( Diff(pts[k].x, pts[k+1].x) <= 1 )
                {   rightPtI = k+1; }
                else
                    break;
            }
            if ( rightPtI && [self pointIsEdge:pts[rightPtI]] )
            {
                lineG = [VLine line]; [lineG setSelected:YES];
                [lineG setColor:nxBlack]; [lineG setWidth:0];
                [(VLine*)lineG setVertices:pts[rightPtI] :pts[rightPtI]];
                [[path list] addObject:lineG];
                lineArray[(*lineCnt)++] = (int)[[path list] count]-1; // add line index to lineArray
                for (m=rightPtI; m<myPcnt-1; m++) // sort out pts[r] j from pts
                    pts[m] = pts[m+1];
                myPcnt--;

                lineG = [VLine line];
                ( [self pointIsEdge:pts[rightPtI-1]] ) ? [lineG setSelected:YES] : [lineG setSelected:NO];
                [lineG setColor:nxBlack]; [lineG setWidth:0];
                [(VLine*)lineG setVertices:pts[rightPtI-1] :pts[rightPtI-1]];
                [[path list] addObject:lineG];
                lineArray[(*lineCnt)++] = (int)[[path list] count]-1; // add line index to lineArray
                for (m=rightPtI-1; m<myPcnt-1; m++) // sort out pts[...-1] j from pts
                    pts[m] = pts[m+1];
                myPcnt--;
            }
            else
            {   lineG = [VLine line]; ( [self pointIsEdge:pts[0]] ) ? [lineG setSelected:YES] : [lineG setSelected:NO];
                [lineG setColor:nxBlack]; [lineG setWidth:0];
                [(VLine*)lineG setVertices:pts[0] :pts[0]];
                [[path list] addObject:lineG];
                lineArray[(*lineCnt)++] = (int)[[path list] count]-1; // add line index to lineArray
                if ( [self pointIsEdge:pts[0]] )
                {
                    if ( myPcnt > 1 && Diff(pts[0].x, pts[1].x) <= 1 ) // pts[1] is second line !!!
                    {   for (m=0; m<myPcnt-1; m++) // sort out pts[0] j from pts
                            pts[m] = pts[m+1];
                        myPcnt--;
                    }
                    lineG = [VLine line];[lineG setSelected:YES];
                    [lineG setColor:nxBlack]; [lineG setWidth:0];
                    [(VLine*)lineG setVertices:pts[0] :pts[0]];
                    [[path list] addObject:lineG];
                    lineArray[(*lineCnt)++] = (int)[[path list] count]-1; // add line index to lineArray
                }
                for (m=0; m<myPcnt-1; m++) // sort out pts[0] j from pts
                    pts[m] = pts[m+1];
                myPcnt--;
            }
            startNewLine = 1; // we do not remove lines in second part to connect rest points

            // sort line indexes from left line to right line
            for (i=0; i<(*lineCnt)-1; i++)
            {   VGraphic	*g1=[[path list] objectAtIndex:lineArray[i]];

                [(VLine*)g1 getVertices:&start :&end];
                for (j=i+1; j<(*lineCnt); j++)
                {   VGraphic	*g2=[[path list] objectAtIndex:lineArray[j]];

                    [(VLine*)g2 getVertices:&s :&e];
                    if ( (e.y > s.y && e.x < ((end.y > start.y) ? (end.x) : (start.x))) ||
                         (e.y < s.y && s.x < ((end.y > start.y) ? (end.x) : (start.x))) ||
                         (e.y == s.y && s.x < ((end.y > start.y) ? (end.x) : (start.x)) &&
                          e.x < ((end.y > start.y) ? (end.x) : (start.x))) )
                    {   int	bufI=lineArray[i];
                        lineArray[i] = lineArray[j];
                        lineArray[j] = bufI;
                        g1 = [[path list] objectAtIndex:lineArray[i]];
                        [(VLine*)g1 getVertices:&start :&end]; // set g1 new !
                    }
                }
            }
        }
        else break;
    }
}

/* */
- (void)optimizePath:(VPath*)path :(int)w
{   int		i1, i2, changeI, startIndex=0, index2=0, yMin, iDiff, openPath = 0;
    float	startDistance=MAXCOORD, dist=(w*w), d1, d2, d, l1eY;
    float	distHalf/*=(w/2)*(w/2)*/, distQuarter;//=(w/8)*(w/8);
    NSPoint	l1S, l1E, l2S, l2E;
    VLine	*l1, *l2;

    if ( ![[path list] count] )
        return;

    distHalf = 100; distQuarter = 25; dist = 121;

    l1 = [[path list] objectAtIndex:0];
    [l1 getVertices:&l1S :&l1E];
    yMin = l1S.y;
    for (i1 = 0; i1<(int)[[path list] count]-1; i1++)
    {	l1=[[path list] objectAtIndex:i1];

        startDistance = MAXCOORD;
        changeI = i1+1;
        [l1 getVertices:&l1S :&l1E];

        if ( Diff(l1S.x, l1E.x) == 0 && Diff(l1S.y, l1E.y) == 0 )
        {
            [[path list] removeObjectAtIndex:i1];
            if ( startIndex > i1 )
                startIndex--;
            i1 = ( startIndex == i1 ) ? (i1 - 1) : (i1 - 2);
            continue;
        }
        l1eY = l1E.y + distHalf;
        /* get index2 */
		index2 = i1+1;
        if ( !openPath && i1 > 50 && (iDiff=((int)[[path list] count]-1 - (i1+1))) > 100 )
        {   int	j, testI, l1eYMin = l1E.y - 10, prevTI=iDiff, diff;

            testI = iDiff/2.0;
            for (j=0; j<iDiff; j++)
            {
                if ( i1+testI < i1+1 || i1+testI > (int)[[path list] count]-1)
                    printf("PathContour.m: -optimizePath: darf nicht sein 2\n");
                l2=[[path list] objectAtIndex:i1+testI];
                [l2 getVertices:&l2S :&l2E];
                if ( Max(l2S.y, l2E.y) < l1eYMin || l2S.y == yMin || l2E.y == yMin )
                {
                    if ( Diff(Max(l2S.y, l2E.y), l1E.y) < distHalf )
                    {   index2 = i1+testI; break; }
                    else if ( testI > iDiff-100 )
                    {   index2 = i1+testI; break; }
                    else // up
                    {   diff = Diff(prevTI, testI)/2.0;
                        prevTI = testI;
                        testI = testI + diff;
                    }
                }
                else if ( testI <= 50 )
                {   index2 = i1+1; break; }
                else // down
                {   diff = Diff(prevTI, testI)/2.0;
                    prevTI = testI;
                    testI = testI - diff;
                }
            }
            if ( index2 < i1+1 || index2 > (int)[[path list] count]-1 )
			{
				index2 = i1+1;
				printf("PathContour.m: -optimizePath: darf nicht sein\n");
			}
        }

        for (i2=index2; i2<(int)[[path list] count]; i2++)
        {   VLine	*l2=[[path list] objectAtIndex:i2];

            [l2 getVertices:&l2S :&l2E];
            d1 = SqrDistPoints(l1E, l2S); d2 = SqrDistPoints(l1E, l2E);
//            if ( (d1 <= dist && d1 < startDistance) || (d2 <= dist && d2 < startDistance) ||)
            if ( (d1 < startDistance || d2 < startDistance) ||
                ((d1 == startDistance || d2 == startDistance) && ([self pointIsEdge:l2S] || [self pointIsEdge:l2E])) )
            {
                if ( d2 < d1 )
                {   startDistance = d2;
                    [l2 setVertices:l2E :l2S]; /* change direction of l2 */
                }
                else
                    startDistance = d1;
                changeI = i2;
                if ( Diff(startDistance, 0.0) <= 0 )
                    break;
            }
            if ( l2S.y > l1eY && l2E.y > l1eY )
                break;
        }
        if ( startDistance ) /* close hole */
        {   l2 = [[path list] objectAtIndex:changeI];
            [(VLine*)l2 getVertices:&l2S :&l2E];
            if ( (d=SqrDistPoints(l1E, l2S)) && d < distQuarter ) 
            {   if ( [self pointIsEdge:l2S] ) [l1 setVertices:l1S :l2S];
                else [l2 setVertices:l1E :l2E];
				if ( openPath )
					openPath = 0;
            }
            else
            {   VLine	*l3 = [[path list] objectAtIndex:startIndex];
                float	d3 = SqrDistPoints(l1E, [l3 pointWithNum:0]);

				/* close with l2 */
                if ( d && d <= dist && d < d3) // distance to nextG must be smaller than to startG
                {   VGraphic	*lineG = [VLine line];
                    NSColor	*nxBlack=[NSColor colorWithCalibratedRed:0.0 green:0.0 blue:0.0 alpha:1.0];

                    [lineG setColor:nxBlack]; [lineG setWidth:0]; [lineG setSelected:NO];
                    [(VLine*)lineG setVertices:l1E :l2S];
                    [[path list] insertObject:lineG atIndex:i1+1];
                    i1 += 1; changeI += 1;
                }
                else if ( i1-startIndex == 0 )
                {
                    /* one single Graphic */
                    [[path list] removeObjectAtIndex:i1];
                    i1 --;
                    continue;
                }
				/* closeTo startG */
                else if ( d3 < d && d3 < distQuarter) // close to startG
                {   if ( [self pointIsEdge:[l3 pointWithNum:0]] ) [l1 setVertices:l1S :[l3 pointWithNum:0]];
                    else [l3 setVertices:l1E :[l3 pointWithNum:MAXINT]];
                    startIndex = i1+1;
                }
                else if ( d3 < d && d3 < dist) // close to startG
                {   VGraphic	*lineG = [VLine line];
                    NSColor	*nxBlack=[NSColor colorWithCalibratedRed:0.0 green:0.0 blue:0.0 alpha:1.0];

					[lineG setColor:nxBlack]; [lineG setWidth:0]; [lineG setSelected:NO];
					[(VLine*)lineG setVertices:l1E :[l3 pointWithNum:0]];
					[[path list] insertObject:lineG atIndex:i1+1];
					i1 += 1; changeI += 1;
                    startIndex = i1+1;
                }
                else if (d3 < d && d < dist)
                    startIndex = i1+1;
                else if ( i1-startIndex == 1 )
                {
                    /* two graphics which cant be closed */
                    [[path list] removeObjectAtIndex:i1];
                    i1--;
                    [[path list] removeObjectAtIndex:i1];
                    i1 --;
                    continue;
                }
				else if ( openPath && d3 < d ) // close to StartG
				{   VGraphic	*lineG = [VLine line];
                    NSColor	*nxBlack=[NSColor colorWithCalibratedRed:0.0 green:0.0 blue:0.0 alpha:1.0];

                    [lineG setColor:nxBlack]; [lineG setWidth:0]; [lineG setSelected:NO];
                    [(VLine*)lineG setVertices:l1E :[l3 pointWithNum:0]];
                    [[path list] insertObject:lineG atIndex:i1+1];
                    i1 += 1; changeI += 1;
                    startIndex = i1+1;
					openPath = 0;
                }
				else if ( openPath && d < d3 ) // close to l2
				{   VGraphic	*lineG = [VLine line];
                    NSColor	*nxBlack=[NSColor colorWithCalibratedRed:0.0 green:0.0 blue:0.0 alpha:1.0];

                    [lineG setColor:nxBlack]; [lineG setWidth:0]; [lineG setSelected:NO];
                    [(VLine*)lineG setVertices:l1E :l2S];
                    [[path list] insertObject:lineG atIndex:i1+1];
                    i1 += 1; changeI += 1;
					openPath = 0;
                }
				else if ( !openPath && d > dist && d3 > dist )
				{	openPath++;
					i1--;
					continue;
				}
            }
//            if ( !openPath && startDistance > dist )
//                startIndex = i1+1;
        }
		else if ( openPath )
			openPath = 0;
        /* if the nearest element is not the next_in_list */
        if ( changeI != (i1+1) )
        {   VGraphic	*gCh=[[path list] objectAtIndex:changeI];

            [[path list] removeObject:gCh];
            [[path list] insertObject:gCh atIndex:i1+1];
        }
    }
    /* close hole from last to start element */
    {   l1=[[path list] objectAtIndex:(int)[[path list] count]-1];
        l2= [[path list] objectAtIndex:startIndex];

        if ( [[path list] count]-startIndex == 1 )
            [[path list] removeObjectAtIndex:(int)[[path list] count]-1];
        else
        {
            [l1 getVertices:&l1S :&l1E];
            [l2 getVertices:&l2S :&l2E];
            if ( (d=SqrDistPoints(l1E, l2S)) && d < distQuarter )
            {   if ( [self pointIsEdge:l2S] ) [l1 setVertices:l1S :l2S];
                else [l2 setVertices:l1E :l2E];
            }
            else if ( d /*&& d <= dist*/ )
            {   VGraphic	*lineG = [VLine line];
                NSColor	*nxBlack=[NSColor colorWithCalibratedRed:0.0 green:0.0 blue:0.0 alpha:1.0];

                [lineG setColor:nxBlack]; [lineG setWidth:0]; [lineG setSelected:NO];
                [(VLine*)lineG setVertices:l1E :l2S];
                [[path list] addObject:lineG];
            }
        }
    }
    /* unite lines with same gradients */
    [self smoothenLinesInPath:path];
    [self smoothenLinesInPath:path];
    [self uniteLinesWithSameGradient:path :w];

    return;
}

/*
 * modified: 2010-03-03 (setDirectionCCW:)
 *           2008-02-08
 * get contour of path using a bitmap algorithm
 * return the calculated path
 */
- (VPath*)contourPath:(VPath*)oPath width:(float)width
{   VPath               *path, *oPathCopy;
    NSRect              conRect, bounds, rect;
    id                  win, conView;
    float               w=width+[oPath width], w2, bytes, scale = 1, maxBytes = 110250000, wi, h, s;
    int                 x, y, right, height, start, w2Int, bytesPerRowHalf, quality = 2;
    NSColor             *nxWhite, *nxBlack;
    NSPoint             moveP, center;
    NSBitmapImageRep	*bitmapImage;

#if DEBUG_CONTUR_TIME
printf("%s Hour.Min.Sec Start\n", [[[NSCalendarDate date] descriptionWithCalendarFormat:@"%H.%M.%S"] UTF8String]);
#endif

    nxBlack = [NSColor colorWithCalibratedRed:0.0 green:0.0 blue:0.0 alpha:1.0];
    nxWhite = [NSColor colorWithCalibratedRed:1.0 green:1.0 blue:1.0 alpha:1.0];

    path = [VPath path];
    [path setColor:[oPath color]];
    [path setFilled:NO];
    [path setWidth:0];
    [path setSelected:NO];

    if ( !w )
        return path;

    /* copy self make it white */
    oPathCopy = [oPath copy];
    [oPathCopy setFilled:YES];
    [oPathCopy setWidth:0];

    /* calc content rect size / scale factor
     * to get not more than 20 MB memory
     * the bounds of the path: width*height / 8(bit) * 2(color deepnes)
     */
    bounds = [oPathCopy bounds];
    wi = conRect.size.width = bounds.size.width + 4*Abs(w);
    h = conRect.size.height = bounds.size.height + 4*Abs(w); /* need a little space for our contour */

    /* need a minimum scale of */
    scale = s = 1.0;
    conRect.size.width = wi*scale; conRect.size.height = h*scale;	/* last guilty values */
    bytes = (wi*scale) * (h*scale);
    w2 = Abs(w)*scale/2.0;

    while ( bytes < maxBytes && s < 50 /*&& conRect.size.width < 10000 && conRect.size.height < 10000*/ )
    {
        scale = s;
        w2 = Abs(w)*scale/2.0;
        conRect.size.width = wi*scale; conRect.size.height = h*scale;	/* last guilty values */
        if ( (quality == 2 && w2 > 40) || (quality == 1 && w2 > 30) || (!quality && w2 > 20) ) // 20
            break; /* stop scale is great enough */

        s += 1.0;
        bytes = (wi*s) * (h*s); // 1 byte is one pixel;
        if ( wi*s > 8000 || h*s > 8000 )
            break; // too big !!!
    }
    if ( conRect.size.width > 8000 || conRect.size.height > 8000 ) // good bye
    {    [oPathCopy release]; return path; }

    /* need our half width/minWidth in pixel and scaled */
    if ( (w2-((int)w2)) > 0.5 )
    {	w2Int = w2 + 1;
        conRect.size.width += 6.0; conRect.size.height += 6.0;
    }
    else
    {	w2Int = w2;
        conRect.size.width += 4.0; conRect.size.height += 4.0;
    }
    conRect.origin.x = conRect.origin.y = 10.0;

    /* scale oPathCopy */
    center.x = bounds.origin.x + bounds.size.width/2.0;
    center.y = bounds.origin.y + bounds.size.height/2.0;
    [oPathCopy scale:scale :scale withCenter:center];
    bounds = [oPathCopy bounds];

    /* move oPathCopy to ~0 */
    moveP.x = -(bounds.origin.x - 4*w2Int - 2.0);
    moveP.y = -(bounds.origin.y - 4*w2Int - 2.0);
    [oPathCopy moveBy:moveP];

    /* build an offscreen window
     * in which we draw the scaled black copy of original path on white background NSBackingStoreBuffered NSBackingStoreRetained
     */
    win = [[NSWindow alloc] initWithContentRect:conRect styleMask:NSBorderlessWindowMask backing:NSBackingStoreRetained defer:NO];
    [win setDynamicDepthLimit:NO];
    [win setDepthLimit:NSBestDepth(NSCalibratedWhiteColorSpace, 8, 8, YES, NULL)];
//[win setDepthLimit:NSBestDepth(NSCalibratedRGBColorSpace, 8, 24, NO, NULL)]; // test apple

    [win setBackgroundColor:( w < 0 ) ? [NSColor grayColor] : [NSColor blackColor]];
#if DEBUG_CONTUR
[win makeKeyAndOrderFront:self]; /* weglassen wenn nicht gesehen werden soll */
#endif
    conView = [win contentView];
    [conView display];

    /* now draw our white scaled path in view
     */
    [conView lockFocus];

#ifdef __APPLE__
[[NSGraphicsContext currentContext] setShouldAntialias:NO];
#endif

    [oPathCopy setFillColor:( w > 0 ) ? [NSColor grayColor] : nxWhite];
    [oPathCopy drawWithPrincipal:nil];

    // w < 0 -> contour inside path
    // w > 0 -> contour outside path
    // w == 0 -> white filled black Background
    if (w)
    {
        [oPathCopy setColor:(w < 0) ? nxBlack : nxWhite];
        [oPathCopy setFilled:NO];
        [oPathCopy setWidth:w2Int*2.0];
        [oPathCopy drawWithPrincipal:nil];
    }
    /* force 8 bit gray -> we must draw one thing gray */
    {   VRectangle	*r=[VRectangle rectangle];

        [r setVertices:NSMakePoint(1.0,1.0) :NSMakePoint(1.0,1.0)];
        [r setFillColor:[NSColor grayColor]];
        [r setFilled:YES];
        [r drawWithPrincipal:nil];
    }
    /* get pixel information into data (char string) */
    rect.origin = NSZeroPoint;
    right = rect.size.width = (int)(conRect.size.width); /* our with scale and bounds calculated width */
    height = rect.size.height = (int)(conRect.size.height);

    bitmapImage = [[NSBitmapImageRep allocWithZone:[self zone]] initWithFocusedViewRect:rect];

    // apple
    if ([bitmapImage bitsPerPixel] > 8 || ![bitmapImage isPlanar] || [bitmapImage samplesPerPixel] > 1 ||
        ([bitmapImage bytesPerRow]/[bitmapImage samplesPerPixel]) > rect.size.width)
    {	NSBitmapImageRep	*abitmap;

        if ([bitmapImage bitsPerSample] == 8) // meshed
        {   int			xl,ny, width;
            int			bpr = [bitmapImage bytesPerRow], spp = 1, abpr;
            int			bpp = [bitmapImage bytesPerPlane];
            unsigned char	*planes[5];

            abitmap = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
                                                              pixelsWide:rect.size.width
                                                              pixelsHigh:rect.size.height
                                                           bitsPerSample:8
                                                         samplesPerPixel:1
                                                                hasAlpha:NO isPlanar:YES
                                                          colorSpaceName:NSCalibratedWhiteColorSpace
                                                             bytesPerRow:rect.size.width
                                                            bitsPerPixel:8];

            data = [abitmap bitmapData];
            abpr = [abitmap bytesPerRow];
            [bitmapImage getBitmapDataPlanes:planes];

            if (![bitmapImage isPlanar])
                spp = [bitmapImage bitsPerPixel]/8;
            width = bpr / spp; // bytesPerRow / samplesPerPixel
            if (width > rect.size.width) // retina display factor two
            {
                for (y=0, ny=0; y<bpp; y+=2*bpr, ny+=abpr) // step two rows on right side
                {
                    for (x=0, xl=0; x<width; x+=2, xl++) // x the same
                    {
                        //*((LONG*)(data+ny+xl)) = *((LONG*)(planes[0]+y+x*spp));
                        *(data+ny+xl) = *(planes[0]+y+x*spp);
                    }
                }
            }
            else
            {
                for (y=0, ny=0; y<bpp; y+=bpr, ny+=abpr)
                {
                    for (x=0; x<width; x++)
                    {
                        //*((LONG*)(data+ny+x)) = *((LONG*)(planes[0]+y+x*spp));
                        *(data+ny+x) = *(planes[0]+y+x*spp);
                    }
                }
            }
        }
        else
        {   [conView unlockFocus];
            [win close];
            [bitmapImage release];
            [oPathCopy release];
            return path;
        }
        [bitmapImage release];
        bitmapImage = abitmap;
    }
    size = [bitmapImage bytesPerPlane];
    data = [bitmapImage bitmapData];
    bytesPerRow = [bitmapImage bytesPerRow];
    bytesPerRowHalf = bytesPerRow/2.0;
    {   int	lineArray[bytesPerRowHalf], lineCnt = 0;
        NSPoint	*pts;
        pts = malloc(right * sizeof(NSPoint));

    /* set loop parameters */
    right -= (2*w2Int+1);
    height -= (2*w2Int+1);

#if DEBUG_CONTUR
[nxGray set];
#endif

    /* vectorize contour */
    start = 2*w2Int+1;
    for (y=start; y<height; y++)
    {   int		pCnt=0, byteY, byteX;

        byteY = y * bytesPerRow;	/* the height */
        byteY = size - byteY - bytesPerRow;
        for (x=start; x<right && byteY+x+19 < size; x++)
        {
            byteX = byteY+x;
            if ( *(data+byteX) != white )
                continue;
            /* l d r u is a black pixel -> one of our pixels */
            if ( *(data+byteX-1) == black || *(data+byteX+bytesPerRow) == black ||
                 *(data+byteX+1) == black || *(data+byteX-bytesPerRow) == black )
            {   NSPoint	nxp = {x, y};
                pts[pCnt] = nxp;
                pCnt++;
            }
        }
        if ( pCnt )
            [self buildPath:path :pts :pCnt :w :lineArray :&lineCnt];
    }
    free(pts);
    } // lineArray, lineCnt
#if DEBUG_CONTUR_TIME
printf("%s Hour.Min.Sec vor Optimieren\n", [[[NSCalendarDate date] descriptionWithCalendarFormat:@"%H.%M.%S"] UTF8String]);
#endif

    /* correct path */
    /*if ( [[path list] count] )
    {   for (x=(int)[[path list] count]-1; x>=0; x--)
        {   VGraphic	*lineG = [[path list] objectAtIndex:x]; // nach opt - nur singles !
            NSPoint	start, end;
            [(VLine*)lineG getVertices:&start :&end];
            if ( //(![lineG isSelected] && Diff(start.x, end.x) <= 2 && Diff(start.y, end.y) <= 2) ||
                (Diff(start.x, end.x) <= 1 && Diff(start.y, end.y) <= 1) )
                [[path list] removeObjectAtIndex:x];
        }
    }*/
    [self optimizePath:path :w2Int];

    /* move and scale path to old great */
    moveP.x = -moveP.x; moveP.y = -moveP.y;
    [path moveBy:moveP];
    scale = 1/scale;
    [path scale:scale :scale withCenter:center];


#if 0
{ int i;
  NSPoint s, e;

  printf("VPath\n");
    for (i=0; i<[[path list] count]; i++)
    {	Line	*l1=[[path list] objectAtIndex:i];

        [l1 getVertices:&s :&e];
        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);
    }
  printf("\n3DLinePath\n");
    for (i=0; i<[[linePath list] count]; i++)
    {	VLine3D	*l1=[[linePath list] objectAtIndex:i];

        [l1 getVertices:&s :&e];
        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);
    }
}
#endif
    [conView unlockFocus];
    [win close];
    [bitmapImage release];
    [oPathCopy release];
#if DEBUG_CONTUR_TIME
printf("%s Hour.Min.Sec End\n\n", [[[NSCalendarDate date] descriptionWithCalendarFormat:@"%H.%M.%S"] UTF8String]);
#endif
    [path setDirectionCCW:[oPath isDirectionCCW]];
    return path;
}

-(NSBitmapImageRep*)scaleImageRep:(NSBitmapImageRep*)srcRep toSize:(NSSize)size
{   NSGraphicsContext   *context;
    NSBitmapImageRep    *newRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
                                                                          pixelsWide:size.width
                                                                          pixelsHigh:size.height
                                                                       bitsPerSample:[srcRep bitsPerSample]
                                                                     samplesPerPixel:[srcRep samplesPerPixel]
                                                                            hasAlpha:[srcRep hasAlpha]  // must have alpha!
                                                                            isPlanar:[srcRep isPlanar]
                                                                      colorSpaceName:[srcRep colorSpaceName]
                                                                         bytesPerRow:0 /*size.width*/
                                                                        bitsPerPixel:0 /*[srcRep bitsPerPixel]*/ ];

    [NSGraphicsContext saveGraphicsState];

    context = [NSGraphicsContext graphicsContextWithBitmapImageRep:newRep];
    [NSGraphicsContext setCurrentContext:context];

    // do not use drawAtPoint: !! it does not respect resolution due to a bug
    [srcRep drawInRect:NSMakeRect( 0, 0, [newRep pixelsWide], [newRep pixelsHigh])];
    /*[srcRep drawInRect:NSMakeRect( 0, 0, [newRep pixelsWide], [newRep pixelsHigh])
              fromRect:NSMakeRect( 0, 0, [srcRep pixelsWide], [srcRep pixelsHigh])  // scales double
             operation:NSCompositeCopy fraction:1.0 respectFlipped:YES hints:nil];*/

    [NSGraphicsContext restoreGraphicsState];
    //[newRep setSize:[srcRep size]]; // this sets the resolution of the source
    //[newRep autorelease];           // if needed
    return newRep;
}

- (VPath*)contourImage:(VImage*)image width:(float)width
{   VPath               *path;
    NSRect              conRect, bounds, rect;
    NSSize              imageSize;
    id                  win, conView;
    float               w=width, w2, scaleX = 1, scaleY = 1;
    int                 x, y, right, height, start, w2Int, bytesPerRowHalf;
    NSColor             *nxBlack;
    NSPoint             moveP, center;
    NSBitmapImageRep    *bitmapImage;
    unsigned char       color, *data2;

#if DEBUG_CONTUR_TIME
    printf("%s Hour.Min.Sec Start\n", [[[NSCalendarDate date] descriptionWithCalendarFormat:@"%H.%M.%S"] UTF8String]);
#endif

    nxBlack = [NSColor colorWithCalibratedRed:0.0 green:0.0 blue:0.0 alpha:1.0];

    path = [VPath path];
    [path setColor:nxBlack];
    [path setFilled:NO];
    [path setWidth:0];
    [path setSelected:NO];

//    if ( !w )
//        return path;

    /* get bouns of image size and original size */
    bounds.size = [image originalSize];
    bounds.origin = [image origin];

    imageSize = [image size];
    scaleX = bounds.size.width /imageSize.width;
    scaleY = bounds.size.height/imageSize.height;

    /* need our half width/minWidth in pixel and scaled */
    ( scaleX < scaleY ) ? (w2 = Abs(w)*scaleX/2.0) : (w2 = Abs(w)*scaleY/2.0);

    ( (w2-((int)w2)) > 0.5 ) ? (w2Int = w2 + 1) : (w2Int = w2);
//    if ( !w2Int ) w2Int = 1;

    if ( w2Int > 46 ) // must scale origninalSize -> to keep the ratio
    {
        while ( w2Int > 46 )
        {
            scaleX -= 1.0; scaleY -= 1.0;
            ( scaleX < scaleY ) ? (w2 = Abs(w)*scaleX/2.0) : (w2 = Abs(w)*scaleY/2.0);
            ( (w2-((int)w2)) > 0.5 ) ? (w2Int = w2 + 1) : (w2Int = w2);
        }
        bounds.size.width  = imageSize.width*scaleX;
        bounds.size.height = imageSize.height*scaleY;
    }
    conRect.size.width  = bounds.size.width  + 2*w2Int + 20;
    conRect.size.height = bounds.size.height + 2*w2Int + 20;    // need a little space for our contour
    conRect.origin.x = conRect.origin.y = w2Int+10.0;

    if ( conRect.size.width > 8000 || conRect.size.height > 8000 ) // good bye
         return path;

    /* build an offscreen window
     * in which we draw the scaled black copy of original path on white background NSBackingStoreBuffered NSBackingStoreRetained
     */
    win = [[NSWindow alloc] initWithContentRect:conRect styleMask:NSBorderlessWindowMask backing:NSBackingStoreRetained defer:NO];
    [win setDynamicDepthLimit:NO];
    [win setDepthLimit:NSBestDepth(NSCalibratedWhiteColorSpace, 8, 8, YES, NULL)];  // same on 10.8 and 10.10

    [win setBackgroundColor:[NSColor whiteColor]];
#if DEBUG_CONTUR
    [win makeKeyAndOrderFront:self]; /* weglassen wenn nicht gesehen werden soll */
#endif
    conView = [win contentView];
    [conView display];

    /* get copy of image */
    [[image image] setSize:bounds.size];

    /* now draw our black scaled path in view
     */
    [conView lockFocus];
#ifdef __APPLE__
    [[NSGraphicsContext currentContext] setShouldAntialias:NO];
#endif
    [[image image] drawAtPoint:conRect.origin fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0];
    //[[image image] compositeToPoint:conRect.origin operation:NSCompositeSourceOver]; // NSCompositeCopy

    /* get pixel information into data (char string) */
    rect.origin = NSZeroPoint;
    right  = rect.size.width  = (int)(conRect.size.width);  // our calculated width including scale and bounds
    height = rect.size.height = (int)(conRect.size.height);

    [[NSColor grayColor] set]; NSRectFill(NSMakeRect(2, 2, 1, 1)); // hack to force 8 bit gray bitmap
    bitmapImage = [[NSBitmapImageRep allocWithZone:[self zone]] initWithFocusedViewRect:rect];
    [conView unlockFocus];  // 2014-12-17 moved to here, right after drawing
    [win close];            // 2014-12-17

    // apple
    if ([bitmapImage bitsPerPixel] > 8 || ![bitmapImage isPlanar] || [bitmapImage samplesPerPixel] > 1 ||
        ([bitmapImage bytesPerRow]/[bitmapImage samplesPerPixel]) > rect.size.width)
    {	NSBitmapImageRep	*abitmap;

        if ([bitmapImage bitsPerSample] == 8) // meshed
        {   int             xl, ny, width;
            int             bpr = [bitmapImage bytesPerRow], spp = 1, abpr;
            int             bpp = [bitmapImage bytesPerPlane];
            unsigned char   *planes[5];

            abitmap = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
                                                              pixelsWide:rect.size.width
                                                              pixelsHigh:rect.size.height
                                                           bitsPerSample:8
                                                         samplesPerPixel:1
                                                                hasAlpha:NO isPlanar:YES
                                                          colorSpaceName:NSCalibratedWhiteColorSpace
                                                             bytesPerRow:rect.size.width
                                                            bitsPerPixel:8];

            data = [abitmap bitmapData];
            abpr = [abitmap bytesPerRow];
            [bitmapImage getBitmapDataPlanes:planes];

            if (![bitmapImage isPlanar])
                spp = [bitmapImage bitsPerPixel]/8;
            width = bpr / spp; // bytesPerRow / samplesPerPixel
            if (width > rect.size.width) // retina display factor two
            {
                for (y=0, ny=0; y<bpp; y+=2*bpr, ny+=abpr) // step two rows on right side
                {
                    for (x=0, xl=0; x<width; x+=2, xl++) // x the same
                    {
                        //*((LONG*)(data+ny+xl)) = *((LONG*)(planes[0]+y+x*spp));
                        *(data+ny+xl) = *(planes[0]+y+x*spp);
                    }
                }
            }
            else
            {
                for (y=0, ny=0; y<bpp; y+=bpr, ny+=abpr)
                {
                    for (x=0; x<width; x++)
                    {
                        //*((LONG*)(data+ny+x)) = *((LONG*)(planes[0]+y+x*spp));
                        *(data+ny+x) = *(planes[0]+y+x*spp);
                    }
                }
            }
        }
        else
        {   //[conView unlockFocus];
            //[win close];
            [bitmapImage release];
            return path;
        }
        [bitmapImage release];
        bitmapImage = abitmap;
    }
    size = [bitmapImage bytesPerPlane];
    data = [bitmapImage bitmapData];
    bytesPerRow = [bitmapImage bytesPerRow];

    /* set loop parameters */
    right -= 10.0;
    height -= 10.0;

    // set not white bytes to black !!!!!!!!!!
    // we do this in invertData

    // w < 0 -> contour inside path
    // w > 0 -> contour outside path
    //    ( w < 0 ) ? (color = black) : (color = white);
    ( w < 0 ) ? (color = white) : (color = black);

    data2 = malloc(size * sizeof(unsigned char));
    data2 = memcpy(data2, data, size); // copy !! allways the same !!!

#if 0 // debug drawArcInData
    start = 10.0; // (gdb) x/100tb data
    for (y=start; y<height && w2Int; y++)
    {   int	byteY, byteX;

        byteY = size - (y * bytesPerRow) - bytesPerRow; /* the height */

        for (x=start; x<right && byteY+x+10 < size; x++)
        {
            byteX = byteY+x;
            *(data+byteX) = ( w < 0 ) ? black : white;
        }
    }
#endif

    start = 10.0; // (gdb) x/100tb data
    for (y=start; y<height && w2Int; y++)
    {   int	byteY, byteX;

        byteY = size - (y * bytesPerRow) - bytesPerRow; /* the height */

        for (x=start; x<right && byteY+x+19 < size; x++)
        {
            byteX = byteY+x;
            if ( *(data2+byteX) == white )
                continue;
            /* we are black AND l d r OR u is a white pixel -> one of our pixels */
            if ( *(data2+byteX-1) == white || *(data2+byteX+bytesPerRow) == white ||
                *(data2+byteX+1) == white || *(data2+byteX-bytesPerRow) == white )
            {
                [self drawArcInDataAt:(byteY+x) radius:w2Int color:color];
            }
        }
    }
    free(data2);

#if DEBUG_CONTUR_2
[[bitmapImage TIFFRepresentation] writeToFile:@"/tmp/contourImage.tiff" atomically:YES]; // debug only


#if 0 // debug drawArcInData

    [conView unlockFocus];
    [win close];
    [[image image] setSize:imageSize]; // set to old great
    [bitmapImage release];

return path;
#endif // debug drawArcInData

#endif

    [self invertData];

    bytesPerRowHalf = bytesPerRow/2.0;
    {   int	lineArray[bytesPerRowHalf], lineCnt = 0;
        NSPoint	*pts;
        pts = malloc(right * sizeof(NSPoint));

        /* vectorize contour */
        start = 10.0;
        for (y=start; y<height; y++)
        {   int		pCnt=0, byteY, byteX;

            byteY = y * bytesPerRow;	/* the height */
            byteY = size - byteY - bytesPerRow;
            for (x=start; x<right; x++)
            {
                byteX = byteY+x;
                if ( *(data+byteX) != white )
                    continue;
                /* l d r u is a black pixel -> one of our pixels */
                if ( *(data+byteX-1) == black || *(data+byteX+bytesPerRow) == black ||
                    *(data+byteX+1) == black || *(data+byteX-bytesPerRow) == black )
                {   NSPoint	nxp = {x, y};
                    pts[pCnt] = nxp;
                    pCnt++;
                }
            }
            if ( pCnt )
                [self buildPath:path :pts :pCnt :w :lineArray :&lineCnt];
        }
        free(pts);
    } // lineArray, lineCnt
    
#if DEBUG_CONTUR_TIME
printf("%s Hour.Min.Sec vor Optimieren\n", [[[NSCalendarDate date] descriptionWithCalendarFormat:@"%H.%M.%S"] UTF8String]);
#endif

    [self optimizePath:path :w2Int];

    /* move and scale path to old greatness */
    /* move and scale path and linePath and *fillPath to old great */
    //moveP.x = -(bounds.origin.x - w2Int - 9.0); // dont know why 9.0 insteat 10.0 is correct - but it is
    moveP.x = -(bounds.origin.x - w2Int - 10.0); // dont know why 9.0 insteat 10.0 is correct - but it is
    //moveP.y = -(bounds.origin.y - w2Int - 9.0); // w2Int+10.0 -> think: lower left coner of image is IN/AT composite pt
    moveP.y = -(bounds.origin.y - w2Int - 10.0); // w2Int+10.0 -> think: lower left coner of image is IN/AT composite pt
    moveP.x = -moveP.x; moveP.y = -moveP.y;

    center = bounds.origin;
    scaleX = 1.0/scaleX;
    scaleY = 1.0/scaleY;
    [path moveBy:moveP];
    [path scale:scaleX :scaleY withCenter:center];

    //[conView unlockFocus];
    //[win close];
    [[image image] setSize:imageSize]; // set to old great
    [bitmapImage release];
#if DEBUG_CONTUR_TIME
printf("%s Hour.Min.Sec End\n\n", [[[NSCalendarDate date] descriptionWithCalendarFormat:@"%H.%M.%S"] UTF8String]);
#endif
    return path;
}

/* modified: 23.02.05
 * get contour of list using a bitmap algorithm
 * return the calculated path
 */
- (VPath*)contourList:(NSArray*)oList width:(float)width
{   VPath               *path;
    NSRect              conRect, bounds=NSZeroRect, rect;
    id                  win, conView;
    float               w=width, w2, bytes, scale = 1, maxBytes = 110250000, wi, h, s, maxW=0;
    int                 i, x, y, right, height, start, w2Int, bytesPerRowHalf, quality = 2;
    int                 cnt = [oList count], drawed = 0;
    NSColor             *nxWhite, *nxBlack;
    NSPoint             moveP, center;
    NSBitmapImageRep    *bitmapImage;

#if DEBUG_CONTUR_TIME
printf("%s Hour.Min.Sec Start\n", [[[NSCalendarDate date] descriptionWithCalendarFormat:@"%H.%M.%S"] UTF8String]);
#endif

    if (!cnt)
        return nil;

    nxBlack = [NSColor colorWithCalibratedRed:0.0 green:0.0 blue:0.0 alpha:1.0];
    nxWhite = [NSColor colorWithCalibratedRed:1.0 green:1.0 blue:1.0 alpha:1.0];

    path = [VPath path];
    [path setColor:[[oList objectAtIndex:0] color]];
    [path setFilled:NO];
    [path setWidth:0];
    [path setSelected:NO];

    /* get Bounds and maxW */
    for (i=0; i < cnt; i++)
    {	VGraphic    *g = [oList objectAtIndex:i];

        if ([g isKindOfClass:[VGroup class]])
        {   int	j, gCnt = [(VGroup*)g countRecursive];

            for (j=0; j<gCnt; j++)
            {   VGraphic    *gg = [(VGroup*)g recursiveObjectAtIndex:j];

                if ( [gg width] > maxW )
                    maxW = [gg width];
                rect = [gg bounds];
                bounds = (!bounds.size.width) ? rect : NSUnionRect(rect, bounds);
            }
        }
        else
        {   if ( [g width] > maxW )
                maxW = [g width];
            rect = [g bounds];
            bounds = (!bounds.size.width) ? rect : NSUnionRect(rect, bounds);
        }
    }
    /* calc content rect size / scale factor
     * to get not more than 20 MB memory
     * the bounds of the path: width*height / 8(bit) * 2(color deepnes)
     */

// (Abs(w)+maxW) ++ maxWidth of objects from list !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!1
    wi = conRect.size.width = bounds.size.width + 4*Abs(w+maxW);
    h = conRect.size.height = bounds.size.height + 4*Abs(w+maxW); /* need a little space for our contour */

    /* need a minimum scale of */
    scale = s = 1.0;
    conRect.size.width = wi*scale; conRect.size.height = h*scale;	/* last guilty values */
    bytes = (wi*scale) * (h*scale);
    w2 = Abs(w)*scale/2.0;

    while ( bytes < maxBytes && s < 50 /*&& conRect.size.width < 10000 && conRect.size.height < 10000*/ ) // 8000
    {
        scale = s;
        w2 = Abs(w)*scale/2.0;
        conRect.size.width = wi*scale; conRect.size.height = h*scale;	/* last guilty values */
        if ( (quality == 2 && w2 > 40) || (quality == 1 && w2 > 30) || (!quality && w2 > 20) ) // 20
            break; /* stop scale is great enough */

        s += 1.0;
        bytes = (wi*s) * (h*s); // 1 byte is one pixel;
        if ( wi*s > 8000 || h*s > 8000 ) // > 10000
            break; // too big !!!
    }
    if ( conRect.size.width > 8000 || conRect.size.height > 8000 ) // good bye > 10000
        return nil;

    w2 = Abs(w+maxW)*scale/2.0;
    /* need our half width/minWidth in pixel and scaled */
    if ( (w2-((int)w2)) > 0.5 )
    {	w2Int = w2 + 1;
        conRect.size.width += 6.0; conRect.size.height += 6.0;
    }
    else
    {	w2Int = w2;
        conRect.size.width += 4.0; conRect.size.height += 4.0;
    }
    conRect.origin.x = conRect.origin.y = 10.0;

    /* center */
    center.x = bounds.origin.x + bounds.size.width/2.0;
    center.y = bounds.origin.y + bounds.size.height/2.0;

    bounds = NSZeroRect;
    for (i=0; i < cnt; i++)
    {	id	g = [oList objectAtIndex:i];

        [g scale:scale :scale withCenter:center];
        rect = [g bounds];
        bounds = (!bounds.size.width) ? rect : NSUnionRect(rect, bounds);
    }

    /* move oList to ~0 */
    moveP.x = -(bounds.origin.x - 4*w2Int - 2.0);
    moveP.y = -(bounds.origin.y - 4*w2Int - 2.0);

    for (i=0; i < cnt; i++)
        [[oList objectAtIndex:i] moveBy:moveP];

    /* build an offscreen window
     * in which we draw the scaled black copy of original path on white background NSBackingStoreBuffered NSBackingStoreRetained
     */
    win = [[NSWindow alloc] initWithContentRect:conRect styleMask:NSBorderlessWindowMask backing:NSBackingStoreRetained defer:NO];
    [win setDynamicDepthLimit:NO];
    [win setDepthLimit:NSBestDepth(NSCalibratedWhiteColorSpace, 8, 8, YES, NULL)];
//[win setDepthLimit:NSBestDepth(NSCalibratedRGBColorSpace, 8, 24, NO, NULL)]; // test apple

//    [win setBackgroundColor:( w < 0 ) ? [NSColor grayColor] : [NSColor blackColor]];
    [win setBackgroundColor:[NSColor blackColor]];

#if DEBUG_CONTUR
[win makeKeyAndOrderFront:self]; /* weglassen wenn nicht gesehen werden soll */
#endif
    conView = [win contentView];
    [conView display];

    /* now draw our scaled path in view
     */
    [conView lockFocus];

#ifdef __APPLE__
[[NSGraphicsContext currentContext] setShouldAntialias:NO];
#endif

    for (i=0; i < cnt; i++)
    {   VGraphic    *g = [oList objectAtIndex:i];
        float       gWidth = ([g width]/scale), endW = w + gWidth, oldGWidth = [g width];
        int         gFilled = [g filled];

        if ([g isKindOfClass:[VGroup class]])
        {   int	j, gCnt = [(VGroup*)g countRecursive];

            for (j=0; j<gCnt; j++)
            {   VGraphic    *gg = [(VGroup*)g recursiveObjectAtIndex:j];
                NSColor     *fillColor = nil, *color = [[gg color] retain];

                gWidth = ([gg width]/scale);
                endW = w + gWidth;
                gFilled = oldGWidth = [gg filled];

                if ( [gg respondsToSelector:@selector(setFillColor:)] )
                    fillColor = [[(VPath*)gg fillColor] retain];

                /* need our half width/minWidth in pixel and scaled */
                w2 = Abs(w+gWidth)*scale/2.0;
                if ([gg isKindOfClass:[VLine class]] &&
                    Diff([gg pointWithNum:0].y, [gg pointWithNum:1].y) <= TOLERANCE)
                    w2Int = ( (w2-((int)w2)) < 0.2 ) ? (w2-1) : (w2);
                else
                    w2Int = ( (w2-((int)w2)) > 0.5 ) ? (w2 + 1) : (w2);

                if ( gFilled )
                {
                    [gg setWidth:0];
                    [(VPath*)gg setFillColor:( endW > 0 ) ? [NSColor grayColor] : nxWhite];
                    [(VPath*)gg drawWithPrincipal:nil];
                    drawed++;

                    if (w2Int)
                    {
                        [gg setColor:(endW > 0) ? nxWhite : nxBlack];
                        if ( [gg isKindOfClass:[VPath class]] )
                            [(VPath*)gg setFilled:NO optimize:NO];
                        else
                            [gg setFilled:NO];
                        [gg setWidth:w2Int*2.0];
                        [gg drawWithPrincipal:nil];
                    }
                }
                else // stroked object
                {   BOOL fillObj = ([gg respondsToSelector:@selector(setFillColor:)]) ? YES : NO;

                    if ( fillObj )
                    {   [gg setWidth:0];
                        [(VPath*)gg setFillColor:( endW > 0 || endW < 0 ) ? nxBlack : nxWhite];
                        [(VPath*)gg drawWithPrincipal:nil];
                        drawed++;
                    }
                    if (w2Int)
                    {   [gg setColor:(endW > 0 || endW < 0) ? nxWhite : nxBlack];
                        if ( [gg isKindOfClass:[VPath class]] )
                            [(VPath*)gg setFilled:NO optimize:NO];
                        else
                            [gg setFilled:NO];
                        [gg setWidth:w2Int*2.0];
                        [gg drawWithPrincipal:nil];
                        drawed++;
                    }
                }
                /* set all values back to old */
                [gg setWidth:oldGWidth];
                [gg setColor:color];
                if ( [gg respondsToSelector:@selector(setFillColor:)] )
                {
                    [(VPath*)gg setFillColor:fillColor];
                    if ( [gg isKindOfClass:[VPath class]] )
                        [(VPath*)gg setFilled:gFilled optimize:NO];
                    else
                        [gg setFilled:gFilled];
                }
            }
        }
        else
        {   NSColor	*fillColor = nil, *color = [[g color] retain];

            if ( [g respondsToSelector:@selector(setFillColor:)] )
                fillColor = [[(VPath*)g fillColor] retain];

            /* need our half width/minWidth in pixel and scaled */
            w2 = Abs(w+gWidth)*scale/2.0;
            if ([g isKindOfClass:[VLine class]] &&
                Diff([g pointWithNum:0].y, [g pointWithNum:1].y) <= TOLERANCE)
                w2Int = ( (w2-((int)w2)) < 0.2 ) ? (w2-1) : (w2);
            else
                w2Int = ( (w2-((int)w2)) > 0.5 ) ? (w2 + 1) : (w2);

            if ( gFilled )
            {
                [g setWidth:0];
                [(VPath*)g setFillColor:( endW > 0 ) ? [NSColor grayColor] : nxWhite];
                [(VPath*)g drawWithPrincipal:nil];
                drawed++;

                if (w2Int) // w2Int
                {
                    [g setColor:(endW > 0) ? nxWhite : nxBlack];
                    if ( [g isKindOfClass:[VPath class]] )
                        [(VPath*)g setFilled:NO optimize:NO];
                    else
                        [g setFilled:NO];
                    [g setWidth:w2Int*2.0]; // w2Int*2.0
                    [g drawWithPrincipal:nil];
                }
            }
            else // stroked object
            {   BOOL fillObj = ([g respondsToSelector:@selector(setFillColor:)]) ? YES : NO;

                if ( fillObj )
                {   [g setWidth:0];
                    [(VPath*)g setFillColor:( endW > 0 || endW < 0 ) ? nxBlack : nxWhite];
                    [(VPath*)g drawWithPrincipal:nil];
                    drawed++;
                }
                if (w2Int)
                {   [g setColor:(endW > 0 || endW < 0) ? nxWhite : nxBlack];
                    if ( [g isKindOfClass:[VPath class]] )
                        [(VPath*)g setFilled:NO optimize:NO];
                    else
                        [g setFilled:NO];
                    [g setWidth:w2Int*2.0];
                    [g drawWithPrincipal:nil];
                    drawed++;
                }
            }
            /* set all values back to old */
            [g setWidth:oldGWidth];
            [g setColor:color];
            if ( [g respondsToSelector:@selector(setFillColor:)] )
            {
                [(VPath*)g setFillColor:fillColor];
                if ( [g isKindOfClass:[VPath class]] )
                    [(VPath*)g setFilled:gFilled optimize:NO];
                else
                    [g setFilled:gFilled];
            }
        }
    }
    if ( !drawed )
    {   [conView unlockFocus];
        [win close];
        return nil;
    }
    /* force 8 bit gray -> we must draw one thing gray */
    {   VRectangle	*r=[VRectangle rectangle];

        [r setVertices:NSMakePoint(1.0,1.0) :NSMakePoint(1.0,1.0)];
        [r setFillColor:[NSColor grayColor]];
        [r setFilled:YES];
        [r drawWithPrincipal:nil];
    }

    /* get pixel information into data (char string) */
    rect.origin = NSZeroPoint;
    right = rect.size.width = (int)(conRect.size.width); /* our with scale and bounds calculated width */
    height = rect.size.height = (int)(conRect.size.height);

    bitmapImage = [[NSBitmapImageRep allocWithZone:[self zone]] initWithFocusedViewRect:rect];

    // apple
    if ([bitmapImage bitsPerPixel] > 8 || ![bitmapImage isPlanar] || [bitmapImage samplesPerPixel] > 1 ||
        ([bitmapImage bytesPerRow]/[bitmapImage samplesPerPixel]) > rect.size.width)
    {	NSBitmapImageRep	*abitmap;

        if ([bitmapImage bitsPerSample] == 8) // meshed
        {   int			xl, ny, width;
            int			bpr = [bitmapImage bytesPerRow], spp = 1, abpr;
            int			bpp = [bitmapImage bytesPerPlane];
            unsigned char	*planes[5];

            abitmap = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
                                                              pixelsWide:rect.size.width
                                                              pixelsHigh:rect.size.height
                                                           bitsPerSample:8
                                                         samplesPerPixel:1
                                                                hasAlpha:NO isPlanar:YES
                                                          colorSpaceName:NSCalibratedWhiteColorSpace
                                                             bytesPerRow:rect.size.width
                                                            bitsPerPixel:8];

            data = [abitmap bitmapData];
            abpr = [abitmap bytesPerRow];
            [bitmapImage getBitmapDataPlanes:planes];

            if (![bitmapImage isPlanar])
                spp = [bitmapImage bitsPerPixel]/8;
            width = bpr / spp; // bytesPerRow / samplesPerPixel
            if (width > rect.size.width) // retina display factor two
            {
                for (y=0, ny=0; y<bpp; y+=2*bpr, ny+=abpr) // step two rows on right side
                {
                    for (x=0, xl=0; x<width; x+=2, xl++) // x the same
                    {
                        //*((LONG*)(data+ny+xl)) = *((LONG*)(planes[0]+y+x*spp));
                        *(data+ny+xl) = *(planes[0]+y+x*spp);
                    }
                }
            }
            else
            {
                for (y=0, ny=0; y<bpp; y+=bpr, ny+=abpr)
                {
                    for (x=0; x<width; x++)
                    {
                        //*((LONG*)(data+ny+x)) = *((LONG*)(planes[0]+y+x*spp));
                        *(data+ny+x) = *(planes[0]+y+x*spp);
                    }
                }
            }
        }
        else
        {   [conView unlockFocus];
            [win close];
            [bitmapImage release];
            return nil;
        }
        [bitmapImage release];
        bitmapImage = abitmap;
    }
    size = [bitmapImage bytesPerPlane];
    data = [bitmapImage bitmapData];
    bytesPerRow = [bitmapImage bytesPerRow];
    bytesPerRowHalf = bytesPerRow/2.0;
    {   int	lineArray[bytesPerRowHalf], lineCnt = 0;
        NSPoint	*pts;
        pts = malloc(right * sizeof(NSPoint));

    /* set loop parameters */
    right -= (2*w2Int+1);
    height -= (2*w2Int+1);

#if DEBUG_CONTUR
[nxGray set];
#endif

    /* vectorize contour */
    start = 2*w2Int+1;
    for (y=start; y<height; y++)
    {   int		pCnt=0, byteY, byteX;

        byteY = y * bytesPerRow;	/* the height */
        byteY = size - byteY - bytesPerRow;
        for (x=start; x<right && byteY+x+19 < size; x++)
        {
            byteX = byteY+x;
            if ( *(data+byteX) != white )
                continue;
            /* l d r u is a black pixel -> one of our pixels */
            if ( *(data+byteX-1) == black || *(data+byteX+bytesPerRow) == black ||
                 *(data+byteX+1) == black || *(data+byteX-bytesPerRow) == black )
            {   NSPoint	nxp = {x, y};
                pts[pCnt] = nxp;
                pCnt++;
#if DEBUG_CONTUR
//NSRectFill(NSMakeRect(x, y, 1, 1));
#endif
            }
        }
        if ( pCnt )
            [self buildPath:path :pts :pCnt :w :lineArray :&lineCnt];
    }
    free(pts);
    } // lineArray, lineCnt
#if DEBUG_CONTUR_TIME
printf("%s Hour.Min.Sec vor Optimieren\n", [[[NSCalendarDate date] descriptionWithCalendarFormat:@"%H.%M.%S"] UTF8String]);
#endif

    /* correct path */
    /*if ( [[path list] count] )
    {   for (x=(int)[[path list] count]-1; x>=0; x--)
        {   VGraphic	*lineG = [[path list] objectAtIndex:x]; // nach opt - nur singles !
            NSPoint	start, end;
            [(VLine*)lineG getVertices:&start :&end];
            if ( //(![lineG isSelected] && Diff(start.x, end.x) <= 2 && Diff(start.y, end.y) <= 2) ||
                (Diff(start.x, end.x) <= 1 && Diff(start.y, end.y) <= 1) )
                [[path list] removeObjectAtIndex:x];
        }
    }*/
    [self optimizePath:path :w2Int];

    /* move and scale path AND oList to old great */
    moveP.x = -moveP.x; moveP.y = -moveP.y;
    [path moveBy:moveP];
    scale = 1/scale;
    [path scale:scale :scale withCenter:center];

    for (i=0; i < cnt; i++)
        [[oList objectAtIndex:i] moveBy:moveP];
    for (i=0; i < cnt; i++)
    {   VGraphic	*g = [oList objectAtIndex:i];

        [g scale:scale :scale withCenter:center];
        [g setDirty:NO];
    }

#if 0
{ int i;
  NSPoint s, e;

  printf("VPath\n");
    for (i=0; i<[[path list] count]; i++)
    {	Line	*l1=[[path list] objectAtIndex:i];

        [l1 getVertices:&s :&e];
        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);
    }
  printf("\n3DLinePath\n");
    for (i=0; i<[[linePath list] count]; i++)
    {	VLine3D	*l1=[[linePath list] objectAtIndex:i];

        [l1 getVertices:&s :&e];
        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);
    }
}
#endif
    [conView unlockFocus];
    [win close];
    [bitmapImage release];
#if DEBUG_CONTUR_TIME
printf("%s Hour.Min.Sec End\n\n", [[[NSCalendarDate date] descriptionWithCalendarFormat:@"%H.%M.%S"] UTF8String]);
#endif
    return path;
}

@end
