/***************************************************************************
 *   Copyright (C) 2004 by Juergen Thies                                   *
 *   layout@juergenthies.de                                                *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   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         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#define _USE_MATH_DEFINES
#include "path.h"
#include "general/setup.h"
#include "pathproperties.h"
#include "elementlist.h"
#include "polygon.h"
#include <qmatrix.h>
//Added by qt3to4:
#include "pointarray.h"
#include <QTextStream>
#include "fileformats/dxf.h"
#include "fileformats/oasis.h"
#include "fileformats/cif.h"
#include "fileformats/csv.h"
#include "fileformats/gds.h"
#include "fileformats/svg.h"
#include "fileformats/gerber.h"
#include "general/drawingfield.h"
#include "general/drc.h"

#include <math.h>
#include "bool/booleanhandler.h"

path::path()
        : element() {
    pointarray.resize(0);
    p_select.resize(0);
}


path::~path() {}


path::path(pointArray points,int layer)
        : element() {
    layerNum=layer;
    pointarray=points;
    p_select.resize(pointarray.size());
    int i;
    for (i=0;i<p_select.size();i++) {
        p_select.clearBit(i);
    }
    width=0;
    cap=0;
    clean();
}

void path::paint(layoutImagePainter *e) {
 //printf("path\n");
    if (layers::num[layerNum].visible) {
	if (width==0) 
 		e->drawPolygon(&pointarray,layers::layerColor[layerNum]);
	else if ((width<e->drawPixelSize)&&(width>0))
		{
		if (e->detailLevel>3) return;
		e->drawPolygon(&pointarray,layers::layerColor[layerNum]);
		}
	else {
         pointArray p=toPolygon();
	 e->drawPolygon(&p,layers::layerColor[layerNum],layers::num[layerNum].brushStyle);
	}
    }
}


void path::paintSelect(layoutImagePainter *e) {
    if (layers::num[layerNum].visible) {
        if (select) {
	    if (width==0) 
		e->drawPolygon(&pointarray,setup::selectColor.rgb());
	    else if ((width<e->drawPixelSize)&&(width>0))e->drawPolygon(&pointarray,setup::selectColor.rgb());
	    else {
                pointArray p=toPolygon();
	        e->drawPolygon(&p,setup::selectColor.rgb(),Qt::NoBrush);
	        }
        } else {
            int i;
            for (i=0;i<pointarray.size();i++) {
                if (p_select.testBit(i)) 
			e->drawPoint(pointarray.point(i),setup::selectColor.rgb());
            }
        }
    }
}

void path::paintSelected(layoutImagePainter *e) {
    if (width==0) 
		e->drawPolygon(&pointarray,setup::selectColor.rgb());
	else if ((width<e->drawPixelSize)&&(width>0))e->drawPolygon(&pointarray,setup::selectColor.rgb());
	else {
         pointArray p=toPolygon();
	 e->drawPolygon(&p,setup::selectColor.rgb(),Qt::NoBrush);
	}
}

void path::paintNode(int node, layoutImagePainter *e){
	if (layers::num[layerNum].visible)
	if (getNode()==node) paintSelected(e);
}

void path::paintHighlighted(QPainter *po,strans trans_ ){
  po->setPen(setup::highlightColor);
  QBrush br=layer::getBrush(setup::highlightBrush);
  br.setColor(setup::highlightColor);
  po->setBrush(br);
  QPen pen=layers::num[layerNum].pen;
  pen.setJoinStyle(Qt::MiterJoin);
    pen.setColor(setup::highlightColor);
    switch (cap) {
    case 0:
        pen.setCapStyle(Qt::FlatCap);
        break;
    case 1:
        pen.setCapStyle(Qt::RoundCap);
        break;
    case 2:
        pen.setCapStyle(Qt::SquareCap);
        break;
    }
    if (width<0) {
        pen.setWidth(-width);
    } else if (width>0) {
        pen.setWidth((int)(trans_.mag*width));
    }
    po->drawPolyline(convert(pointarray,trans_));
    po->setPen(setup::highlightColor);
    po->setBrush(setup::highlightColor);
    po->drawPolyline(convert(pointarray,trans_));
  //paintHighlightedBackground(po,trans_ );
}

void path::paintHighlighted(QPainter *po,strans trans_,QPoint p_ ) {
  po->setPen(setup::highlightColor);
  QBrush br=layer::getBrush(setup::highlightBrush);
  br.setColor(setup::highlightColor);
  po->setBrush(br);
  QPoint p;
  int x,y;
  int i;
  for (i=0;i<pointarray.size();i++) {
		if (pointarray.point(i)==p_){p=convert(pointarray.point(i),trans_);x=p.x();y=p.y();
				po->drawLine(x-1,y-1,x+1,y+1);
				po->drawLine(x+1,y-1,x-1,y+1);
				po->drawLine(x,y-5,x,y+5);
				po->drawLine(x-5,y,x+5,y);
				}}
}

void path::paintSize(QPainter *po,strans  trans_,double uunits){
}

void path::paintDistance(QPainter *po,strans  trans_, double uunits,element *e) {
}

void path::paintInfo(QPoint *min,QPoint *max,uint *count)const{
   (*count)++;
    int widthH=width/2;
    int i;
    int num=pointarray.size();
    QPoint p;
    for (i=0;i<num;i++) {
        p=pointarray.point(i);
        if (p.x()-widthH<min->x()) {
            min->setX(p.x()-widthH);
        }
        if (p.y()-widthH<min->y()) {
            min->setY(p.y()-widthH);
        }
        if (p.x()+widthH>max->x()) {
            max->setX(p.x()+widthH);
        }
        if (p.y()+widthH>max->y()) {
            max->setY(p.y()+widthH);
        }
    }
}

void path::fSelect(QRect select_) {
    if (layers::num[layerNum].visible) {
        int i;
        for (i=0;i<pointarray.size();i++) {
            if (pointInRect(pointarray.point(i),select_)) {
                select=true;
                clearAllPSelect();
            };
        }
    }
}



void path::fAllSelect(QRect select_) {
    if (layers::num[layerNum].visible) {
        int i;
	bool b=true;
        for (i=0;i<pointarray.size();i++) {
            if (!pointInRect(pointarray.point(i),select_)) {
                b=false;
                
            };
        }
	if (b) {
		clearAllPSelect();
		select=true;}
	
    }
}

void path::fDeselect(QRect select_) {
    if (layers::num[layerNum].visible) {
        int i;
        for (i=0;i<pointarray.size();i++) {
            if (pointInRect(pointarray.point(i),select_)) {
                select=false;
                clearAllPSelect();
            };
        }
    }
}
void path::fAllDeselect(QRect select_) {
    if (layers::num[layerNum].visible) {
        int i;
	bool b=true;
        for (i=0;i<pointarray.size();i++) {
            if (!pointInRect(pointarray.point(i),select_)) {
                b=false;
                
            };
        }
	if (b) {
		clearAllPSelect();
		select=false;}
	
    }
}

void path::pSelect(QRect select_) {
    if (layers::num[layerNum].visible) {
        int i;
        if (select) {
            setAllPSelect();
            select=false;
        }
        for (i=0;i<pointarray.size();i++) {
            if (pointInRect(pointarray.point(i),select_)) {
                p_select.setBit(i);
            }
            ;
        }
        bool b=true;
        for (i=0;i<p_select.size();i++) {
            b=b&&p_select.testBit(i);
        }
        if (b) {
            clearAllPSelect();
            select=true;
        }
    }
}

void path::pDeselect(QRect select_) {
    if (layers::num[layerNum].visible) {
        int i;
        if (select) {
            setAllPSelect();
            select=false;
        }
        for (i=0;i<pointarray.size();i++) {
            if (pointInRect(pointarray.point(i),select_)) {
                p_select.clearBit(i);
            };
        }
        bool b=true;
        for (i=0;i<p_select.size();i++) {
            b=b&&p_select.testBit(i);
        }
        if (b) {
            clearAllPSelect();
            select=true;
        }
    }
}
void path::minimum(QPoint *pos) {
    int i;
    QPoint p;
    for (i=0;i<pointarray.size();i++) {
        p=pointarray.point(i);
        if (p.x()<pos->x()) {
            pos->setX(p.x());
        }
        if (p.y()<pos->y()) {
            pos->setY(p.y());
        }
    }
}

void path::maximum(QPoint *pos) {
    int i;
    QPoint p;
    for (i=0;i<pointarray.size();i++) {
        p=pointarray.point(i);
        if (p.x()>pos->x()) {
            pos->setX(p.x());
        }
        if (p.y()>pos->y()) {
            pos->setY(p.y());
        }
    }
}

void path::minimumSelect(QPoint *pos){
  if (select) minimum(pos);
  else {
  int i;
  QPoint p;
  for (i=0;i<pointarray.size();i++){
    if(p_select.testBit(i)) {
	p=pointarray.point(i);
	if (p.x()<pos->x()){pos->setX(p.x());}
	if (p.y()<pos->y()){pos->setY(p.y());}}
	}
  }
}

void path::maximumSelect(QPoint *pos){
if (select) maximum(pos);
else {
int i;
QPoint p;
for (i=0;i<pointarray.size();i++){
   if(p_select.testBit(i)) {
	p=pointarray.point(i);
	if (p.x()>pos->x()){pos->setX(p.x());}
	if (p.y()>pos->y()){pos->setY(p.y());}}
  }}
}

void path::clearAllPSelect() {
    int i;
    for (i=0;i<p_select.size();i++) {
        p_select.clearBit(i);
    }
}

void path::setAllPSelect() {
    int i;
    for (i=0;i<p_select.size();i++) {
        p_select.setBit(i);
    }
}

void path::invertSelect(){
 if (select) {select=false; return;}
 bool b=false;
 int i;
    for (i=0;i<p_select.size();i++) {
	if (p_select.testBit(i)) {
		p_select.clearBit(i);
		b=true;	
		}
	else {
        	p_select.setBit(i);
	}
    }
 if (!b) {
	clearAllPSelect();
	select=true;
	}
}

void path::deleteSelect() {
    int i,k;
    pointArray pointarray2(pointarray.size());
    k=0;
    for (i=0;i<pointarray.size();i++) {
        if (!p_select.testBit(i)) {
            pointarray2.setPoint(k,pointarray.point(i));
            k++;
        }
    }
    if (p_select.testBit(pointarray.size()-1)&&(pointarray.point(0)==pointarray.point(pointarray.size()-1))) {
        pointarray2.setPoint(k,pointarray2.point(0));
        k++;
    }
    pointarray2.resize(k);
    pointarray.resize(k);
    pointarray=pointarray2;
    p_select.resize(k);
    clearAllPSelect();
}

void path::saveSOURCE( source *o){
}

void path::saveGDS(gds *g) {
	if (pointarray.size()>setup::gdsMaxPoints){ //8191){
		QString s1;
		s1.setNum(setup::gdsMaxPoints);
		g->error->addItem("Path with more than "+s1+" points. Path splitted.",3);
		
		path p=path(this);
		p.pointarray.resize(setup::gdsMaxPoints);
		p.saveGDS(g);
		p.pointarray=pointarray;
		p.pointarray.remove(0,setup::gdsMaxPoints-1);
		p.saveGDS(g);
		return;
	}
QPoint point;
 // path 
    g->write->writeUInt16(4);
    g->write->writeUInt8(9);
    g->write->writeUInt8(0);
//(*g->streamPtr)<<(quint16) 4<<(quint8) 9<<(quint8)0;  //path
 //layer
    g->write->writeUInt16(6);
    g->write->writeUInt8(0x0D);
    g->write->writeUInt8(2);
    if (!setup::gdsMapLayer)
    	g->write->writeInt16((qint16)layerNum);
    else
	g->write->writeInt16((qint16)layers::num[layerNum].mapToLayer);
    //datatype
    g->write->writeUInt16(6);
    g->write->writeUInt8(0x0E);
    g->write->writeUInt8(2);
    if (!setup::gdsMapLayer)
    	g->write->writeInt16((qint16)datatype);
    else
	g->write->writeInt16((qint16)layers::num[layerNum].getMapToDatatype(datatype));
//(*g->streamPtr)<<(quint16) 6<<(quint8) 0x0D<<(quint8)2<<(qint16)(layer_nr);  //layer
//(*g->streamPtr)<<(quint16) 6<<(quint8) 0x0E<<(quint8)2<<(qint16)(datatype);  //Datatype
 //pathtype
    g->write->writeUInt16(6);
    g->write->writeUInt8(0x21);
    g->write->writeUInt8(2);
    g->write->writeInt16((qint16)cap);
//(*g->streamPtr)<<(quint16) 6<<(quint8) 0x21<<(quint8)2<<(qint16)(cap);  //pathtype
 //width
    g->write->writeUInt16(8);
    g->write->writeUInt8(0x0F);
    g->write->writeUInt8(3);
    g->write->writeInt32((qint32)(width));
//(*g->streamPtr)<<(quint16) 8<<(quint8) 0x0F<<(quint8)3<<(qint32)(width);  //width
    int i=pointarray.size();
    if (i>8191) {
    	i=8191;
    	g->error->addItem("Path with more than 8191 points. Data is lost.",1);}
    //(*g->streamPtr)<<(quint16) ((i*2*4)+4)<<(quint8) 0x10<<(quint8)3;  //XY
    //xy 
    g->write->writeUInt16((i*2*4)+4);
    g->write->writeUInt8(0x10);
    g->write->writeUInt8(3);
    for (int k=0;k<i;k++){
	point=pointarray.point(k);
	//((*g->streamPtr)<<(qint32)(point.x())<<(qint32)(point.y());
	g->write->writeInt32((qint32)point.x());g->write->writeInt32((qint32)point.y());
    }
	//properties
	saveGDSProperty(g);
// endel
    g->write->writeUInt16(4);
    g->write->writeUInt8(0x11);
    g->write->writeUInt8(0);
//(*g->streamPtr)<<(quint16) 4<<(quint8) 0x11<<(quint8)0;  //endel
    g->count();
}

void path::save(QDataStream *stream){
	(*stream)<<(qint8)(3);
	(*stream)<<(qint16)(layerNum);
	(*stream)<<(qint16)(datatype);
	(*stream)<<(qint16)(cap);
	(*stream)<<(qint32)(width);
	(*stream)<<(qint16)(pointarray.size());
	for (int i=0;i<pointarray.size();i++){
		(*stream)<<(qint32)(pointarray.point(i).x());
		(*stream)<<(qint32)(pointarray.point(i).y());
	}
}

void path::saveSelect(QDataStream *stream){
  if (select){
	save(stream);
  }
}

void path::saveDXF(dxf *d) {
  QString s;
  d->writeEntry(0,"POLYLINE");
  d->writeEntry(100,"AcDb2dPolyline");
  //d->writeEntry(st,8,setup::layer->nr[layer_nr].name);
  d->writeLayer(layerNum);
  d->writeEntry(66,"   1");
  d->writeEntry(70,"   0");
  d->writeEntry(40,s.setNum(width*d->df->userunits));
  d->writeEntry(41,s.setNum(width*d->df->userunits));
  for (int i=0; i<pointarray.size();i++){
	d->writeEntry(0,"VERTEX");
	d->writeEntry(100,"AcDbVertex");
	d->writeEntry(100,"AcDb2dVertex");
	d->writeEntry(8,layers::num[layerNum].name);
	d->writeEntry(10,s.setNum(pointarray.point(i).x()*d->df->userunits));
	d->writeEntry(20,s.setNum(pointarray.point(i).y()*d->df->userunits));
	}
  d->writeEntry(0,"SEQEND");
//dxf::writeEntry(st,8,setup::layer->nr[layer_nr].name);
}

#ifdef USE_3d
void path::saveDXF3d(dxf3d*d){
if (select||d->renderAll()){
	pointArray pa=toPolygon();
	pa.clean();
	d->save(layerNum,pa);
	}
}
#endif

void path::saveSVG(svg *s){
*(s->str)<<"<polyline points=\"";
for (int i=0; i<pointarray.size();i++){
	s->savePos("",pointarray.point(i).x());
	s->savePos("",-pointarray.point(i).y());
	}
*(s->str)<<"\" ";
s->saveValue("fill","none");
s->saveValue("stroke",layers::num[layerNum].pen.color().name());
if (width<0) {
	QString s1;
	s1.setNum(-width);
	s->saveValue("stroke-width",s1+"px");
	}
if (width>0) {
	s->savePos("stroke-width",width);
	}
*(s->str)<<"/>"<<s->endOfLine;
if (cap!=0) s->error->addItem("Path caps can not be saved in svg.",2);
}

void path::saveOASIS( oasis *o){
  int oasisDatatype=datatype;
  int oasisLayer=layerNum;
  if (!setup::oasisMapLayer){
	oasisLayer=layers::num[layerNum].mapToLayer;
	oasisDatatype=layers::num[layerNum].getMapToDatatype(datatype);
  }
 if (!o->modal.absoluteMode){o->setModalAbsoluteMode();}
  qint8 info_byte=(qint8)(128+32);  //write pointlist+extension;
  if (oasisLayer!=o->modal.layer) info_byte+=1;
  if (oasisDatatype!=o->modal.datatype) info_byte+=2;
  if (pointarray.point(0).x()!=o->modal.geometry_x) info_byte+=16;
  if (pointarray.point(0).y()!=o->modal.geometry_y) info_byte+=8;
  if ((width/2)!=o->modal.path_halfwidth) info_byte+=64;
  o->writeUnsignedInteger((uint)22);
  o->writeRaw(info_byte);
  if (info_byte&1) {
	o->modal.layer=oasisLayer;
	o->writeUnsignedInteger((uint)o->modal.layer);
	}
  if (info_byte&2) {
	o->modal.datatype=oasisDatatype;
	o->writeUnsignedInteger((uint)oasisDatatype);
	}
  if (info_byte&64) {
	o->modal.path_halfwidth=width/2;
	if (o->modal.path_halfwidth<0)
	 {o->modal.path_halfwidth=0;
	 o->error->addItem("Negavite/absolut width is not possible in OASIS files.",4);
	 }
	o->writeUnsignedInteger((uint)o->modal.path_halfwidth);}
  if (cap==0) o->writeUnsignedInteger((uint)5);
  else if (cap==2) o->writeUnsignedInteger((uint)10);
  else {
  o->writeUnsignedInteger((uint)5);
  o->error->addItem("Round caps are not possible in OASIS files.",4);
  }
  o->writePointArray(pointarray,false);
  if (info_byte&16) {
	o->modal.geometry_x=pointarray.point(0).x();
	o->writeSignedInteger(o->modal.geometry_x);
	}
  if (info_byte&8) {
	o->modal.geometry_y=pointarray.point(0).y();
	o->writeSignedInteger(o->modal.geometry_y);}  
 o->count();
 saveOASISProperty(o);
}
void path::saveCIF( cif *c){
  QString s1;
  QString s="L "+layers::num[layerNum].name;
  c->writeEntry(s);
  s="W ";
  if (width>=0) s+=s1.setNum(width)+" ";
  else s+="0 ";
  for (int i=0;i<pointarray.size();i++){
  	s+=s1.setNum(pointarray.point(i).x())+",";
	s+=s1.setNum(pointarray.point(i).y())+" ";
  }
  if ((width!=0)&&(cap!=1))c->reportSave->addItem("Only round caps are possible in CIF format.",3);
  if ((width<0))c->reportSave->addItem("Absolut width is not possible in CIF format.",3);
  s=s.trimmed();
  c->writeEntry(s);
}

void path::saveCSV( csv *c){
 if (select) c->savePointArray(pointarray);
}

void path::saveGerber( gerber *g){
 if (g->saveLayer!=layerNum) return;
	if ((width<=0)){
		g->reportSave->addItem("Pathes must have a positive width to be saved in gerber format.",3);
		return;
		}
 	if (cap==1){
		QString apertur=g->aperturCircle(width);
		g->write(apertur,pointarray.point(0),2);
		for (int i=1;i<pointarray.size();i++){
			g->write(apertur,pointarray.point(i),1);
		}
	}
	else if (cap==2) {
		QString apertur=g->aperturSquare(width);
		g->write(apertur,pointarray.point(0),2);
		for (int i=1;i<pointarray.size();i++){
			g->write(apertur,pointarray.point(i),1);
		}
	}else {
		pointArray pa=toPolygon();
		if (pa.size()==0) return;
		g->writeOutput("G36*\r\nG01");
		g->writeOutput(pa.point(0),2);
		for (int i=1;i<pa.size();i++){
			g->writeOutput(pa.point(i),1);
		}
		g->writeOutput("G37*\r\n");
	}
}

void path::saveODB( odb *g){
#ifdef netlistutility
#endif
}

void path::saveEPS( eps *e){
}

int path::saveEPSCount(){
  int count=29+20+20+11+pointarray.size()*(16+1)+9+7+20;
  return count;
}

void path::moveSelect(QPoint pos) {
    int i;
    QPoint p;
    if (select)
        pointarray.translate(pos.x(),pos.y());
    else {
        for (i=0;i<pointarray.size();i++) {
            if (p_select.testBit(i)) {
                p=pointarray.point(i);
                p=p+pos;
                pointarray.setPoint(i,p);
            }
        }
    clean();
    }
}

void path::move(QPoint pos) {
    pointarray.translate(pos.x(),pos.y());
}
void path::resize(double size) {
    int i;
    QPoint p;
    width=element::runden(size*width);
    for (i=0;i<pointarray.size();i++) {
        p=pointarray.point(i)*size;
        pointarray.setPoint(i,p);
    }
}

void path::resize(double size,int mod, bool *b){
if (width %mod!=0) *b=true;
    for (int i=0;i<pointarray.size();i++) {
        if (pointarray.point(i).x()%mod!=0) *b=true;
        if (pointarray.point(i).y()%mod!=0) *b=true;
    }

resize(size);
}

void path::mapSelect(strans m) {
    if (!select) return;
    if (width>0) {
        width=(int)(m.mag*width);
    }
   int i;
    QPoint p;
    if (select) {
        for (i=0;i<pointarray.size();i++) {
            p=pointarray.point(i);
            p=m.matrix.map(p);
            pointarray.setPoint(i,p);
        }
    } else {
        for (i=0;i<pointarray.size();i++) {
            if (p_select.testBit(i)) {
                p=pointarray.point(i);
                p=m.matrix.map(p);
                pointarray.setPoint(i,p);
            }
        }
    }
}

void path::map(strans m) {
    if (width>0) {
        width=(int)(m.mag*width);
    }
    int i;
    QPoint p;
    for (i=0;i<pointarray.size();i++) {
        p=pointarray.point(i);
        p=m.matrix.map(p);
        pointarray.setPoint(i,p);
    }
}

void path::deletePoint(uint pos) {
    for (int i=pos;i<pointarray.size()-1;i++) {
        pointarray.setPoint(i,pointarray.point(i+1));
    }
    pointarray.resize(pointarray.size()-1);
    p_select.resize(pointarray.size());
}

void path::addPoint(uint pos) {
    pointarray.resize(pointarray.size()+1);
    p_select.resize(pointarray.size());
    for (int i=pointarray.size()-1;i>(int)pos;i--) {
        pointarray.setPoint(i,pointarray.point(i-1));
    }
}

void path::clean() {
    QPoint p;
    //for (uint i=0; i<pointarray.size();i++){printf("c x %d y %d\n",pointarray.point(i).x(),pointarray.point(i).y());}
    //überflüssige Punkte entfernen
    for (int i=0;i<(int)pointarray.size()-1;i++) {
        if (pointarray.size()<=2)
            return; //no area
        if (pointarray.point(i)==pointarray.point(i+1)) {
            deletePoint(i+1);
            i--;
	    continue;
        }
        if (i>=2) if (onLine(pointarray.point(i),pointarray.point(i-2),pointarray.point(i-1))) {
		deletePoint(i-1);
           	i--;
		continue;
		}
	if (i==2) if (onLine(pointarray.point(i),pointarray.point(i-1),pointarray.point(i-2))){
		deletePoint(i-2);
           	i--;
		continue;
		}
	if ((i==pointarray.size()-2)&&(i>2)) if (onLine(pointarray.point(i),pointarray.point(i-1),pointarray.point(i+1))){
		deletePoint(i+1);
           	i--;
		continue;
		}
    }
}

bool path::correct() {
    if (pointarray.size()<2)
        return false;
    if ((pointarray.size()==2)&&(pointarray.point(0)==pointarray.point(1))&&(cap==0)) return false;
    return true;
}

void path::roundSelect(int n) {
    for (int i=(int)pointarray.size()-1;i>=0;i--) {
        if (p_select.testBit(i)||select) {
            pointarray.setPoint(i,round(pointarray.point(i),n));
        }
    }
    if ((select)&&(width>0)) {
	width=((int((width+(n/2)))/n)*n);
        }
    clean();
}

void path::sizeadjustSelect(int value) {
if (select)
    if (width!=0) {
        if (width>0) {
            width+=value+value;
            if (width<0)
                width=0;
        } else {
            width-=value-value;
            if (width>0)
                width=0;
        }
    }
}

double path::nearestDistance(QPoint p) {
    if (layers::num[layerNum].visible) {
        double dis=1.1E99;
        double d;
        for (int i=0; i<pointarray.size();i++) {
            d=distance(pointarray.point(i),p);
            if (d<dis) {
                dis=d;
            };
        }
        return dis;
    } else
        return 1.1E99;
}

double path::nearestDistance(const QPoint p,QPoint *p_) const{
    if (layers::num[layerNum].visible) {
        double dis=1.1E99;
        double d;
        for (int i=0; i<pointarray.size();i++) {
            d=distance(pointarray.point(i),p);
            if (d<dis) {
                dis=d;
		*p_=pointarray.point(i);
            };
        }
        return dis;
    } else
        return 1.1E99;
}

double path::nearestLine( QPoint p,QPoint *point,int) {
 if (layers::num[layerNum].visible) {
    double dis=1.1E99;
    double d;
    for (int i=0; i<pointarray.size()-1;i++){
    	QPoint h=pointarray.point(i)-pointarray.point(i+1);
	QPoint help=p+QPoint(-h.y(),h.x());
	cutPoint3(p,help,pointarray.point(i),pointarray.point(i+1),&h);
	d=distance(h,p);
	bool between=true;
	if ((h.x()<pointarray.point(i).x())&&(h.x()<pointarray.point(i+1).x())) between=false;
	if ((h.x()>pointarray.point(i).x())&&(h.x()>pointarray.point(i+1).x())) between=false;
	if ((h.y()<pointarray.point(i).y())&&(h.y()<pointarray.point(i+1).y())) between=false;
	if ((h.y()>pointarray.point(i).y())&&(h.y()>pointarray.point(i+1).y())) between=false;
            if ((d<dis)&&between) {
                 dis=d;
		 *point=h;
		 };
    }
    return dis;}
  else return 1.1E99;
}

double path::nearestMiddle(QPoint p,QPoint *point,int) {
 if (layers::num[layerNum].visible) {
    double dis=1.1E99;
    double d;
    for (int i=0; i<pointarray.size()-1;i++){
    	QPoint help=(pointarray.point(i)+pointarray.point(i+1))/2;
	d=distance(help,p);
        if (d<dis) {
                 dis=d;
		 *point=help;
		 };
    }
    return dis;}
  else return 1.1E99;
return 0;
}


bool path::showProperties(elementList *el, drawingField *d ,bool basicEditing) {
    pathproperties b(d->userunits);
    b.setElement(el->thisElement->getPath(),basicEditing);
    b.show();
    int i=b.exec();
    b.hide();
    switch (i) {
    case QDialog::Rejected :
        return false;
    case QDialog::Accepted :
        clean();
        return false;
    case 2 :
        return true;
    case 3 : {
            elementList *e;
            e=new elementList();
            e->nextElement=el->nextElement;
            e->thisElement=convertToPolygon();
            el->nextElement=e;
            if (e->thisElement!=NULL)
                return true;
            return false;
        }
    case 4 : {
            elementList *e;
            e=new elementList();
            e->nextElement=el->nextElement;
            e->thisElement=closeToPolygon();
            el->nextElement=e;
            if (e->thisElement!=NULL)
                return true;
            return false;
        }

    }
    return false;
}

double path::areaSelected() {
    double a=0;
    if (width<=0)
        return 0;
    for (int i=1;i<pointarray.size();i++) {
        a+=width*distance(pointarray.point(i-1),pointarray.point(i));
    }
    switch (cap) {
    case 1:
        a+=(width*width/4*M_PI);
        break;
    case 2:
        a+=(width*width);
        break;
    }
    return a;
}

double path::circumferenceSelected(){
 double a=length()*2;
    switch (cap) {
    case 0:
	a+=(2*width);
	break;
    case 1:
        a+=(width*M_PI);
        break;
    case 2:
        a+=(4*width);
        break;
    }
    return a;
 return a;
}


polygon* path::closeToPolygon() {
    if (pointarray.size()<3)
        return NULL;
    pointArray points=pointarray;
    points.resize(points.size()+1);
    points.setPoint(points.size()-1,points.point(0));
    polygon *p=new polygon(points,layerNum);
    return p;
}

polygon* path::convertToPolygonIfClosed(){
    if (pointarray.size()<3)
        return NULL;
    pointArray points=pointarray;
    if (points.point(points.size()-1)!=points.point(0))return NULL;
    polygon *p=new polygon(points,layerNum);
    return p;
}

bool path::pointInsideElement(QPoint p){
if (width==0) return false;
return pointInPolygon(toPolygon(),p);
}

pointArray path::toPolygonSimple()const{
return toPolygon(true);
}


pointArray path::toPolygon(bool simple)const{
    if ((pointarray.size()==2)&&(pointarray.point(0)==pointarray.point(1))){
	switch (cap) {
	case 0: return pointarray; break;
	case 1: {
		QPoint p1=pointarray.point(0)+QPoint((int)((0.5)*(double)(abs(width))),0);
		pointArray p=element::spirale(pointarray.point(0),p1,p1,setup::circularDefault);
		return p;
		break;}
	case 2: {
		pointArray p;
		p.resize(5);
		int w=(int)((0.5)*(double)(abs(width)));
		p.setPoint(0,pointarray.point(0)+QPoint(w,w));
		p.setPoint(1,pointarray.point(0)+QPoint(-w,w));
		p.setPoint(2,pointarray.point(0)+QPoint(-w,-w));
		p.setPoint(3,pointarray.point(0)+QPoint(w,-w));
		p.setPoint(4,pointarray.point(0)+QPoint(w,w));
		return p;
		break;
		}
	}
    }
    QMatrix mp90,mn90;
    double factor;
    mp90.setMatrix(1,0,0,1,0,0);
    mn90=mp90;
    mp90.rotate(90);
    mn90.rotate(-90);
    pointArray a1,a2;
    QPoint p,p1,p2,p_,pc;
    bool b;
    p=pointarray.point(1)-pointarray.point(0);
    factor=1.0/element::length(p)*(0.5)*(double)(abs(width));
    p.setX(round((double)(p.x())*factor));
    p.setY(round((double)(p.y())*factor));
    p1=pointarray.point(0)+mp90.map(p);
    p2=pointarray.point(0)+mn90.map(p);
    int pos1=0,pos2=0;
    a1.resize(1);
    a2.resize(1);
    switch (cap) {
    case 0:
        a1.setPoint(0,p1);
        a2.setPoint(0,p2);
        pos1=1;
        pos2=1;
        break;
    case 1:
        for (int i=90;i<=270;i+=10) {
            QMatrix m;
            m.setMatrix(1,0,0,1,0,0);
            m.rotate(-i);
            pos1++;
            a1.resize(pos1);
            a1.setPoint(pos1-1,pointarray.point(0)+m.map(p));
        }
        pos2=1;
        a2.setPoint(0,p2);
        break;
    case 2:
        a1.setPoint(0,p1-(p));
        a2.setPoint(0,p2-(p));
        pos1=1;
        pos2=1;
        break;
    }
    for (int i=1;i<pointarray.size()-1;i++) {
        p_=p;
        p=pointarray.point(i+1)-pointarray.point(i);
        factor=1.0/element::length(p)*(0.5)*(double)(width);
        p.setX(round((double)(p.x())*factor));
        p.setY(round((double)(p.y())*factor));
        factor=angle(pointarray.point(i-1),pointarray.point(i),pointarray.point(i+1));
	if (!simple) if ((factor>179.5)||(factor<-179.5)){
		pointArray pa1=pointarray;
		pointArray pa2=pa1.cut(i);
		path help(this);
		help.pointarray=pa1;
		pa1=help.toPolygonSimple();
		help.pointarray=pa2;
		pa2=help.toPolygon();
		booleanHandler boolean;
		boolean.setA(&pa1);
		boolean.setB(&pa2);
		QList<pointArray> pl=boolean.getAPlusB();
		if (pl.size()>=1) return pl.at(0);
		}
        //printf("angle: %e\n",factor);
        p1=pointarray.point(i)+mp90.map(p);
        p2=pointarray.point(i+1)+mp90.map(p);
	if (a1.point(pos1-1)!=pointarray.point(i)+mp90.map(p_))
        	b=cutPoint3(a1.point(pos1-1),pointarray.point(i)+mp90.map(p_),p1,p2,&pc);
	else 	b=cutPoint3(a1.point(pos1-1),pointarray.point(i-1)+mp90.map(p_),p1,p2,&pc);
        pos1++;
        a1.resize(pos1);
        if (b) {
	    if ((cap==1)&&(factor<0)) //runde extensions
		 {
		a1.setPoint(pos1-1,pointarray.point(i)+mp90.map(p_));
		 for (int k=(int)factor+10;k<0;k+=10) {
            		QMatrix m=mp90;
            		m.rotate(-k);
            		pos1++;
            		a1.resize(pos1);
            		a1.setPoint(pos1-1,pointarray.point(i)+m.map(p));
        		}
		pos1++;
        	a1.resize(pos1);
		a1.setPoint(pos1-1,pointarray.point(i)+mp90.map(p));
		}
	    else if ((factor<-170)) {  //sptizen entfernen
                a1.setPoint(pos1-1,pointarray.point(i)+mp90.map(p_));
                pos1++;
                a1.resize(pos1);
                a1.setPoint(pos1-1,p1);
            } else {
                a1.setPoint(pos1-1,pc);
            }
        } else {
            a1.setPoint(pos1-1,p1);
        } //parallel
        p1=pointarray.point(i)+mn90.map(p);
        p2=pointarray.point(i+1)+mn90.map(p);
	if (a2.point(pos2-1)!=pointarray.point(i)+mn90.map(p_))
        	b=cutPoint3(a2.point(pos2-1),pointarray.point(i)+mn90.map(p_),p1,p2,&pc);
	else 	b=cutPoint3(a2.point(pos2-1),pointarray.point(i-1)+mn90.map(p_),p1,p2,&pc);
        pos2++;
        a2.resize(pos2);
        if (b) {
	    if ((cap==1)&&(factor>0)) //runde extensions
		 {
		a2.setPoint(pos2-1,pointarray.point(i)+mn90.map(p_));
		 for (int k=(int)factor-10;k>0;k-=10) {
            		QMatrix m=mn90;
            		m.rotate(-k);
            		pos2++;
            		a2.resize(pos2);
            		a2.setPoint(pos2-1,pointarray.point(i)+m.map(p));
        		}
		pos2++;
        	a2.resize(pos2);
		a2.setPoint(pos2-1,pointarray.point(i)+mn90.map(p));
		}
            else if ((factor>170)) { //sptizen entfernen
                a2.setPoint(pos2-1,pointarray.point(i)+mn90.map(p_));
                pos2++;
                a2.resize(pos2);
                a2.setPoint(pos2-1,p1);
            } else {
                a2.setPoint(pos2-1,pc);
            }
        } else {
            a2.setPoint(pos2-1,p1);
        } //paralell
    }
    p=pointarray.point(pointarray.size()-1)-pointarray.point(pointarray.size()-2);
    factor=1.0/element::length(p)*(0.5)*(double)(width);
    p.setX(round((double)(p.x())*factor));
    p.setY(round((double)(p.y())*factor));
    p1=pointarray.point(pointarray.size()-1)+mp90.map(p);
    p2=pointarray.point(pointarray.size()-1)+mn90.map(p);
    switch (cap) {
    case 0:
        pos1++;
        pos2++;
        a1.resize(pos1);
        a2.resize(pos2);
        a1.setPoint(pos1-1,p1);
        a2.setPoint(pos2-1,p2);
        break;
    case 1:
        for (int i=270;i>=90;i-=10) {
            QMatrix m;
            m.setMatrix(1,0,0,1,0,0);
            m.rotate(i);
            pos1++;
            a1.resize(pos1);
            a1.setPoint(pos1-1,pointarray.point(pointarray.size()-1)-m.map(p));
        }
        break;
    case 2:
        pos1++;
        pos2++;
        a1.resize(pos1);
        a2.resize(pos2);
        a1.setPoint(pos1-1,p1+(p));
        a2.setPoint(pos2-1,p2+(p));
        break;
    }
    for (uint i=a2.size();i>0;i--) {
        pos1++;
        a1.resize(pos1);
        a1.setPoint(pos1-1,a2.point(i-1));
    }
    pos1++;
    a1.resize(pos1);
    a1.setPoint(pos1-1,a1.point(0));
    return a1;
}

polygon* path::convertToPolygon()const {
    if (width<=0)
        return NULL;
    //if (pointarray.size()<2)
    //    return NULL;

    /*for (uint i=0;i<a1.size();i++){
    printf(" %d: x:%d y:%d\n",i,a1.point(i).x(),a1.point(i).y());
    }*/
    polygon *po=new polygon(toPolygon(),layerNum);
    po->datatype=datatype;
    po->property=property;
    return po;
}

