/***************************************************************************
 *   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 "cellref.h"
#include "cell.h"
#include "element.h"
#include "polygon.h"
#include "box.h"
#include "cellrefarray.h"
#include "strans.h"
#include <math.h>
#include "text.h"
#include "path.h"
#include "cellrefproperties.h"
#include "fileformats/dxf.h"
#include "general/drawingfield.h"
#include "fileformats/gds.h"
#include "fileformats/oasis.h"
#include "fileformats/cif.h"
#include "fileformats/svg.h"
#include <QTextStream>


cellref::cellref(cell *c,QPoint pos)
 : element(){
  cell_ref=c;
  point=pos;
  trans.reset();
}

cellref::cellref()
 : element(){
  cell_ref=NULL;
  trans.reset();
  point=QPoint(0,0);
}

cellref::~cellref(){}

void cellref::setCellRef(cell *cell_){
  cell_ref=cell_;
}

void cellref::setPos(QPoint pos){
  point=pos;
}

void cellref::paint(layoutImagePainter *e){
  if (*e->paintAbort) return;
  if (setup::displayCells) {
  	strans m=e->drawTrans;
  	e->drawTrans.translate(point.x(),point.y());
  	if (trans.mirror_x){e->drawTrans.toggleMirror_x();};
  	e->drawTrans.rotate(trans.angle);
  	e->drawTrans.scale(trans.mag);
	e->drawPixelSize=(int)(1.0/e->drawTrans.mag);
 	e->cellrefDepth++;
	if ((e->cellrefDepth <= setup::depthOfCellrefs)
		||(setup::depthOfCellrefs==0)) cell_ref->paint(e);
	else cell_ref->paintBoundingRec(e,setup::gridColor.rgb());
	e->cellrefDepth--;
  	e->drawTrans=m;
	e->drawPixelSize=(int)(1.0/e->drawTrans.mag);
	}
   else{
	strans m=e->drawTrans;
	e->drawTrans.translate(point.x(),point.y());
	if (trans.mirror_x){e->drawTrans.toggleMirror_x();};
	e->drawTrans.rotate(trans.angle);
	e->drawTrans.scale(trans.mag);
	//e->drawPixelSize=(int)(1.0/e->drawTrans.mag);
	cell_ref->paintBoundingRec(e,setup::gridColor.rgb());
	e->drawTrans=m;
	//e->drawPixelSize=(int)(1.0/e->drawTrans.mag);
  }
  if (setup::displayCellName)
   {
  	if ((e->cellrefDepth ==0))// <setup::depthOfCellrefs)||(setup::depthOfCellrefs==0))
		if (e->visiblePoint( point)) {
		strans trans;
		e->drawText(cell_ref->cellName,setup::fontSize,point,trans,setup::gridColor.rgb());
		}
	}
  if (setup::displayCellOrigin){
    e->drawTarget(point,setup::zeroColor.rgb());
    //e->drawDot(point,setup::zeroColor.rgb());
    //e->drawPoint(point,setup::zeroColor.rgb());
  }
}


void cellref::paintSelect(layoutImagePainter *e){
  if (select){
	if (*e->paintAbort) return;
	if (setup::displayCells) {;
		strans m=e->drawTrans;
		e->drawTrans.translate(point.x(),point.y());
		if (trans.mirror_x){e->drawTrans.toggleMirror_x();};
		e->drawTrans.rotate(trans.angle);
		e->drawTrans.scale(trans.mag);
		e->drawPixelSize=(int)(1.0/e->drawTrans.mag);
		e->cellrefDepth++;
		if ((e->cellrefDepth <= setup::depthOfCellrefs)
		||(setup::depthOfCellrefs==0))cell_ref->paintSelected(e);
		else cell_ref->paintBoundingRec(e,setup::selectColor.rgb());
		e->cellrefDepth--;
		e->drawTrans=m;
		e->drawPixelSize=(int)(1.0/e->drawTrans.mag);
		}
	   else{
		strans m=e->drawTrans;
		e->drawTrans.translate(point.x(),point.y());
		if (trans.mirror_x){e->drawTrans.toggleMirror_x();};
		e->drawTrans.rotate(trans.angle);
		e->drawTrans.scale(trans.mag);
		//e->drawPixelSize=(int)(1.0/e->drawTrans.mag);
		cell_ref->paintBoundingRec(e,setup::selectColor.rgb());
		e->drawTrans=m;
		//e->drawPixelSize=(int)(1.0/e->drawTrans.mag);
	}
	if (setup::displayCellName) {
  		if ((e->cellrefDepth ==0))// <setup::depthOfCellrefs)||(setup::depthOfCellrefs==0))
		if (e->visiblePoint( point)) {
			strans trans;
			e->drawText(cell_ref->cellName,10,point,trans,setup::selectColor.rgb());
		}
	}
  }
}



void cellref::paintSelected(layoutImagePainter *e){
  if (*e->paintAbort) return;
  if (setup::displayCells) {
  	strans m=e->drawTrans;
  	e->drawTrans.translate(point.x(),point.y());
  	if (trans.mirror_x){e->drawTrans.toggleMirror_x();};
  	e->drawTrans.rotate(trans.angle);
  	e->drawTrans.scale(trans.mag);
	e->drawPixelSize=(int)(1.0/e->drawTrans.mag);
	e->cellrefDepth++;;
	if ((e->cellrefDepth <= setup::depthOfCellrefs)
		||(setup::depthOfCellrefs==0))cell_ref->paintSelected(e);
	else cell_ref->paintBoundingRec(e,setup::selectColor.rgb());
	e->cellrefDepth--;
  	e->drawTrans=m;
	e->drawPixelSize=(int)(1.0/e->drawTrans.mag);
	}
  else{
	strans m=e->drawTrans;
	e->drawTrans.translate(point.x(),point.y());
	if (trans.mirror_x){e->drawTrans.toggleMirror_x();};
	e->drawTrans.rotate(trans.angle);
	e->drawTrans.scale(trans.mag);
	//e->drawPixelSize=(int)(1.0/e->drawTrans.mag);
	cell_ref->paintBoundingRec(e,setup::selectColor.rgb());
	e->drawTrans=m;
	//e->drawPixelSize=(int)(1.0/e->drawTrans.mag);
  }
   if (setup::displayCellName) {
  	if ((e->cellrefDepth ==0))// <setup::depthOfCellrefs)||(setup::depthOfCellrefs==0))
		if (e->visiblePoint( point)) {
			strans trans;
			e->drawText(cell_ref->cellName,10,point,trans,setup::selectColor.rgb());
		}
	}
}

void cellref::paintNode(int node, layoutImagePainter *e){
	//if (getNode()==node) paintSelected(e);
	if (*e->paintAbort) return;
	for (int i=0;i<property.size();i++)
		{
		int pnum=property.at(i).getNum();
		//if (pnum>=100000)printf("node %d %d %d\n",node,pnum-100000,property.at(i).getValueInt());
		if (pnum==100000+node){
			if (setup::displayCells) {
  				strans m=e->drawTrans;
  				e->drawTrans.translate(point.x(),point.y());
  				if (trans.mirror_x){e->drawTrans.toggleMirror_x();};
  				e->drawTrans.rotate(trans.angle);
  				e->drawTrans.scale(trans.mag);
				e->cellrefDepth++;;
				if ((e->cellrefDepth <= setup::depthOfCellrefs)
					||(setup::depthOfCellrefs==0)) cell_ref->paintNode(property.at(i).getValueInt(),e);
				e->cellrefDepth--;
  				e->drawTrans=m;
				}
		}
		}
}

void cellref::paintDevice(QString device, layoutImagePainter *e){
	if (getDeviceName()==device) paintSelected(e);
}

void cellref::paintDeviceNode(QString device,int node, layoutImagePainter *e){
	if (getDeviceName()==device) paintNode(node,e);
}

void cellref::paintHighlighted(QPainter *po,strans trans_){
  if (setup::displayCells) {
	strans m=trans_;
  	trans_.translate(point.x(),point.y());
  	if (trans.mirror_x){trans_.toggleMirror_x();};
  	trans_.rotate(trans.angle);
  	trans_.scale(trans.mag);
	cell_ref->paintHighlighted(po,trans_);
	trans_=m;
	}
    else{
	strans m=trans_;
  	trans_.translate(point.x(),point.y());
  	if (trans.mirror_x){trans_.toggleMirror_x();};
  	trans_.rotate(trans.angle);
  	trans_.scale(trans.mag);
	cell_ref->paintHighlightedBoundingRec(po,trans_);
	trans_=m;
	}
   if (setup::displayCellName) {
  	po->setPen(setup::highlightColor);
  	po->drawText(convert(point,trans_),cell_ref->cellName); 
	}
   //paintHighlightedBackground(po,trans_ );
}

void cellref::paintHighlighted(QPainter *po,strans trans_,QPoint p_ ) {
 if (p_==point) {paintHighlighted(po,trans_);}
}

void cellref::paintInfo(QPoint *min,QPoint *max,uint *count)const{
  QPoint pos1,pos2,pos3,pos4;
  uint c2;
  cell_ref->paintInfoGet( &pos2,&pos1,&c2);
  if (c2==0) return;
  pos3=trans.mapIn( pos1)+point;
  pos4=trans.mapIn( pos2)+point;
  if (pos4.x()>max->x())max->setX(pos4.x());
  if (pos3.x()>max->x())max->setX(pos3.x());
  if (pos4.y()>max->y())max->setY(pos4.y());
  if (pos3.y()>max->y())max->setY(pos3.y());
  if (pos4.x()<min->x())min->setX(pos4.x());
  if (pos3.x()<min->x())min->setX(pos3.x());
  if (pos4.y()<min->y())min->setY(pos4.y());
  if (pos3.y()<min->y())min->setY(pos3.y());
  (*count)+=c2;
 //printf("count: %d/%d\n",c2,*count);
  pos3=QPoint(pos2.x(),pos1.y());
  pos4=QPoint(pos1.x(),pos2.y());
  pos3=trans.mapIn( pos3)+point;
  pos4=trans.mapIn( pos4)+point;
  if (pos4.x()>max->x())max->setX(pos4.x());
  if (pos3.x()>max->x())max->setX(pos3.x());
  if (pos4.y()>max->y())max->setY(pos4.y());
  if (pos3.y()>max->y())max->setY(pos3.y());
  if (pos4.x()<min->x())min->setX(pos4.x());
  if (pos3.x()<min->x())min->setX(pos3.x());
  if (pos4.y()<min->y())min->setY(pos4.y());
  if (pos3.y()<min->y())min->setY(pos3.y());
}

void cellref::cSelect(QRect select_){
  if (pointInRect(point,select_)){select=true;}
}

void cellref::cDeselect(QRect select_){
  if (pointInRect(point,select_)){select=false;}
}

void cellref::minimum(QPoint *pos){
  QPoint pos1,pos2;
  QMatrix m=QMatrix();
  /*
  pos1 = *pos - point;
  if (trans.mirror_x){pos1.setY(-pos1.y());};
  //if (trans.angle==180) {pos1.setY(-pos1.y());pos1.setX(-pos1.x());}
  m.rotate(-trans.angle);
  m.scale(1/trans.mag,1/trans.mag);
  pos1=m.map(pos1);
  pos2=pos1;*/
  pos1=QPoint(INT_MIN,INT_MIN);
  pos2=QPoint(INT_MAX,INT_MAX);
  cell_ref->maximum(&pos1);
  cell_ref->minimum(&pos2);
  if (pos1.x()<pos2.x()) return;
  m.reset();
  m.rotate(trans.angle);
  m.scale(trans.mag,trans.mag);
  pos1=m.map(pos1);
  pos2=m.map(pos2);
  if (trans.mirror_x){pos1.setY(-pos1.y());pos2.setY(-pos2.y());};
  //if (trans.angle==180) {pos1.setY(-pos1.y());pos1.setX(-pos1.x());}
  //if (trans.angle==180) {pos2.setY(-pos2.y());pos2.setX(-pos2.x());}
  pos1+=point;
  pos2+=point;
  if (pos2.x()<pos->x())pos->setX(pos2.x());
  if (pos1.x()<pos->x())pos->setX(pos1.x());
  if (pos2.y()<pos->y())pos->setY(pos2.y());
  if (pos1.y()<pos->y())pos->setY(pos1.y());
}

