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

cellrefArray::cellrefArray(cell *c,pointArray array,int anzx,int anzy)
        : element() {
    cell_ref=c;
    point=array.point(0);
    space_x=(array.point(1)-point)/anzx;
    space_y=(array.point(2)-point)/anzy;
    anz_x=anzx;
    anz_y=anzy;
    trans.reset();
    clean();
}

cellrefArray::cellrefArray(cell *c,QPoint pos1,QPoint pos2,int anzx,int anzy)
        : element() {
    cell_ref=c;
    point=pos1;
    QPoint p=pos2-pos1;
    space_x=QPoint(p.x(),0);
    space_y=QPoint(0,p.y());
    anz_x=anzx;
    anz_y=anzy;
    trans.reset();
    clean();
}

cellrefArray::cellrefArray(cell *c,QPoint pos1, QPoint pos2,int anzx,int anzy,strans trans_){
    cell_ref=c;
    point=pos1;
    QPoint p=pos2-pos1;
    space_x=QPoint(p.x(),0);
    space_y=QPoint(0,p.y());
    anz_x=anzx;
    anz_y=anzy;
    trans.reset();
    trans*=trans_;
    clean();
		}

cellrefArray::~cellrefArray() {}

cellrefArray::cellrefArray()
        : element() {
    cell_ref=NULL;
    trans.reset();
}

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

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

void cellrefArray::clean(){
}