elementList* path::cutSelect(QPoint p1, QPoint p2) {
    if (!select)
        return NULL;
    clean();
    pointArray a_copy,a1;
    a_copy=pointarray;
    QPoint pos;
    bool b;
    int anz_cp=0;
    elementList *a=NULL;
    elementList *c;
    path *p;
    int nr=0;
    // Schnittpunkte bestimmen
    for (int i=0; i<a_copy.size()-1;i++) {
    	if (anz_cp>0) {
			nr++;
			a1.resize(nr);
			a1.setPoint(nr-1,a_copy.point(i));
		}
        b=cutPoint(p1,p2,a_copy.point(i),a_copy.point(i+1),&pos);
        if (b&&(pos!=a_copy.point(i+1))) {
            if ((p1!=pos)&&(p2!=pos)) {
	    	if (anz_cp==0) {
			if (pos!=a_copy.point(i)){
				pointarray.resize(i+2);
    				pointarray.setPoint(i+1,pos);
   			 	clean();
				anz_cp++;
				a1.resize(1);
				a1.setPoint(0,pos);
				nr=1;	
			}
		} else
		{
                	anz_cp++;
			nr++;
			a1.resize(nr);
			a1.setPoint(nr-1,pos);
			p=new path(a1,layerNum);
			p->setCap(cap);
			p->setWidth(width);
			p->selectAll();
			//p->select=true;
       			p->clean();
        		c=new elementList();
        		c->thisElement=p;
        		c->nextElement=a;
        		a=c;
			a1.resize(1);
			a1.setPoint(0,pos);
			nr=1;
		}
            }
        }
    }
    if (anz_cp>0) {
    	nr++;
	a1.resize(nr);
	a1.setPoint(nr-1,a_copy.point(a_copy.size()-1));
    	p=new path(a1,layerNum);
	p->selectAll();
	p->setCap(cap);
	p->setWidth(width);
	//p->select=true;
       	p->clean();
        c=new elementList();
        c->thisElement=p;
        c->nextElement=a;
        a=c;
    	}
    return a;
}