void cellref::maximum(QPoint *pos){
  QPoint pos1,pos2;
  QMatrix m=QMatrix();
/*  pos1 = *pos - point;
  //pos1=QPoint(0,0);
  if (trans.mirror_x){pos1.setY(-pos1.y());};
  //if (trans.angle==180) {pos1.setY(-pos1.y());pos1.setX(-pos1.x());}
   QMatrix m=QMatrix();
  m.rotate(-trans.angle);
  m.scale(1/trans.mag,1/trans.mag);
  pos1=m.map(pos1);
  pos2=pos1;*/
  pos1=QPoint(INT_MIN,INT_MIN);
  pos2=QPoint(INT_MAX,INT_MAX);
  cell_ref->maximum(&pos1);
  cell_ref->minimum(&pos2);
  if (pos1.x()<pos2.x()) return;
  //printf("cref:\npos1 %d %d\n",pos1.x(),pos1.x());
  //printf("pos2 %d %d\n",pos2.x(),pos2.x());
  //if (trans.angle==180) {pos1.setY(-pos1.y());pos1.setX(-pos1.x());}
  //if (trans.angle==180) {pos2.setY(-pos2.y());pos2.setX(-pos2.x());}
  m.reset();
  m.rotate(trans.angle);
  m.scale(trans.mag,trans.mag);
  pos1=m.map(pos1);
  pos2=m.map(pos2);
  //printf("pos1n %d %d\n",pos1.x(),pos1.x());
  //printf("pos2n %d %d\n",pos2.x(),pos2.x());
  if (trans.mirror_x){pos1.setY(-pos1.y());pos2.setY(-pos2.y());};
  pos1+=point;
  pos2+=point;
  if (pos2.x()>pos->x())pos->setX(pos2.x());
  if (pos1.x()>pos->x())pos->setX(pos1.x());
  if (pos2.y()>pos->y())pos->setY(pos2.y());
  if (pos1.y()>pos->y())pos->setY(pos1.y());
}