void cellrefArray::paint(layoutImagePainter *e) {
    if (*e->paintAbort) return;
    if (setup::displayCells) {
    	QPoint pos;
    	int x,y;
	e->cellrefDepth++;
	strans m=e->drawTrans;
	QPoint max=QPoint(INT_MIN,INT_MIN);
    	QPoint min=QPoint(INT_MAX,INT_MAX);
    	uint count;
    	cell_ref->paintInfoGet( &min,&max,&count);
	int pdifx=(int)(e->drawTrans.mag*(max.x()-min.x()));
	int pdify=(int)(e->drawTrans.mag*(max.y()-min.y()));
	bool spaceOK=true;
	bool spacePositive=true;
#define useSecStage 25
	if (useSecStage<(int)(e->drawTrans.mag*space_x.x())) spaceOK=false;
	if (useSecStage<(int)(e->drawTrans.mag*space_y.y())) spaceOK=false;
	if (space_x.x()<0) {spaceOK=false;spacePositive=false;}
	if (space_y.x()!=0) spaceOK=false;
	if (space_x.y()!=0) spaceOK=false;
	if (space_y.y()<0) {spaceOK=false;spacePositive=false;}
	if ((anz_x>(useSecStage<<1))&&(anz_y>(useSecStage<<1))&&(pdifx<12)&&(pdify<12)&&(trans.mag==1)&&(trans.angle==0)&&
			(!(trans.mirror_x))
			&&(e->drawTrans.angle==0)&&(e->drawTrans.mirror_x)&&spaceOK){
				if (e->visibleBox(point+space_x*anz_x+space_y*anz_y+max,point+min)) {
			//zweistufig image paint
				//erste stufe
				int sec=pdifx/4+4;
				//printf("cellreff1 %d\n",pdifx+sec*2);
				layoutImage dp(pdifx+sec*2,pdify+sec*2);
				dp.setPaintAbort(e->paintAbort);
				strans trans=dp.getDrawTrans();
				trans.translate(sec,sec);
				trans.scale(e->drawTrans.mag);
				trans.toggleMirror_x();;
				trans.translate(-min.x(),-max.y());
				dp.setDrawTrans(trans);
				//dp.fill(setup::backgroundColor.rgb());
				dp.setBackground();
				//dp.imagePainter->drawPixelSize=(int)(1.0/trans.mag);
				dp.imagePainter->cellrefDepth=e->cellrefDepth;
				cell_ref->paint(dp.imagePainter);
				//zweite Stufe
				int spacexx=(int)(e->drawTrans.mag*(space_x.x())*useSecStage);
				int spaceyy=(int)(e->drawTrans.mag*(space_y.y())*useSecStage);
				layoutImage dp2((spacexx)+pdifx+sec*2,(spaceyy)+pdify+sec*2);
				//printf("size %d %d\n",(spacexx+spaceyx)+pdifx+sec*2,(spacexy+spaceyy)+pdify+sec*2);
				dp2.setPaintAbort(e->paintAbort);
				strans trans2=dp2.getDrawTrans();
				trans2.translate(sec,sec);
				trans2.scale(e->drawTrans.mag);
				dp2.setDrawTrans(trans2);
				//dp2.fill(setup::backgroundColor.rgb());
				dp2.setBackground();
				//dp.imagePainter->drawPixelSize=(int)(1.0/trans.mag);
				dp2.imagePainter->cellrefDepth=e->cellrefDepth;
				for (x=0;x<useSecStage;x++) {
					 for (y=0;y<useSecStage;y++) {
						pos=space_x*x+space_y*y;
						QPoint p1=convert(pos,trans2);
						p1+=QPoint(-sec,-sec);
						//printf("%d %d\n",p1.x(),p1.y());
						dp2.imagePainter->drawImage(*(dp.getImage()),p1.x(),p1.y());
						}
					 if (*e->paintAbort) return;
				}
				for (x=0;x<anz_x;x+=useSecStage) {
					 if (x+useSecStage>=anz_x) x=anz_x-useSecStage;
					 for (y=0;y<anz_y;y+=useSecStage) {
						if (y+useSecStage>=anz_y) y=anz_y-useSecStage;
						pos=point+space_x*x+space_y*y+QPoint(min.x(),space_y.y()*(useSecStage-1)+max.y())+QPoint(e->drawPixelSize/3,e->drawPixelSize/3);
						QPoint p1=convert(pos,e->drawTrans);
						p1+=QPoint(-sec,-sec);
						e->drawImage(*(dp2.getImage()),p1.x(),p1.y());
						}
					 if (*e->paintAbort) return;
				}
			}}
	else if ((anz_x*anz_y>4)&&(pdifx<150)&&(pdify<150)&&(trans.mag==1)&&(trans.angle==0)&&
			(!(trans.mirror_x))&&(count>3)
			&&(e->drawTrans.angle==0)&&(e->drawTrans.mirror_x)){
				int sec=pdifx/4+4;
				//printf("cellreff1 %d\n",pdifx+sec*2);
				layoutImage dp(pdifx+sec*2,pdify+sec*2);
				dp.setPaintAbort(e->paintAbort);
				strans trans=dp.getDrawTrans();
				trans.translate(sec,sec);
				trans.scale(e->drawTrans.mag);
				trans.toggleMirror_x();;
				trans.translate(-min.x(),-max.y());
				dp.setDrawTrans(trans);
				//dp.fill(setup::backgroundColor.rgb());
				dp.setBackground();
				//dp.imagePainter->drawPixelSize=(int)(1.0/trans.mag);
				dp.imagePainter->cellrefDepth=e->cellrefDepth;
				cell_ref->paint(dp.imagePainter);
			int xStart=0;
			int yStart=0;
			int xStop=anz_x;
			int yStop=anz_y;
			#define paintOptStep 100
			for (int x=xStart;x<xStop;x++) {
				for (int y=yStart;y<yStop;y++) {
						pos=point+space_x*x+space_y*y+QPoint(min.x(),max.y())+QPoint(e->drawPixelSize/3,e->drawPixelSize/3);
						QPoint p1=convert(pos,e->drawTrans);
						p1+=QPoint(-sec,-sec);
						e->drawImage(*(dp.getImage()),p1.x(),p1.y());
						}
					 if (*e->paintAbort) return;
				}
	}
	else if ((anz_x>100)&&(anz_y>100)&&(trans.mag==1)&&(trans.angle==0)&&
			(!(trans.mirror_x))&&spacePositive){
		if (e->visibleBox(point+space_x*anz_x+space_y*anz_y+max,point+min)) {
			//printf("opt\n");
			int xStart=0;
			int yStart=0;
			int xStop=anz_x;
			int yStop=anz_y;
			#define paintOptStep 100
			//printf("stop y %d\n",xStop);
			for (int x=xStart;x<xStop;x++) {
				for (int y=yStart;y<yStop;y++) {
					pos=point+space_x*x+space_y*y;
					e->drawTrans.translate(pos.x(),pos.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);
					if ((e->cellrefDepth <= setup::depthOfCellrefs)
					||(setup::depthOfCellrefs==0))cell_ref->paint(e);
					else cell_ref->paintBoundingRec(e,setup::gridColor.rgb());
					e->drawTrans=m;
					e->drawPixelSize=(int)(1.0/e->drawTrans.mag);
				}
			}
		}
	}
	else {
	//printf("full\n");
        for (x=0;x<anz_x;x++) {
          for (y=0;y<anz_y;y++) {
		//printf("cellreff3\n");
            	pos=point+space_x*x+space_y*y;
            	e->drawTrans.translate(pos.x(),pos.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);
            	if ((e->cellrefDepth <= setup::depthOfCellrefs)
		||(setup::depthOfCellrefs==0))cell_ref->paint(e);
		else cell_ref->paintBoundingRec(e,setup::gridColor.rgb());
            	e->drawTrans=m;
		e->drawPixelSize=(int)(1.0/e->drawTrans.mag);
          	}
	    if (*e->paintAbort) return;
            }
		
	 }

    e->cellrefDepth--;
    } else {
	for (int x=0;x<anz_x;x++) {
          for (int y=0;y<anz_y;y++) {
		//printf("cellreff3\n");
		strans m=e->drawTrans;
            	QPoint pos=point+space_x*x+space_y*y;
            	e->drawTrans.translate(pos.x(),pos.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());
  }
}



void cellrefArray::paintSelect(layoutImagePainter *e) {
    if (*e->paintAbort) return;
    if (select) {
	
		  paintSelected(e);
	}
/*
	e->cellrefDepth++;
	strans m=e->drawTrans;
    	QPoint pos;
    	int x,y;
        for (x=0;x<anz_x;x++) {
            for (y=0;y<anz_y;y++) {
                pos=point+space_x*x+space_y*y;
                e->drawTrans.translate(pos.x(),pos.y());
                if (trans.mirror_x) {
                    e->drawTrans.toggleMirror_x();
                };
                e->drawTrans.rotate(trans.angle);
                e->drawTrans.scale(trans.mag);
                if ((e->cellrefDepth <= setup::depthOfCellrefs)
		||(setup::depthOfCellrefs==0))cell_ref->paintSelected(e);
		else cell_ref->paintBoundingRec(e,setup::selectColor.rgb());
                e->drawTrans=m;
            }
        }
        e->cellrefDepth--;
      }else{
	for (int x=0;x<anz_x;x++) {
          for (int y=0;y<anz_y;y++) {
		//printf("cellreff3\n");
		strans m=e->drawTrans;
            	QPoint pos=point+space_x*x+space_y*y;
            	e->drawTrans.translate(pos.x(),pos.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 cellrefArray::paintSelected( layoutImagePainter *e) {
    if (*e->paintAbort) return;
    if (setup::displayCells) {
	QPoint pos;
    	int x,y;
	e->cellrefDepth++;
	strans m=e->drawTrans;
	QPoint max=QPoint(INT_MIN,INT_MIN);
    	QPoint min=QPoint(INT_MAX,INT_MAX);
    	uint count;
    	cell_ref->paintInfoGet( &min,&max,&count);
	int pdifx=(int)(e->drawTrans.mag*(max.x()-min.x()));
	int pdify=(int)(e->drawTrans.mag*(max.y()-min.y()));
	if ((anz_x*anz_y>1000)){
		QPoint pointMax=QPoint(INT_MIN,INT_MIN);
		QPoint pointMin=QPoint(INT_MAX,INT_MAX);	
		uint i=0;
		paintInfo(&pointMin,&pointMax,&i);
		e->drawBox.setPoint(0,pointMin);
		e->drawBox.setPoint(1,QPoint(pointMax.x(),pointMin.y()));
		e->drawBox.setPoint(2,pointMax);
		e->drawBox.setPoint(3,QPoint(pointMin.x(),pointMax.y()));
		e->drawBox.setPoint(4,pointMin);
  		e->drawPolygon(&e->drawBox,setup::selectColor.rgb());
	}
	else if ((anz_x*anz_y>4)&&(pdifx<150)&&(pdify<150)&&(trans.mag==1)&&(trans.angle==0)&&
			(!(trans.mirror_x))&&(count>3)
			&&(e->drawTrans.angle==0)&&(e->drawTrans.mirror_x)){
				int sec=pdifx/4+4;
				//printf("cellreff1 %d\n",pdifx+sec*2);
				layoutImage dp(pdifx+sec*2,pdify+sec*2);
				dp.setPaintAbort(e->paintAbort);
				strans trans=dp.getDrawTrans();
				trans.translate(sec,sec);
				trans.scale(e->drawTrans.mag);
				trans.toggleMirror_x();;
				trans.translate(-min.x(),-max.y());
				dp.setDrawTrans(trans);
				//dp.fill(setup::backgroundColor.rgb());
				dp.setBackground();
				//dp.imagePainter->drawPixelSize=(int)(1.0/trans.mag);
				dp.imagePainter->cellrefDepth=e->cellrefDepth;
				cell_ref->paintSelected(dp.imagePainter);
				for (x=0;x<anz_x;x++) {
					 for (y=0;y<anz_y;y++) {
						pos=point+space_x*x+space_y*y+QPoint(min.x(),max.y())+QPoint(e->drawPixelSize/3,e->drawPixelSize/3);
						QPoint p1=convert(pos,e->drawTrans);
						p1+=QPoint(-sec,-sec);
						e->drawImage(*(dp.getImage()),p1.x(),p1.y());
						}
				}
	}
	else {
        for (x=0;x<anz_x;x++) {
          for (y=0;y<anz_y;y++) {
		//printf("cellreff3\n");
            	pos=point+space_x*x+space_y*y;
            	e->drawTrans.translate(pos.x(),pos.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);
            	if ((e->cellrefDepth <= setup::depthOfCellrefs)
		||(setup::depthOfCellrefs==0))cell_ref->paintSelected(e);
		else cell_ref->paintBoundingRec(e,setup::selectColor.rgb());
            	e->drawTrans=m;
		e->drawPixelSize=(int)(1.0/e->drawTrans.mag);
          	}
            }
	 }

    e->cellrefDepth--;
    }else if ((anz_x*anz_y>1000)){
		QPoint pointMax=QPoint(INT_MIN,INT_MIN);
		QPoint pointMin=QPoint(INT_MAX,INT_MAX);	
		uint i=0;
		paintInfo(&pointMin,&pointMax,&i);
		e->drawBox.setPoint(0,pointMin);
		e->drawBox.setPoint(1,QPoint(pointMax.x(),pointMin.y()));
		e->drawBox.setPoint(2,pointMax);
		e->drawBox.setPoint(3,QPoint(pointMin.x(),pointMax.y()));
		e->drawBox.setPoint(4,pointMin);
  		e->drawPolygon(&e->drawBox,setup::selectColor.rgb());
	}
    else{
	for (int x=0;x<anz_x;x++) {
          for (int y=0;y<anz_y;y++) {
		//printf("cellreff3\n");
		strans m=e->drawTrans;
            	QPoint pos=point+space_x*x+space_y*y;
            	e->drawTrans.translate(pos.x(),pos.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 cellrefArray::paintNode(int , layoutImagePainter *){
	//if (getNode()==node) paintSelected(e);
}


void cellrefArray::paintHighlighted( QPainter *po,strans trans_ ) {
    strans m=trans_;
    QPoint pos;
    int x,y;
    if (setup::displayCells) {
	{
	for (x=0;x<anz_x;x++) {
		for (y=0;y<anz_y;y++) {
		pos=point+space_x*x+space_y*y;
		trans_.translate(pos.x(),pos.y());
		if (trans.mirror_x) {
			trans_.toggleMirror_x();
		};
		trans_.rotate(trans.angle);
		trans_.scale(trans.mag);
		if (anz_x*anz_y>20) cell_ref->paintHighlightedBoundingRec(po,trans_);
		else
		cell_ref->paintHighlighted(po,trans_);
		trans_=m;
		}
    	}
	}}
  else{
	for (x=0;x<anz_x;x++) {
		for (y=0;y<anz_y;y++) {
		pos=point+space_x*x+space_y*y;
		trans_.translate(pos.x(),pos.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); //,-1);
	}
 // paintHighlightedBackground(po,trans_ );
}

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

void cellrefArray::paintInfo(QPoint *min,QPoint *max,uint *count)const{
  QPoint pos1,pos2,pos3,pos4,pos5,pos6;
  uint c2;
  cell_ref->paintInfoGet( &pos4,&pos5,&c2);
  pos1=QPoint(pos4.x(),pos5.y());
  pos2=QPoint(pos5.x(),pos4.y());
  (*count)+=c2*anz_x*anz_y;
//printf("count array: %d/%d\n",c2,*count);
  if (c2==0) return;
      for (int x=0;x<2;x++) {
        for (int y=0;y<2;y++) {
           	pos3=point+space_x*x*(anz_x-1)+space_y*y*(anz_y-1);
		pos6=trans.mapIn( pos4)+pos3;
  		if (pos6.x()>max->x())max->setX(pos6.x());
  		if (pos6.x()<min->x())min->setX(pos6.x());
  		if (pos6.y()>max->y())max->setY(pos6.y());
  		if (pos6.y()<min->y())min->setY(pos6.y());
		pos6=trans.mapIn( pos5)+pos3;
  		if (pos6.x()>max->x())max->setX(pos6.x());
  		if (pos6.x()<min->x())min->setX(pos6.x());
  		if (pos6.y()>max->y())max->setY(pos6.y());
  		if (pos6.y()<min->y())min->setY(pos6.y());
		pos6=trans.mapIn( pos1)+pos3;
  		if (pos6.x()>max->x())max->setX(pos6.x());
  		if (pos6.x()<min->x())min->setX(pos6.x());
  		if (pos6.y()>max->y())max->setY(pos6.y());
  		if (pos6.y()<min->y())min->setY(pos6.y());
		pos6=trans.mapIn( pos2)+pos3;
  		if (pos6.x()>max->x())max->setX(pos6.x());
  		if (pos6.x()<min->x())min->setX(pos6.x());
  		if (pos6.y()>max->y())max->setY(pos6.y());
  		if (pos6.y()<min->y())min->setY(pos6.y());

	}}
}


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

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

void cellrefArray::minimum(QPoint *pos) {
    QPoint pos1,pos2,pos3;
    QPoint max=QPoint(INT_MIN,INT_MIN);
    QPoint min=QPoint(INT_MAX,INT_MAX);
	cell_ref->maximum(&max);
    cell_ref->minimum(&min);
	if (max.x()<min.x()) return;
    for (int x=0;x<2;x++) {
        for (int y=0;y<2;y++) {
            pos3=point+space_x*x*(anz_x-1)+space_y*y*(anz_y-1);
			QMatrix m=QMatrix();
         //   pos1 = *pos - pos3;
	    /*if (trans.angle==180) {
		pos1.setY(-pos1.y());
		pos1.setX(-pos1.x());
		}*/
        /*    if (trans.mirror_x) {
                pos1.setY(-pos1.y());
            };
            QMatrix m=QMatrix();
  	    m.rotate(-trans.angle);
	    m.scale(1/trans.mag,1/trans.mag);
  	    pos1=m.map(pos1);
            pos2=pos1;*/
         //   cell_ref->maximum(&max);
         //   cell_ref->minimum(&min);
	    m.reset();
            m.rotate(trans.angle);
 	    m.scale(trans.mag,trans.mag);
            pos1=m.map(max);
            pos2=m.map(min);
            if (trans.mirror_x) {
                pos1.setY(-pos1.y());
                pos2.setY(-pos2.y());
            };
	  /*  if (trans.angle==180){
		pos1.setY(-pos1.y());
		pos1.setX(-pos1.x());
		pos2.setY(-pos2.y());
		pos2.setX(-pos2.x());
		}*/
            pos1+=pos3;
            pos2+=pos3;
			//printf("min p3 %d,%d p1 %d,%d, p2 %d,%d\n",pos3.x(),pos3.y(),pos1.x(),pos1.y(),pos2.x(),pos2.y());
            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 cellrefArray::maximum(QPoint *pos) {
    QPoint pos1,pos2,pos3;
	QPoint max=QPoint(INT_MIN,INT_MIN);
    QPoint min=QPoint(INT_MAX,INT_MAX);
	cell_ref->maximum(&max);
    cell_ref->minimum(&min);
	if (max.x()<min.x()) return;
    for (int x=0;x<2;x++) {
        for (int y=0;y<2;y++) {
            pos3=point+space_x*x*(anz_x-1)+space_y*y*(anz_y-1);
         /*   pos1 = *pos - pos3;
            if (trans.mirror_x) {
                pos1.setY(-pos1.y());
            };*/
 	    QMatrix m=QMatrix();
  	 /*   m.rotate(-trans.angle);
	    m.scale(1/trans.mag,1/trans.mag);
  	    pos1=m.map(pos1);
            pos2=pos1;
            cell_ref->maximum(&pos1);
            cell_ref->minimum(&pos2);*/
  	    m.reset();
            m.rotate(trans.angle);
	    m.scale(trans.mag,trans.mag);
            pos1=m.map(max);
            pos2=m.map(min);
            if (trans.mirror_x) {
                pos1.setY(-pos1.y());
                pos2.setY(-pos2.y());
            };
            pos1+=pos3;
            pos2+=pos3;
			//printf("max p3 %d,%d p1 %d,%d, p2 %d,%d\n",pos3.x(),pos3.y(),pos1.x(),pos1.y(),pos2.x(),pos2.y());
            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 cellrefArray::minimumSelect(QPoint *pos) {
 if (!select) return;
 minimum(pos);
}

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

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

void cellrefArray::saveSelect(QDataStream *stream){
  if (select){
	save(stream);
  }
}
void cellrefArray::save(QDataStream *stream){
	(*stream)<<(qint8)(9);
	(*stream)<<(qint32)(point.x());
	(*stream)<<(qint32)(point.y());
	QPoint pos;
        (*stream)<<((qint16)anz_x);
        (*stream)<<((qint16)anz_y);
 	pos=space_x*anz_x+point;
    	(*stream)<<(qint32)(pos.x());
	(*stream)<<(qint32)(pos.y());
    	pos=space_y*anz_y+point;
    	(*stream)<<(qint32)(pos.x());
	(*stream)<<(qint32)(pos.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 cellrefArray::saveSOURCE( source *o){
}

void cellrefArray::saveGDS(gds *g) {
    QPoint pos;
//SRef
    g->write->writeUInt16(4);
    g->write->writeUInt8(0x0B);
    g->write->writeUInt8(0);
    //(*g->streamPtr)<<(quint16) 4<<(quint8) 0x0B<<(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);
    }
    if (trans.angle!=0){
	//angle
	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);
    }
 //colrow
    g->write->writeUInt16(8);
    g->write->writeUInt8(0x13);
    g->write->writeUInt8(2);	
    g->write->writeInt16((qint16)anz_x);
    g->write->writeInt16((qint16)anz_y);
    //(*g->streamPtr)<<(quint16) 8<<(quint8) 0x13<<(quint8)2;  //COLROW
    //qint16 x=anz_x;
    //qint16 y=anz_y;
    //*g->streamPtr)<<x<<y;
    //xy
    g->write->writeUInt16(((3*2*4)+4));
    g->write->writeUInt8(0x10);
    g->write->writeUInt8(3);
    g->write->writeInt32((qint32)point.x());g->write->writeInt32(point.y());
    pos=space_x*anz_x+point;
    g->write->writeInt32((qint32)pos.x());g->write->writeInt32(pos.y());
    pos=space_y*anz_y+point;
    g->write->writeInt32((qint32)pos.x());g->write->writeInt32(pos.y());
    //(*g->streamPtr)<<(quint16) ((3*2*4)+4)<<(quint8) 0x10<<(quint8)3;  //XY
    //(*g->streamPtr)<<(qint32)(point.x())<<(qint32)(point.y());
    //pos=space_x*anz_x+point;
    //(*g->streamPtr)<<(qint32)(pos.x())<<(qint32)(pos.y());
    //pos=space_y*anz_y+point;
    //(*g->streamPtr)<<(qint32)(pos.x())<<(qint32)(pos.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 cellrefArray::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));
  d->writeEntry(70,s.setNum(anz_x));
  d->writeEntry(71,s.setNum(anz_y));
  d->writeEntry(44,s.setNum(space_x.x()*d->df->userunits));
  d->writeEntry(45,s.setNum(space_y.y()*d->df->userunits));
if ((space_y.x()!=0)||(space_x.y()!=0)) d->report.addItem("Non orthogonal spacings are not possible",2);

}

#ifdef USE_3d
void cellrefArray::saveDXF3d(dxf3d*d){
if (select||d->renderAll()){
	view3dRenderMode renderMode=d->renderMode;
	d->renderMode=view3dRenderAll;
	int x,y;
        for (x=0;x<anz_x;x++) {
            for (y=0;y<anz_y;y++) {
                QPoint pos=point+space_x*x+space_y*y;
		strans m=d->trans;
		d->trans.translate(pos.x(),pos.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 cellrefArray::saveSVG(svg *s){
 QPoint pos;
 int x_,y_;
 for (x_=0;x_<anz_x;x_++) {
  for (y_=0;y_<anz_y;y_++) {
  	pos=point+space_x*x_+space_y*y_;
	*(s->str)<<"<use xlink:href=\"#"<<cell_ref->cellName<<"\" ";
	*(s->str)<<"transform=\"";
	*(s->str)<<"translate(";
		s->savePos("",pos.x());
		s->savePos("",-pos.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){
		*(s->str)<<"scale(";
		s->saveNum("",trans.mag);
		*(s->str)<<") ";
		}
 if (trans.mirror_x){
	*(s->str)<<"scale(1,-1) ";
	}
	*(s->str)<<"\" />"<<s->endOfLine;
  }
}
/* *(s->str)<<"<rect ";
s->savePos("x",rect.left());
s->savePos("y",-rect.top());
s->savePos("width",rect.right()-rect.left());
s->savePos("height",rect.top()-rect.bottom());
s->saveValue("fill",layers::num[layerNum].pen.color().name());
*(s->str)<<"/>\r\n";*/
//if (trans.mirror_x) s->error->addItem("Mirrored cellref can not be save in svg.",2);
s->error->addItem("Cellrefarrays saved as cellrefs",4);
s->error->addItem("Hierarchical design can not be display by some svg viewers.",4);
}

void cellrefArray::saveOASIS( oasis *o){
  if (!o->modal.absoluteMode){o->setModalAbsoluteMode();}
  qint8 info_byte=(qint8)(128);  //explicid cellname,repition;
  if ((anz_x>1)||(anz_y>1))  info_byte+=8;
  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);}
  if  (info_byte&8){
  	if ((anz_x==1)&&(space_y.x()==0)&&(space_y.y()>0)) {
		o->writeUnsignedInteger((uint)3);
		o->modal.y_dimension=anz_y;
		o->writeUnsignedInteger((uint)(anz_y-2));
		o->modal.y_space=space_y.y();
		o->writeUnsignedInteger((uint)space_y.y());}
	else if (anz_x==1) {
		o->writeUnsignedInteger((uint)9);
		o->writeUnsignedInteger((uint)(anz_y-2));
		o->writeGDelta(space_y);
		}
	else if ((anz_y==1)&&(space_x.y()==0)&&(space_x.x()>0)){
		o->writeUnsignedInteger((uint)2);
  		o->modal.x_dimension=anz_x;
		o->writeUnsignedInteger((uint)(anz_x-2));
		o->modal.x_space=space_x.x();
		o->writeUnsignedInteger((uint)space_x.x());}
	else if (anz_y==1) {
		o->writeUnsignedInteger((uint)9);
		o->writeUnsignedInteger((uint)(anz_x-2));
		o->writeGDelta(space_x);
		}
	else if ((space_y.x()==0)&&(space_x.y()==0)&&(space_y.y()>0)&&(space_x.x()>0)){
  		o->writeUnsignedInteger((uint)1);
  		o->modal.x_dimension=anz_x;
		o->modal.y_dimension=anz_y;
		o->writeUnsignedInteger((uint)(anz_x-2));
		o->writeUnsignedInteger((uint)(anz_y-2));
		o->modal.x_space=space_x.x();
		o->modal.y_space=space_y.y();
		o->writeUnsignedInteger((uint)(space_x.x()));
		o->writeUnsignedInteger((uint)(space_y.y()));
	  }
	else {
		o->writeUnsignedInteger((uint)8);
		o->modal.x_dimension=anz_x;
		o->modal.y_dimension=anz_y;
		o->writeUnsignedInteger((uint)(anz_x-2));
		o->writeUnsignedInteger((uint)(anz_y-2));
		o->writeGDelta(space_x);
		o->writeGDelta(space_y);
	}
	}   
  saveOASISProperty(o);
}

void cellrefArray::saveCIF( cif *c){
  if (trans.mag!=1.0) {
    QString smag;
    smag.setNum(trans.mag);
    c->reportSave->addItem("cellref magnification is ignored",2,smag);
  }
 QPoint pos;
 int x_,y_;
 for (x_=0;x_<anz_x;x_++) {
  for (y_=0;y_<anz_y;y_++) {
  pos=point+space_x*x_+space_y*y_;
  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(pos.x())+" ";
  s+=s1.setNum(pos.y())+" ";
  s=s.trimmed();
  c->writeEntry(s);
  }}
}

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

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

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

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

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

void cellrefArray::resize(double size) {
    point*=size;
    space_x*=size;
    space_y*=size;
}

elementList* cellrefArray::flatSelect() {
    elementList *b,*a=NULL;
    element *c=NULL;
    cellref *cellr;
    if (!select)
        return NULL;
    for (int x=0;x<anz_x;x++) {
            for (int y=0;y<anz_y;y++) {
                cellr=new cellref(cell_ref,point+space_x*x+space_y*y);
                c=cellr;
		c->select=true;
                //pos=point+space_x*x+space_y*y;
		cellr->trans=trans;
                b=new elementList();
                b->thisElement=c;
                b->nextElement=a;
                c=NULL;
                a=b;
            }
        }
    return a;
}

void cellrefArray::map(strans m) {
   trans*=m;
   point=m.matrix.map(point);
   bool map=false;
   	if (m.mirror_x) {
		space_x.setY(-space_x.y());
		space_y.setY(-space_y.y());
		map=true;
	}
   	if (m.angle!=0){
			QMatrix ma=QMatrix(1,0,0,1,0,0);
			ma.rotate(-m.angle);
			space_x=ma.map(space_x);
			space_y=ma.map(space_y);
			map=true;
		}
	if (m.mag!=1.0){
			QMatrix ma=QMatrix(m.mag,0,0,m.mag,0,0);
			space_x=ma.map(space_x);
			space_y=ma.map(space_y);
			}
if (map) clean();
}

void cellrefArray::mapSelect(strans m) {
    if (select) {
		map(m);
 /*       	trans*=m;
  		point=m.matrix.map(point);
		if (m.mirror_x) {
   			space_x.setY(-space_x.y());
			space_y.setY(-space_y.y());
			}
		if (m.angle!=0){
			QMatrix ma=QMatrix(1,0,0,1,0,0);
			ma.rotate(-m.angle);
			space_x=ma.map(space_x);
			space_y=ma.map(space_y);
		}
    }*/
	/*	trans*=m;
		point=m.matrix.map(point);
		if (!rot) {
			QMatrix ma=QMatrix(m.matrix.m11(),m.matrix.m21(), m.matrix.m12(),m.matrix.m22(),0,0);
			space_x=ma.map(space_x);
			space_y=ma.map(space_y);}
		else {
		if (m.mirror_x) {
			space_x.setY(-space_x.y());
			space_y.setY(-space_y.y());
			}
		if (m.angle!=0){
			QMatrix ma=QMatrix(1,0,0,1,0,0);
			ma.rotate(-m.angle);
			space_x=ma.map(space_x);
			space_y=ma.map(space_y);
			}
		if (m.mag!=1.0){
			QMatrix ma=QMatrix(m.mag,0,0,m.mag,0,0);
			space_x=ma.map(space_x);
			space_y=ma.map(space_y);
			}*/
			//}
	
	}
}

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

double cellrefArray::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);
	double dis=1e99;
    {
    for (int x=0;x<anz_x;x++) {
        for (int y=0;y<anz_y;y++) {
            QPoint pos=point+space_x*x+space_y*y;
			p2=p1+pos;
			double d=distance(p,p2);
			if (d<dis) {
				dis=d;
				}		
	}}
 }
 return dis;

}
double cellrefArray::nearestDistancePoint(const QPoint p, QPoint *p_)const{
		QPoint p1,p2;
	uint i;
	cell_ref->paintInfoGet(&p1,&p2,&i);
	p1=(p1+p2)/2;
	p1=trans.mapIn(p1);
	double dis=1e99;
    {
    for (int x=0;x<anz_x;x++) {
        for (int y=0;y<anz_y;y++) {
            QPoint pos=point+space_x*x+space_y*y;
			p2=p1+pos;
			double d=distance(p,p2);
			if (d<dis) {
				dis=d;
				*p_=p2;
				}		
	}}
}
//double d=distance(point,p);
//if (d<dis) return d;
 return dis;
}

double cellrefArray::nearestDistance(const QPoint p,QPoint *p_)const {
double dis=1e99;
QPoint pr;
  {
    for (int x=0;x<anz_x;x++) {
        for (int y=0;y<anz_y;y++) {
            QPoint pos=point+space_x*x+space_y*y;
	    QPoint p1=trans.mapOut(p-pos);
	    QPoint p3=trans.mapOut(*p_-pos);
	    //elementList *e=
	    cell_ref->nearestPointVirtual(p1,&p3);
	    *p_=trans.mapIn(p3)+pos;
	    double d=distance(p,*p_);
	    if (d<dis) {
		dis=d;
		pr=*p_;
		}
	}}
	}
 *p_=pr;
 return dis;
}

double cellrefArray::nearestLine(QPoint p,QPoint *p_,int radius) {
double dis=1e99;
QPoint pr;
    for (int x=0;x<anz_x;x++) {
        for (int y=0;y<anz_y;y++) {
		QPoint pos=point+space_x*x+space_y*y;
		QPoint p1=trans.mapOut(p-pos);
		QPoint p3=cell_ref->nearestLine(p1,(int)(1.0/trans.mag*radius));
		*p_=trans.mapIn(p3)+pos;
		double d=distance(p,*p_);
		if (d<dis) {
			dis=d;
			pr=*p_;
			}
	}}
 *p_=pr;
return  dis;
}	

double cellrefArray::nearestMiddle(QPoint p,QPoint *p_,int radius) {
double dis=1e99;
QPoint pr;
    for (int x=0;x<anz_x;x++) {
        for (int y=0;y<anz_y;y++) {
		QPoint pos=point+space_x*x+space_y*y;
		QPoint p1=trans.mapOut(p-pos);
		QPoint p3=cell_ref->nearestMiddleLine(p1,(int)(1.0/trans.mag*radius));
		*p_=trans.mapIn(p3)+pos;
		double d=distance(p,*p_);
		if (d<dis) {
			dis=d;
			pr=*p_;
			}
	}}
 *p_=pr;
return  dis;
}

double cellrefArray::nearestCenter(QPoint p,QPoint *p_,int radius) {
double dis=1e99;
QPoint pr;
    for (int x=0;x<anz_x;x++) {
        for (int y=0;y<anz_y;y++) {
		QPoint pos=point+space_x*x+space_y*y;
		QPoint p1=trans.mapOut(p-pos);
		QPoint p3=cell_ref->nearestCenter(p1,(int)(1.0/trans.mag*radius));
		*p_=trans.mapIn(p3)+pos;
		double d=distance(p,*p_);
		if (d<dis) {
			dis=d;
			pr=*p_;
			}
	}}
 *p_=pr;
return  dis;
}

bool cellrefArray::showProperties(elementList *el, drawingField *d,bool  ) {
    cellrefarrayproperties b(d);
    b.setElement(el->thisElement->getCellrefArray());
    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 :
    	{
	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;
	}
    }
    return false;
}
bool cellrefArray::identicalStructure(element *e){
if (e->isCellrefArray()) {
	cellrefArray *b=reinterpret_cast<cellrefArray(*)>(e);
	if ((*b)%(*this)) return true;
	}
return false;
}

bool operator% (const cellrefArray &b1,const cellrefArray &b2){
if (b1.cell_ref!=b2.cell_ref) return false;
if (!(b1.trans==b2.trans)) return false;
if (b1.anz_x!=b2.anz_x) return false;
if (b1.anz_y!=b2.anz_y) return false;
if (b1.space_x!=b2.space_x) return false;
if (b1.space_y!=b2.space_y) return false;
return true;
}

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

void  cellrefArray::findEdge(QPoint p1, QPoint p2,int layer,char dir,int *result){
if ((int)(trans.angle)%90!=0) return;
//if ((int)(trans.mag)!=1) return;
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;
for (int x=0;x<anz_x;x++) {
        for (int y=0;y<anz_y;y++) {
            QPoint pos=point+space_x*x+space_y*y;
			QPoint p3=trans.mapOut(p1-pos);
			QPoint p4=trans.mapOut(p2-pos);

			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))+pos;
			else p3=trans.mapIn(QPoint(0,r))+pos;
			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 cellrefArray::lineDistanceLayer(QPoint p1,QPoint p2, int *left,int *right,int layer, QPoint , QPoint ){
 
for (int x=0;x<anz_x;x++) {
        for (int y=0;y<anz_y;y++) {
            QPoint pos=point+space_x*x+space_y*y;
		QPoint p3=trans.mapOut(p1-pos);
		QPoint p4=trans.mapOut(p2-pos);
		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 cellrefArray::pointOnLayer(QPoint p,int layer){
 
for (int x=0;x<anz_x;x++) {
        for (int y=0;y<anz_y;y++) {
            	QPoint pos=point+space_x*x+space_y*y;
		QPoint p3=trans.mapOut(p-pos);
		if (cell_ref->pointOnLayer(p,layer)) return true;
	}
	}
return false;
}

bool operator== (const cellrefArray &b1,const cellrefArray &b2){
if (b1.point!=b2.point) return false;
if (b1.cell_ref!=b2.cell_ref) return false;
if (!(b1.trans==b2.trans)) return false;
if (b1.anz_x!=b2.anz_x) return false;
if (b1.anz_y!=b2.anz_y) return false;
if (b1.space_x!=b2.space_x) return false;
if (b1.space_y!=b2.space_y) return false;
return true;
}