bool path::mergeSelect(path *p){
  if (!select) return false;
  if (!p->select) return false;
  if (width!=p->width) return false;
  if (layerNum!=p->layerNum) return false;
  if (pointarray.point(0)==p->pointarray.point(0)){
	for (int i=0; i<p->pointarray.size();i++){addPoint(0);pointarray.setPoint(0,p->pointarray.point(i));}
	return true;
  }
  if (pointarray.point(0)==p->pointarray.point(p->pointarray.size()-1)){
	for (int i=p->pointarray.size()-1;i>=0;i--){addPoint(0);pointarray.setPoint(0,p->pointarray.point(i));}
	return true;
  }
  if (pointarray.point(pointarray.size()-1)==p->pointarray.point(0)){
	for (int i=0; i<p->pointarray.size();i++){addPoint(pointarray.size()+1);pointarray.setPoint(pointarray.size()-1,p->pointarray.point(i));}
	return true;
  }
  if (pointarray.point(pointarray.size()-1)==p->pointarray.point(p->pointarray.size()-1)){
	for (int i=p->pointarray.size()-1;i>=0;i--){addPoint(pointarray.size()+1);pointarray.setPoint(pointarray.size()-1,p->pointarray.point(i));}
	return true;
  }
return false;
}

void path::expandCaps(int beginExt , int endExt){
if (pointarray.size()==1) return;
QPoint deltaBegin=pointarray.point(0)-pointarray.point(1);
if (deltaBegin==QPoint(0,0)) deltaBegin=QPoint(-1,0);
QPoint deltaEnd=pointarray.point(pointarray.size()-1)-pointarray.point(pointarray.size()-2);
if (deltaEnd==QPoint(0,0)) deltaEnd=QPoint(1,0);
cap=0;
pointarray.setPoint(0,pointarray.point(0)+(deltaBegin*beginExt/element::length(deltaBegin)));
pointarray.setPoint(pointarray.size()-1,pointarray.point(pointarray.size()-1)+(deltaEnd*endExt/element::length(deltaEnd)));
}