void cellref::minimumSelect(QPoint *pos) {
 if (!select) return;
 minimum(pos);
}

void cellref::maximumSelect(QPoint *pos) {
 if (!select) return;
 maximum(pos);
}

cell* cellref::depend(){
  return cell_ref;
}

void cellref::saveSelect(QDataStream *stream){
  if (select){
	save(stream);
  }
}
void cellref::save(QDataStream *stream){
	(*stream)<<(qint8)(8);
	(*stream)<<(qint32)(point.x());
	(*stream)<<(qint32)(point.y());
	(*stream)<<(qreal)(trans.angle);
	(*stream)<<(qreal)(trans.mag);
        if (trans.mirror_x) (*stream)<<(qint8)(1);
	else (*stream)<<(qint8)(0);
	(*stream)<<(qint16)cell_ref->cellName.length();
	if (cell_ref->cellName.length()!=0) stream->writeRawData (cell_ref->cellName.toAscii().data(), cell_ref->cellName.length() );
}

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

void cellref::saveGDS(gds *g){
  //SRef
    g->write->writeUInt16(4);
    g->write->writeUInt8(0x0A);
    g->write->writeUInt8(0);
  //(*g->streamPtr)<<(quint16) 4<<(quint8) 0x0A<<(quint8)0;  //SRef
    g->writeString(cell_ref->cellName,0x12);
    qint16 strans_=0;
    if (trans.mirror_x){strans_|=0x8000;};
 /* //{strans_|=0x0002;
   //strans_|=0x0004;};*/
    //STRANS
    g->write->writeUInt16(6);
    g->write->writeUInt8(0x1A);
    g->write->writeUInt8(1);
    g->write->writeInt16((qint16)(strans_));
  //(*g->streamPtr)<<(quint16) 6<<(quint8) 0x1A<<(quint8)1<<(qint16)(strans_);  //STRANS
    //mag
   if (trans.mag!=1){
	g->write->writeUInt16(12);
	g->write->writeUInt8(0x1B);
	g->write->writeUInt8(5);
	//(*g->streamPtr)<<(quint16) 12<<(quint8) 0x1B<<(quint8)5;  //MAG
	g->write8ByteReal(trans.mag);
	}
     //angle
   if (trans.angle!=0){
	g->write->writeUInt16(12);
	g->write->writeUInt8(0x1C);
	g->write->writeUInt8(5);
	//(((*g->streamPtr)<<(quint16) 12<<(quint8) 0x1C<<(quint8)5;  //Angle
	if ((trans.mirror_x)&&(trans.angle!=0)) g->write8ByteReal(360-trans.angle);	
	else  g->write8ByteReal(trans.angle);	
    }
  //xy
    g->write->writeUInt16(((2*4)+4));
    g->write->writeUInt8(0x10);
    g->write->writeUInt8(3);
    g->write->writeInt32((qint32)point.x());g->write->writeInt32(point.y());
  //(*g->streamPtr)<<(quint16) ((2*4)+4)<<(quint8) 0x10<<(quint8)3;  //XY
  //(*g->streamPtr)<<(qint32)(point.x())<<(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
}

void cellref::saveDXF(dxf *d) {
  QString s;
  d->writeEntry(0,"INSERT");
  d->writeEntry(100,"AcDbBlockReference");
  //d->writeEntry(st,8,"0");
  d->writeLayer(0);
  d->writeEntry(2,cell_ref->cellName);
  d->writeEntry(10,s.setNum(point.x()*d->df->userunits));
  d->writeEntry(20,s.setNum(point.y()*d->df->userunits));
  d->writeEntry(30,"   0");
  d->writeEntry(41,s.setNum(trans.mag));
  if (trans.mirror_x) {
	d->writeEntry(42,s.setNum(-trans.mag));}
  else { d->writeEntry(42,s.setNum(trans.mag));}
  d->writeEntry(43,s.setNum(trans.mag));
  d->writeEntry(50,s.setNum(trans.angle));
}

#ifdef USE_3d
void cellref::saveDXF3d(dxf3d*d){
if (select||d->renderAll()){
	view3dRenderMode renderMode=d->renderMode;
	d->renderMode=view3dRenderAll;
	strans m=d->trans;
  	d->trans.translate(point.x(),point.y());
  	if (trans.mirror_x){d->trans.toggleMirror_x();};
  	d->trans.rotate(trans.angle);
  	d->trans.scale(trans.mag);
	cell_ref->saveDXF3d(d);
  	d->trans=m;
	d->renderMode=renderMode;
	}
}
#endif