bool path::identicalStructure(element *e){
if (e->isPath()) {
	path *b=reinterpret_cast<path(*)>(e);
	if ((*b)==(*this)) return true;
	}
return false;
}

bool operator% (const path &b1,const path &b2){
if (b1.layerNum!=b2.layerNum) return false;
if (b1.datatype!=b2.datatype) return false;
if (b1.pointarray.size()!=b2.pointarray.size()) return false;
if (b1.pointarray.size()==0) return true;
bool b=true;
QPoint off=b1.pointarray.point(0)-b2.pointarray.point(0);
for (int i=0;i<b1.pointarray.size();i++){
	if (b1.pointarray.point(i)!=b2.pointarray.point(i)+off) b=false;
	}
if (b) return true;
b=true;
off=b1.pointarray.point(0)-b2.pointarray.point(b2.pointarray.size()-1);
for (int i=0;i<b1.pointarray.size();i++){
	if (b1.pointarray.point(i)!=b2.pointarray.point(b2.pointarray.size()-i-1)+off) b=false;
	}
return b;
}

bool path::identical(element *e){
if (e->isPath()) {
	path *b=reinterpret_cast<path(*)>(e);
	if ((*b)==(*this)) return true;
	}
return false;
}

bool operator== (const path &b1,const path &b2){
if (b1.layerNum!=b2.layerNum) return false;
if (b1.datatype!=b2.datatype) return false;
if (b1.pointarray.size()!=b2.pointarray.size()) return false;
bool b=true;
for (int i=0;i<b1.pointarray.size();i++){
	if (b1.pointarray.point(i)!=b2.pointarray.point(i)) b=false;
	}
if (b) return true;
b=true;
for (int i=0;i<b1.pointarray.size();i++){
	if (b1.pointarray.point(i)!=b2.pointarray.point(b2.pointarray.size()-i-1)) b=false;
	}
return b;
}