void cellref::saveSVG(svg *s){
 *(s->str)<<"<use xlink:href=\"#"<<cell_ref->cellName<<"\" ";
 *(s->str)<<"transform=\"";
 *(s->str)<<"translate(";
	s->savePos("",point.x());
	s->savePos("",-point.y());
	*(s->str)<<") ";
 if (trans.angle!=0){
	*(s->str)<<"rotate(";
	if (trans.mirror_x) s->saveNum("",trans.angle);
	else s->saveNum("",-trans.angle);
	*(s->str)<<") ";
	}
 if (trans.mag!=1.0){
	*(s->str)<<"scale(";
	s->saveNum("",trans.mag);
	*(s->str)<<") ";
	}
 if (trans.mirror_x){
	*(s->str)<<"scale(1,-1) ";
	}
 *(s->str)<<"\" />"<<s->endOfLine;
//if (trans.mirror_x) s->error->addItem("Mirrored cellref can not be save in svg.",2);
s->error->addItem("Hierarchical design can not be display by some svg viewers.",4);
}

void cellref::saveOASIS( oasis *o){
 if (!o->modal.absoluteMode){o->setModalAbsoluteMode();}
  qint8 info_byte=(qint8)(128);  //explicid cellname;
  if (trans.mirror_x) info_byte+=1;
  if (trans.mag!=1) info_byte+=4;
  if (trans.angle!=0) info_byte+=2;
  if (point.x()!=o->modal.placement_x) info_byte+=32;
  if (point.y()!=o->modal.placement_y) info_byte+=16;
  o->writeUnsignedInteger((uint)18);
  o->writeRaw(info_byte);
  o->writeString(cell_ref->cellName);
  if (info_byte&4) {
	o->writeReal(trans.mag);
	}
  if (info_byte&2) {
	if (trans.mirror_x) o->writeReal(360-trans.angle);
	else o->writeReal(trans.angle);
	}
  if (info_byte&32) {
	o->modal.placement_x=point.x();
	o->writeSignedInteger(o->modal.placement_x);
	}
  if (info_byte&16) {
	o->modal.placement_y=point.y();
	o->writeSignedInteger(o->modal.placement_y);}  
  saveOASISProperty(o);
}
void cellref::saveCIF( cif *c){
  QString s;
  QString s1;
  s=cell_ref->cellName;
  //for (int i=1;i<c->cellNum;i++){
  //	if (cell_ref->cellName==c->listCells[i]){s1=s1.setNum(i);} }
  s1=s1.setNum(c->hashList.value(cell_ref->cellName));
  s="C "+s1+" ";
  double angle=trans.angle;
  if (trans.mirror_x) {s+="MY ";
      angle=360-trans.angle;
  }
  if (trans.angle!=0) {
  	if (angle==90) {s+="R 0 1 ";}
	else if ((angle==-90)||(angle==270)) {s+="R 0 -1 ";}
	else {
		int y=int(1000.0*tan((double)angle/360*2*M_PI));
		if (y<0) y=-y;
		if (angle>180) y=-y;
		if ((angle>90)&&(angle<270)) s+="R -1000 "+s1.setNum(y)+" ";
		else s+="R 1000 "+s1.setNum(y)+" ";
	}
  }
  s+="T ";
  s+=s1.setNum(point.x())+" ";
  s+=s1.setNum(point.y())+" ";
  s=s.trimmed();
  c->writeEntry(s);
  if (trans.mag!=1.0) {
    QString smag;
    smag.setNum(trans.mag);
    c->reportSave->addItem("cellref magnification is ignored",2,smag);
  }
  
}

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

int cellref::saveEPSCount(){
  int count=(5+1*(16)+13+14+11+5);
  return count;
}

void cellref::moveSelect(QPoint pos){
  if (select) point+=pos;
}

void cellref::move(QPoint pos){
  point+=pos;
}

void cellref::moveOrigin(QPoint p) {
move(trans.mapIn(p));
}

void cellref::resize(double size){
 point*=size;
}

elementList* cellref::flatLayer(int l) { 
}

elementList* cellref::flatSelect(){
  elementList *f,*b,*a=NULL;
  element *c=NULL;
  element *c2;
  strans matrix;
  if (!select) return NULL;
  for (f=cell_ref->firstElement;f!=NULL;f=f->nextElement){
		if (f->thisElement->isBox()){c=f->thisElement->convertToPolygon();}
		if (f->thisElement->isPolygon()){c=new polygon((f->thisElement->getPolygon()));}
		if (f->thisElement->isCellrefArray()){c=new cellrefArray(f->thisElement->getCellrefArray());}
		if (f->thisElement->isCellref()){c=new cellref(f->thisElement->getCellref());}
		if (f->thisElement->isText()){c=new txt(f->thisElement->getText());}
		if (f->thisElement->isPath()){c=new path(f->thisElement->getPath());}
		if (c==NULL) {c=new element();*c=*f->thisElement;}
		c->select=true;
		matrix.reset();
		matrix.translate(point.x(),point.y());
		if (trans.mirror_x){matrix.toggleMirror_x();};
		matrix.rotate(trans.angle);
		matrix.scale(trans.mag);
		c->map(matrix);
		if (f->thisElement->isBox()){
				c2=c->convertToBox();
				if (c2!=NULL){
					delete c;
					c=c2;
					c->select=true;}}
		b=new elementList();
		b->thisElement=c;
		b->nextElement=a;
		c=NULL;
		a=b;};
  return a;
}

void cellref::map(strans m){
  trans*=m;
  point=m.matrix.map(point);
}

void cellref::mapSelect(strans m){
  if (select){
	trans*=m;
  	point=m.matrix.map(point);
	/*//printf("before\n");
	//printf(" angle %f",angle);
	//printf(" mag %f",mag);
	//printf(" mirror %d",mirror_x);
	//printf(" m %f %f %f %f",m.m11(),m.m12(),m.m21(),m.m22());
	//printf("\n");
	QWMatrix matrix;
	matrix.setMatrix(1,0,0,1,0,0);
	matrix.translate(point.x(),point.y());
	if (mirror_x){matrix.scale(1,-1);};
	matrix.rotate(angle);
	matrix.scale(mag,mag);
	matrix=matrix*m;
	//printf("complete\n");
	//printf(" angle %f",angle);
	//printf(" mag %f",mag);
	//printf(" mirror %d",mirror_x);
	//printf(" m %f %f %f %f",matrix.m11(),matrix.m12(),matrix.m21(),matrix.m22());
	//printf("\n");
	mag=matrix.det();
	if (mag<0) {mag*=-1;}
	matrix.scale(1/mag,1/mag);
	angle=asin(matrix.m21())*180/M_PI;
	matrix.rotate(-angle);
	if ((matrix.m12()>0.01)||(matrix.m12()<-0.01)){matrix.rotate(2*angle);angle*=-1;}
	if (matrix.m11()<0) {rotate(180);matrix.rotate(180);}
	if (matrix.m22()<0) {mirror_x=true;}
	else {mirror_x=false;}
	point=m.map(point);
	//printf("after\n");
	//printf(" angle %f",angle);
	//printf(" mag %f",mag);
	//printf(" mirror %d",mirror_x);
	//printf(" m %f %f %f %f",matrix.m11(),matrix.m12(),matrix.m21(),matrix.m22());
	//printf("\n");	*/	
  } 
}