double path::length(){
double l=0;
QPoint p=pointarray.point(0);
for (int i=1;i<pointarray.size();i++){
	l+=element::length(pointarray.point(i)-p);
	p=pointarray.point(i);
	}
return l;
}

bool path::isArc(QPoint *p, int *radius, double *start,double *end){
  if (pointarray.size()<4) return false;
  pointArray pa=element::fitToCircle(pointarray);
  if (pa.size()<3) return false;
  long long x,y;
  x=0;y=0;
  for (int i=1; i<pa.size();i++){
	x+=pa.point(i).x();
	y+=pa.point(i).y();
	}
  x=runden((double)x/(pa.size()-1));
  y=runden((double)y/(pa.size()-1));
  QPoint pc=QPoint(x,y);
  double d=distance(pc,pointarray.point(0));
  double sum=d;
  double min=d;
  double max=d;
  int offset=(int) (0.02*distance(pc,pa.point(0)))+10;
  for (int i=1; i<pointarray.size();i++){
	double d1=distance(pc,pointarray.point(i));
	sum+=d1;
	//printf("arc %f center: %d %d\n",d1,pc.x(),pc.y());
	if (d1>max) { max=d1; if (max>d+offset) return false;};
	if (d1<min) { min=d1; if (min<d-offset) return false;};
	}
  (*p)=(pc);
  (*radius)=runden(sum/(pointarray.size()));
  offset=(int)(0.001*(*radius)+3);
  if ((*radius)<runden(max-offset)) return false;
  if ((*radius)>runden(min+offset)) return false;
  (*start)=angle(pc,pointarray.point(0));
  if ((*start)<0) (*start)+=360;
  if ((*start)>359.95) (*start=0);
  (*end)=angle(pc,pointarray.point(pointarray.size()-1));
  if ((*end)<0) (*end)+=360;
  if ((*end)>359.95) (*end=0);
  double ah=angle(pc,pointarray.point(1));;
  if (ah<0) ah+=360;
  if ((*start)<(*end)){
	if ((ah>(*start))&&(ah< (*end))) {
	//ok
	}
	else {
	//swap
 	     ah=(*start);
	     (*start)=(*end);
	     (*end)=ah;
	}
	}
   else {
	if ((ah<(*start))&&(ah> (*end))){
	     ah=(*start);
	     (*start)=(*end);
	     (*end)=ah;
	}
	}

  //double f=sum/(pointarray.size()-1);
  //printf("arc min:%f max:%f d:%f r:%f \n",min,max,d,f);
  //printf("arc start:%f end:%f \n",(*start),(*end));
  //printf("center: %d %d radius: %d \n",pc.x(),pc.y(),(*radius));
  return true;
}

void  path::findEdge(QPoint p1, QPoint p2,int layer,char dir,int *result){
if (layer!=layerNum) return;
if (width<=0) return;
QPoint pa;
pa=pointarray.point(0);
int capExtend=0;
int wh=width/2;
if (cap>0) capExtend=wh;
switch(dir){
	case 0:
		for (int i=1;i<pointarray.size();i++){
			QPoint p=pointarray.point(i);
			if (((pa.y()>p2.y())&&(p.y()<p1.y()))||((p.y()>p2.y())&&(pa.y()<p1.y())))
			if ((p.x()==pa.x())&&(p.x()+wh>(*result))&&(p.x()+wh<p1.x()))
				*result=p.x()+wh;
			pa=p;
		}
		break;
	case 1:
		for (int i=1;i<pointarray.size();i++){
			QPoint p=pointarray.point(i);
			if (((pa.x()>p2.x())&&(p.x()<p1.x()))||((p.x()>p2.x())&&(pa.x()<p1.x())))
			if ((p.y()==pa.y())&&(p.y()+wh>(*result))&&(p.y()+wh<p1.y()))
				*result=p.y()+wh;
			pa=p;
		}
		break;
	case 2:
		for (int i=1;i<pointarray.size();i++){
			QPoint p=pointarray.point(i);
			if (((pa.y()>p2.y())&&(p.y()<p1.y()))||((p.y()>p2.y())&&(pa.y()<p1.y())))
			if ((p.x()==pa.x())&&(p.x()-wh<(*result))&&(p.x()-wh>p2.x()))
				*result=p.x()-wh;
			pa=p;
		}
		break;
	case 3:
		for (int i=1;i<pointarray.size();i++){
			QPoint p=pointarray.point(i);
			if (((pa.x()>p2.x())&&(p.x()<p1.x()))||((p.x()>p2.x())&&(pa.x()<p1.x())))
			if ((p.y()==pa.y())&&(p.y()-wh<(*result))&&(p.y()-wh>p2.y()))
				*result=p.y()-wh;
			pa=p;
		}
		break;
}
if (pointarray.size()<2) return;
int s=pointarray.size()-1;
switch(dir){
	case 0:
		if ((pointarray.point(0).y()+wh>p2.y())&&(pointarray.point(0).y()-wh<p1.y()))
		if ((pointarray.point(0).y()==pointarray.point(1).y())&&(pointarray.point(1).x()<pointarray.point(0).x())&&
			(pointarray.point(0).x()+capExtend>(*result))&&(pointarray.point(0).x()+capExtend<p1.x()))
			  *result=pointarray.point(0).x()+capExtend;
		if ((pointarray.point(s).y()+wh>p2.y())&&(pointarray.point(s).y()-wh<p1.y()))
		if ((pointarray.point(s).y()==pointarray.point(s-1).y())&&(pointarray.point(s).x()>pointarray.point(s-1).x())&&
			(pointarray.point(s).x()+capExtend>(*result))&&(pointarray.point(s).x()+capExtend<p1.x()))
			  *result=pointarray.point(s).x()+capExtend;
		break;
	case 1:
		if ((pointarray.point(0).x()+wh>p2.x())&&(pointarray.point(0).x()-wh<p1.x()))
		if ((pointarray.point(0).x()==pointarray.point(1).x())&&(pointarray.point(1).y()<pointarray.point(0).y())&&
			(pointarray.point(0).y()+capExtend>(*result))&&(pointarray.point(0).y()+capExtend<p1.y()))
			  *result=pointarray.point(0).y()+capExtend;
		if ((pointarray.point(s).x()+wh>p2.x())&&(pointarray.point(s).x()-wh<p1.x()))
		if ((pointarray.point(s).x()==pointarray.point(s-1).x())&&(pointarray.point(s).y()>pointarray.point(s-1).y())&&
			(pointarray.point(s).y()+capExtend>(*result))&&(pointarray.point(s).y()+capExtend<p1.y()))
			  *result=pointarray.point(s).y()+capExtend;	
		break;
	case 2:
		if ((pointarray.point(0).y()+wh>p2.y())&&(pointarray.point(0).y()-wh<p1.y()))
		if ((pointarray.point(0).y()==pointarray.point(1).y())&&(pointarray.point(1).x()>pointarray.point(0).x())&&
			(pointarray.point(0).x()-capExtend<(*result))&&(pointarray.point(0).x()-capExtend>p2.x()))
			  *result=pointarray.point(0).x()-capExtend;
		if ((pointarray.point(s).y()+wh>p2.y())&&(pointarray.point(s).y()-wh<p1.y()))
		if ((pointarray.point(s).y()==pointarray.point(s-1).y())&&(pointarray.point(s).x()<pointarray.point(s-1).x())&&
			(pointarray.point(s).x()-capExtend<(*result))&&(pointarray.point(s).x()-capExtend>p2.x()))
			  *result=pointarray.point(s).x()-capExtend;
		break;
	case 3:
		if ((pointarray.point(0).x()+wh>p2.x())&&(pointarray.point(0).x()-wh<p1.x()))
		if ((pointarray.point(0).x()==pointarray.point(1).x())&&(pointarray.point(1).y()>pointarray.point(0).y())&&
			(pointarray.point(0).y()-capExtend<(*result))&&(pointarray.point(0).y()-capExtend>p2.y()))
			  *result=pointarray.point(0).y()-capExtend;
		if ((pointarray.point(s).x()+wh>p2.x())&&(pointarray.point(s).x()-wh<p1.x()))
		if ((pointarray.point(s).x()==pointarray.point(s-1).x())&&(pointarray.point(s).y()<pointarray.point(s-1).y())&&
			(pointarray.point(s).y()-capExtend<(*result))&&(pointarray.point(s).y()-capExtend>p2.y()))
			  *result=pointarray.point(s).y()-capExtend;			
		break;
}
}