double cellref::areaSelected(){
 return cell_ref->areaSelected()*trans.mag*trans.mag;
}

double cellref::nearestDistance(QPoint p) {
       // return distance(point,p);
	QPoint p1,p2;
	uint i;
	cell_ref->paintInfoGet(&p1,&p2,&i);
	p1=(p1+p2)/2;
	p1=trans.mapIn(p1)+point;
	double d=  distance(p,p1);
	//double dis=distance(point,p);
	//if (d>dis) return dis;
	return d;
	/*QPoint p1=trans.mapOut(p-point);
	p1=cell_ref->nearestPoint(p1);
	p1=trans.mapIn(p1)+point;
	return  distance(p,p1);*/
}

double cellref::nearestDistancePoint(const QPoint p, QPoint *point_)const{
	// return distance(point,p);
	QPoint p1,p2;
	uint i;
	cell_ref->paintInfoGet(&p1,&p2,&i);
	p1=(p1+p2)/2;
	p1=trans.mapIn(p1)+point;
	double d=  distance(p,p1);
	*point_=p1;
	//printf("%d %d\n",p1.x(),p1.y());
	//double dis=distance(point,p);
	//if (d>dis) return dis;
	return d;
	/*QPoint p1=trans.mapOut(p-point);
	p1=cell_ref->nearestPoint(p1);
	p1=trans.mapIn(p1)+point;
	return  distance(p,p1);*/
}

double cellref::nearestDistance(const QPoint p,QPoint *p_)const {
	QPoint p1=trans.mapOut(p-point);
	//QPoint p2=trans.mapOut(p1);
	//printf("%d %d / %d %d\n",p.x(),p.y(),p2.x(),p2.y());
	QPoint p3=trans.mapOut(*p_-point);
	//elementList *e=
	cell_ref->nearestPointVirtual(p1,&p3);
	//printf(":%d %d / %d %d (%f)\n",p1.x(),p1.y(),p3.x(),p3.y(),distance(p1,p3));
	*p_=trans.mapIn(p3)+point;
	//printf(".%d %d / %d %d (%f)\n",p.x(),p.y(),p_->x(),p_->y(),distance(p,*p_));
	return  distance(p,*p_);
        //return distance(point,p);
}

double cellref::nearestLine(QPoint p,QPoint *p_,int radius) {
	QPoint p1=trans.mapOut(p-point);
	QPoint p3=cell_ref->nearestLine(p1,(int)(1.0/trans.mag*radius));
	*p_=trans.mapIn(p3)+point;
	return  distance(p,*p_);
}

double cellref::nearestMiddle(QPoint p,QPoint *p_,int radius) {
	QPoint p1=trans.mapOut(p-point);
	QPoint p3=cell_ref->nearestMiddleLine(p1,(int)(1.0/trans.mag*radius));
	*p_=trans.mapIn(p3)+point;
	return  distance(p,*p_);
}

double cellref::nearestCenter(QPoint p,QPoint *p_,int radius) {
	QPoint p1=trans.mapOut(p-point);
	QPoint p3=cell_ref->nearestCenter(p1,(int)(1.0/trans.mag*radius));
	*p_=trans.mapIn(p3)+point;
	return  distance(p,*p_);
}