void path::lineDistanceLayer(QPoint p1,QPoint p2, int *left,int *right,int layer, QPoint min, QPoint max){
    if (layer!=layerNum) return;
    if (pointarray.size()==0) return;
    int widthH=width/2;
    if (widthH<0) widthH=0;
    QPoint minPath,maxPath;
    minPath=pointarray.point(0);
    maxPath=minPath;
    QPoint p;
    for (int i=0;i<pointarray.size();i++) {
        p=pointarray.point(i);
        if (p.x()-widthH<minPath.x()) minPath.setX(p.x()-widthH);
        if (p.y()-widthH<minPath.y()) minPath.setY(p.y()-widthH);
        if (p.x()+widthH>maxPath.x()) maxPath.setX(p.x()+widthH);
        if (p.y()+widthH>maxPath.y()) maxPath.setY(p.y()+widthH);
    }
    if (max.x()<minPath.x())return ;
    if (min.x()>maxPath.x())return ;
    if (max.y()<minPath.y())return ;
    if (min.y()>maxPath.y())return ;
    //printf("path max %d %d %d %d\n",maxPath.x(),maxPath.y(),minPath.x(),minPath.y());
    //printf("search max %d %d %d %d\n",max.x(),max.y(),min.x(),min.y());
    pointArray pa=toPolygon();
    pa.lineDistance(p1,p2,left,right);
}