bool cellref::showProperties(elementList *el, drawingField *d,bool ) {
    cellrefproperties b(d);
    b.setElement(el->thisElement->getCellref());
    b.show();
    int i=b.exec();
    b.hide();
    switch (i) {
    case QDialog::Rejected :
    	return false;
    case QDialog::Accepted :
    	return false;
    case 2 :
    	return true;
    case 3 :
    	{
	select=true;
	elementList *e=flatSelect();
	elementList *a=e;
	if (e!=NULL)
		for (a=e;a->nextElement!=NULL;a=a->nextElement){}
	a->nextElement=el->nextElement;
	el->nextElement=e;
	return true;
	}
    case 4:
	{
	
	elementList *a=new elementList;
	QPoint pos2;
	QPoint min=QPoint(INT_MAX,INT_MAX);
	QPoint max=QPoint(INT_MIN,INT_MIN);
	cell_ref->minimum(&min);
	cell_ref->maximum(&max);
	if (min==QPoint(INT_MAX,INT_MAX))return true;
	pos2=max-min+point;
	cellrefArray *cra=new cellrefArray(cell_ref,point, pos2,2,2,trans);
	a->thisElement=cra; 
	a->nextElement=el->nextElement;
	el->nextElement=a;
	if (cra->showProperties(a,d,false)){
		delete a->thisElement;
		a->thisElement=NULL;
		}
	return true;
	}
    }
    return false;
}

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

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

void  cellref::findEdge(QPoint p1, QPoint p2,int layer,char dir,int *result){
if ((int)(trans.angle)%90!=0) return;
//if ((int)(trans.mag)!=1) return;
QPoint p3=trans.mapOut(p1-point);
QPoint p4=trans.mapOut(p2-point);
char dir2=dir;
int rot=(int)(trans.angle)/90;
if (trans.mirror_x) {
	switch(dir){
		case 1:dir2=3;
			break;
		case 3:dir2=1;
			break;
	}
}
dir2=dir2-rot;
if (dir2>3) dir2-=4;
if (dir2<0) dir2+=4;
int r=cell_ref->findEdge(p3,p4,layer,dir2);
//printf("%d %d %d rot: %d ",dir,dir2,r,rot);
if ((dir2%2)==0) p3=trans.mapIn(QPoint(r,0))+point;
else p3=trans.mapIn(QPoint(0,r))+point;
switch (dir){
	case 0:
		if ((p3.x()>(*result))&&(p3.x()<p1.x()))
			*result=p3.x();
		break;
	case 1:
		if ((p3.y()>(*result))&&(p3.y()<p1.y()))
			*result=p3.y();
		break;
	case 2:
		if ((p3.x()<(*result))&&(p3.x()>p2.x()))
			*result=p3.x();
		break;
	case 3:
		if ((p3.y()<(*result))&&(p3.y()>p2.y()))
			*result=p3.y();
		break;
}
//printf("%d %d/%d\n",*result,p3.x(),p3.y());
}
void cellref::lineDistanceLayer(QPoint p1,QPoint p2, int *left,int *right,int layer, QPoint , QPoint ){
 
//if ((int)(trans.mag)!=1) return;
QPoint p3=trans.mapOut(p1-point);
QPoint p4=trans.mapOut(p2-point);
int left2=runden(1.0/trans.mag* (*left));
int right2=runden(1.0/trans.mag*(*right));
int left3=left2;
int right3=right2;
if (trans.mirror_x){
	left2=right3;
	right2=left3;
	}
    cell_ref->lineDistanceLayer(p3,p4,&left2,&right2,layer);
if (trans.mirror_x){
	int help=left2;;
	left2=right2;
	right2=help;
	}
//printf(" %d %d %d %d %d %d\n",*left,left2,left3,*right,right2,right3);
if (left2!=left3) *left=runden(trans.mag*left2);
if (right2!=right3) *right=runden(trans.mag*right2);
}

bool cellref::pointOnLayer(QPoint p,int layer){
QPoint p3=trans.mapOut(p-point);
return cell_ref->pointOnLayer(p3,layer);
}

bool operator% (const cellref &b1,const cellref &b2){
if (b1.cell_ref!=b2.cell_ref) return false;
if (!(b1.trans==b2.trans)) return false;
return true;
}

bool operator== (const cellref &b1,const cellref &b2){
if (b1.point!=b2.point) return false;
if (b1.cell_ref!=b2.cell_ref) return false;
if (!(b1.trans==b2.trans)) return false;
return true;
}