void path::cropSharpAnglesSelect(int n){
double a,b;
for (int i=(int)pointarray.size()-2;i>0;i--) {
	if (p_select.testBit(i)||select){
		a=angle(pointarray.point(i+1),pointarray.point(i),pointarray.point(i-1));
		if ((fabs(a)>90.001)&&(fabs(a)<179.999)){
			b=1.0/sin((180-fabs(a))*M_PI/360)*(n/2);
			//printf("%d : %f/%f\n",i,a,b);
			QPoint ph=pointarray.point(i);
			QPoint p2=pointarray.point(i)-pointarray.point(i+1);
			pointarray.insert(i+1,QPoint(0,0));
			pointarray.setPoint(i+1,ph-(p2*(b/element::length(p2))));
			p2=pointarray.point(i)-pointarray.point(i-1);
			pointarray.setPoint(i,ph-(p2*(b/element::length(p2))));
			p_select.resize(pointarray.size());
		}
	}}
}

bool path::pointOnLayer(QPoint p,int layer){
    if (layer!=layerNum) return false;
    if (pointarray.size()==0) return false;
    if (element::pointInPolygon(toPolygon(),p)) return true;
return false;
}

bool path::drcMinSize(int val,drc *DRC,bool sharpAngles){
}

bool path::drcAngle90(drc *DRC){
bool b=true;
for (int i=1;i<pointarray.size();i++){
	QPoint dif=pointarray.point(i-1)-pointarray.point(i);
	if ((dif.x()!=0)&&(dif.y()!=0)){
		b=false;
		DRC->reportErrorDeg((pointarray.point(i-1)+pointarray.point(i))/2,angle(pointarray.point(i-1),pointarray.point(i)));
		}
	}
return b;
}
bool path::drcAngle45(drc *DRC){
bool b=true;
for (int i=1;i<pointarray.size();i++){
	QPoint dif=pointarray.point(i-1)-pointarray.point(i);
	if (dif.x()<0)dif.setX(-dif.x());
	if (dif.y()<0)dif.setY(-dif.y());
	if ((dif.x()!=0)&&(dif.y()!=0)&&(dif.x()!=dif.y())){
		b=false;
		DRC->reportErrorDeg((pointarray.point(i-1)+pointarray.point(i))/2,angle(pointarray.point(i-1),pointarray.point(i)));
		}
	}
return b;
}
bool path::drcAngle(double ang ,drc *DRC){
bool b=true;
double a;
for (int i=(int)pointarray.size()-2;i>0;i--) {
	a=angle(pointarray.point(i+1),pointarray.point(i),pointarray.point(i-1));
		if ((fabs(a)>ang+0.001)&&(fabs(a)<179.999)) {
			b=false;
			DRC->reportErrorDeg(pointarray.point(i),a);
		}
	}
return b;
}

void path::snapSelectGet(QHash<int,QPoint> *h){
     if (select) {
       
     } else {
	for (int i=(int)pointarray.size()-1;i>=0;i--) {
	    if (!p_select.testBit(i)) {
	        QList<QPoint> l=h->values(pointarray.point(i).x());
		if (!l.contains(pointarray.point(i))) h->insertMulti(pointarray.point(i).x(),pointarray.point(i));
	    }
	}
     }
}

void path::snapSelectSnap(QHash<int,QPoint> *h,int radius){
  bool moved=false;
     for (int i=(int)pointarray.size()-1;i>=0;i--) {
	    if (p_select.testBit(i)||select) {
	        double snapdist=radius+1;
		bool snaped=false;
		int x1=pointarray.point(i).x();
		QPoint snapTo;
		for (int x=0;x<=radius;++x){
		  QList<QPoint> l=h->values(x1+x);
		  if (x!=0) l<<h->values(x1-x);
		  for (int k=l.size();k>0;--k){
		    if (distance(pointarray.point(i),l.at(k-1))<snapdist){
		      snaped=true; moved=true; snapdist=distance(pointarray.point(i),l.at(k-1));
		      snapTo=l.at(k-1);
		    }
		  }
		}
		if (snaped)
		  pointarray.setPoint(i,snapTo);
		else{
		  QList<QPoint> l=h->values(pointarray.point(i).x());
                  if (!l.contains(pointarray.point(i))) h->insertMulti(pointarray.point(i).x(),pointarray.point(i));
		}
	    }

     }
  if (moved) clean();
}
