void trend::TrendBase::wirem(int4b* pdata, unsigned psize, WireWidth width, const SGBitSet* psel) { // first check whether to draw only the center line DBbox wsquare = DBbox(TP(0,0),TP(width,width)); bool center_line_only = !wsquare.visible(topCTM() * scrCTM(), visualLimit()); _clayer->wire(pdata, psize, width, center_line_only,psel,*_rmm); }
/*! Build a new quadTree structure for the tdtdata in the inlist. The method is using the existing _overlap variable. For every layout shape fitinsubtree() method is called in a try to put the data in the child quadTree. At the end the method is called for every of the child structures. */ void laydata::quadTree::sort(dataList& inlist) { // if the input list is empty - nothing to do! if (0 == inlist.size()) return; dataList::iterator DI = inlist.begin(); // if the list contains only one component - link it and run away if (1 == inlist.size()) { DI->first->nextis(NULL); _first = DI->first; return; } byte i; // the overlapping box of the currnet shape // DBbox shovl(TP(0,0)); DBbox shovl = DEFAULT_OVL_BOX; // the maximum possible overlapping boxes of the 4 children DBbox maxsubbox[4] = {DEFAULT_OVL_BOX, DEFAULT_OVL_BOX, DEFAULT_OVL_BOX, DEFAULT_OVL_BOX}; for (i = 0; i < 4; i++) maxsubbox[i] = _overlap.getcorner(i); // the sub-lists data will be sorted in dataList sublist[4]; // which is the child where current shape fits int fitinsubbox; // initialize the iterator float sharea, totalarea = _overlap.area(); while (inlist.end() != DI) { // get the overlap of the current shape shovl = DI->first->overlap();shovl.normalize(); sharea = shovl.area(); // Check it fits in some of the children if (totalarea <= 4 * sharea || (-1 == (fitinsubbox = fitsubtree(shovl, maxsubbox)))) { // no fit. The shape is sorted in the current tree DI->first->nextis(_first); _first = DI->first; } else { // fits in sub-tree fitinsubbox sublist[fitinsubbox].push_back(*DI); // check this child already exists if (_quads[fitinsubbox]) // yes ? _quads[fitinsubbox]->_overlap.overlap(shovl); else { // create the child, initialize the overlapping box _quads[fitinsubbox] = DEBUG_NEW quadTree(); _quads[fitinsubbox]->_overlap = shovl; } } // in all cases get rid of the current shape pointer. It is already sorted DI = inlist.erase(DI); } // at this point inlist MUST be empty - split over max 4+this quadTrees // now go and sort the children - if any for(i = 0; i < 4; i++) if (_quads[i]) _quads[i]->sort(sublist[i]); }
void trend::TrendBase::grcwire (int4b* pdata, unsigned psize, WireWidth width) { // first check whether to draw only the center line DBbox wsquare = DBbox(TP(0,0),TP(width,width)); bool center_line_only = !wsquare.visible(topCTM() * scrCTM(), visualLimit()); _grcLayer->wire(pdata, psize, width, center_line_only); }
/*! Checks whether a single layout object shape will fit into one of the childrens quadTree. It calls add() and returns success if the new layout object fits entirely into one of the possible subtrees or if it blows up its overlaping area not more than 10%. Returns false if the shape does not fit anywhere - means it should be placed higher into the quadTree structure.\n The method might be called recursively via the add() method. */ bool laydata::quadTree::fitintree(tdtdata* shape) { DBbox shovl = shape->overlap(); float clipedarea[4]; // check the clipping to see in witch region to place the shape for (byte i = 0; i < 4 ; i++) { DBbox subbox = _overlap.getcorner(i); clipedarea[i] = subbox.cliparea(shovl,true); if (-1 == clipedarea[i]) {//entirely inside the area if (!_quads[i]) _quads[i] = DEBUG_NEW quadTree(); _quads[i]->add(shape); return true; } } // if we got to this point - means that the shape does not fit // entirely inside neither of the four sub-areas. // It is a decision time then byte candidate = biggest(clipedarea); // now calculate the eventual new overlaping box DBbox newovl = _overlap.getcorner(candidate); newovl.overlap(shovl); // if the max area of the candidate does not blow more than 10% - // then seems to be OK to get it if (newovl.area() < 1.1 * (_overlap.area() / 4)) { if (!_quads[candidate]) _quads[candidate] = DEBUG_NEW quadTree(); _quads[candidate]->add(shape); return true; } return false; // shape can not be fit into any subtree }
void trend::TrendBase::wiret(const PointVector& pdata, WireWidth width) { // first check whether to draw only the center line DBbox wsquare = DBbox(TP(0,0),TP(width,width)); bool center_line_only = !wsquare.visible(topCTM() * scrCTM(), visualLimit()); _clayer->wire(pdata, width, center_line_only, *_rmm); }
/*!*/ laydata::tdtdata* laydata::quadTree::merge_selected(tdtdata*& shapeRef) { laydata::tdtdata* mergeres = NULL; DBbox overlapRef = shapeRef->overlap(); // check the entire holder for clipping... if (overlapRef.cliparea(_overlap) == 0) return NULL; // now start traversing the shapes in the current horlder one by one tdtdata* wdt = _first; while(wdt) { // for fully selected shapes if they overlap with the reference // and this is not the same shape as the reference if ((wdt != shapeRef) && ((sh_selected == wdt->status()) || (sh_merged == wdt->status())) && (overlapRef.cliparea(wdt->overlap()) != 0)) { // go and merge it mergeres = polymerge(wdt->shape2poly(), shapeRef->shape2poly()); if (NULL != mergeres) { // If the merge produce a result - return the result and // substitute the shapeRef with its merged counterpart shapeRef = wdt; return mergeres; } } wdt = wdt->next(); } // if we've got to this point - means that no more shapes to merge // in this area for(byte i = 0; i < 4; i++) if (_quads[i]) { mergeres = _quads[i]->merge_selected(shapeRef); if (NULL != mergeres) return mergeres; } //at this point there is nothing more to traverse, so return NULL return NULL; }
/*! Add a single layout object shape into the quadTree. It first checks whether or not another layout object is already placed into this quadTree. If not it simply links the shape and exits. If another object is already here, then the new overlap area is calculated. \n In case the new area is the same as the existing one, then the object might be (possibly) fited into one of the childrens quadTree. To check this fitintree() method is called. If this is unsuccessfull, just then the layout object is linked to this quadTree. \n If the new overlapping area is bigger that the existing one, then the layout object is linked to the current quadTree after what the current quadTree as well as its successors has to be rebuild using resort().\n The method might be called recursively via fitintree() method. */ void laydata::quadTree::add(tdtdata* shape) { DBbox shovl = shape->overlap();shovl.normalize(); if (empty()) { // first shape in the container _overlap = shovl; _first = shape;shape->nextis(NULL); } else { // save the old overlap DBbox oldovl = _overlap; // calculate the new container overlap _overlap.overlap(shovl); float areaold = oldovl.area(); float areanew = _overlap.area(); // The equation below produce problems with severe consequences. // It seems to be because of the type of the conversion // if (oldovl.area() == _overlap->area()) { if (areaold == areanew) { // if the overlapping box hasn't changed, // try to fit the shape into subtree if ((areanew <= 4 * shovl.area()) || !fitintree(shape)) { // shape doesn't fit into the subtree, so place it here shape->nextis(_first); _first = shape; } } else { // the overlapping box has had blown-up shape->nextis(_first); _first = shape; resort(); // re-sort the entire tree } } }
void trend::TrendBase::genRulerMarks(const CTM& LayCTM, DBline& long_mark, DBline& short_mark, DBline& text_bp, double& scaledpix) { // Side ticks (segments) of the rulers has to be with constant size. The next // lines are generating a segment with the size 7/3 screen pixels centred in // the {0,0} point of the canvas (logical coordinates) // The coefficients 1e3/1e-3 are picked arbitrary in an attempt to reduce the // error const double ico = 1e3; const double dco = 1/ico; DBline tick_sample = DBline(TP(0,0),TP(0,7,ico)) * LayCTM; double tick_size = ((double)(tick_sample.p2().y()-tick_sample.p1().y())); long_mark = DBline(TP(0,-tick_size, dco),TP(0,tick_size, dco)); tick_sample = DBline(TP(0,0),TP(0,3,ico)) * LayCTM; tick_size = ((double)(tick_sample.p2().y()-tick_sample.p1().y())); short_mark = DBline(TP(0,-tick_size, dco),TP(0,tick_size, dco)); tick_sample = DBline(TP(0,0),TP(0,20,ico)) * LayCTM; tick_size = ((double)(tick_sample.p1().y()-tick_sample.p2().y())); text_bp = DBline(TP(0,0),TP(0,tick_size, dco)); // now prepare to draw the size DBbox pixelbox = DBbox(TP(),TP(15,15)) * LayCTM; scaledpix = ((double)(pixelbox.p2().x()-pixelbox.p1().x())); }
void layprop::SupplementaryData::getConsts(const CTM& LayCTM, DBline& long_mark, DBline& short_mark, DBline& text_bp, double& scaledpix) { // Side ticks (segments) of the rulers has to be with constant size. The next lines // are generating a segment with the size 7/3 screen pixels centered in // the {0,0} point of the canvas (logical coords) // the coeffitients 1e3/1e-3 are picked ramdomly attempting to reduce the // error const double ico = 1e3; const double dco = 1/ico; DBline tick_sample = DBline(TP(0,0),TP(0,7,ico)) * LayCTM; double tick_size = ((double)(tick_sample.p2().y()-tick_sample.p1().y())); long_mark = DBline(TP(0,-tick_size, dco),TP(0,tick_size, dco)); tick_sample = DBline(TP(0,0),TP(0,3,ico)) * LayCTM; tick_size = ((double)(tick_sample.p2().y()-tick_sample.p1().y())); short_mark = DBline(TP(0,-tick_size, dco),TP(0,tick_size, dco)); tick_sample = DBline(TP(0,0),TP(0,20,ico)) * LayCTM; tick_size = ((double)(tick_sample.p1().y()-tick_sample.p2().y())); text_bp = DBline(TP(0,0),TP(0,tick_size, dco)); // now prepare to draw the size DBbox pixelbox = DBbox(TP(),TP(15,15)) * LayCTM; scaledpix = ((double)(pixelbox.p2().x()-pixelbox.p1().x())); }
/*! A temporary Draw (during move/copy operations) of the container contents on the screen using the virtual quadTree::tmp_draw() method of the parent object. */ void laydata::tdtlayer::motion_draw(const layprop::DrawProperties& drawprop, ctmqueue& transtack) const { // check the entire layer for clipping... DBbox clip = drawprop.clipRegion(); if (empty()) return; DBbox areal = overlap().overlap(transtack.front()); if ( clip.cliparea(areal) == 0 ) return; else if (!areal.visible(drawprop.ScrCTM())) return; quadTree::motion_draw(drawprop, transtack); }
/*! Removes marked shapes from the quadtree without deleting them. The removed shapes are still listed in the _shapesel container of the current cell. The new overlapping box is calculated during this process and the method returns true to notify its parent that the overlapping box has changed and resort has to be initiated on the upper levels of the tree. The tree is processed bottom-up, i.e. the method is recursively called first for child quadTree structures.\n On the top level the method is called by two tdtcell methods: delete_selected and move selected. The difference is that for delete, partially selected shapes are ignored and not processed.\n Fully selected shapes are always marked as sh_deleted. When move operation is going on they will be re-marked afterwards to sh_selected by the move(copy) virtual methods of tdtdata. */ bool laydata::quadTree::delete_marked(SH_STATUS stat, bool partselect) { assert(!((stat != sh_selected) && (partselect == true))); // Create and initialize a variable "to be sorted" bool _2B_sorted = false; // save the old overlap, and initialize the new one DBbox oldovl = _overlap; _overlap = DEFAULT_OVL_BOX; // deleteing sequence is bottom-up, so start from the children for (byte i = 0; i < 4; i++) if (_quads[i]) { _2B_sorted |= _quads[i]->delete_marked(stat, partselect); // check that there is still something left in the child quadTree if (_quads[i]->empty()) { delete _quads[i]; _quads[i] = NULL; } else update_overlap(_quads[i]->overlap()); } // prepare a pair of pointers to tdtdata tdtdata* wds = _first; tdtdata* wdsP = NULL; // loop all tdtdata in the current tree and check they are selected while (wds) // if selected ... if ((stat == wds->status()) || (partselect && (sh_partsel == wds->status()))) { // mark the fully selected shapes as deleted if (stat == wds->status()) wds->set_status(sh_deleted); // Unlink the marked shape from the list if (wdsP) { // if this is not the first shape wdsP->nextis(wds->next()); wds->nextis(NULL); wds = wdsP->next(); } else { // Special attention when this is the first shape _first = wds->next(); wds->nextis(NULL); wds = _first; } } // If not selected, or partially selected but partselect == false, // update the overlapping box, and move further else { update_overlap(wds->overlap()); wdsP = wds; wds = wds->next(); } // If _overlap is still NULL here -> means the placeholder is empty. Will // be deleted by the parent if (empty()) _invalid = true; else { //Now if the overlapping rectangles differ, then invalidate //the current quadTree float areaold = oldovl.area(); float areanew = _overlap.area(); if (areaold != areanew) _invalid = true; } return _2B_sorted |= _invalid; }
short laydata::quadTree::clip_type(tenderer::TopRend& rend) const { if (empty()) return 0; // check the entire holder for clipping... DBbox clip = rend.clipRegion(); DBbox areal = _overlap.overlap(rend.topCTM()); float clip_area = clip.cliparea(areal); if ( ( 0.0 == clip_area ) || (!areal.visible(rend.ScrCTM())) ) return 0; if (0.0 < clip_area) return 1; else return -1; }
int tellstdfunc::stdGETOVERLAP::execute() { telldata::TtLayout* layObject = static_cast<telldata::TtLayout*>(OPstack.top());OPstack.pop(); assert(layObject); real DBscale = PROPC->DBscale(); DBbox ovlBox = layObject->data()->overlap(); telldata::TtPnt p1DB(ovlBox.p1().x()/DBscale, ovlBox.p1().y()/DBscale ); telldata::TtPnt p2DB(ovlBox.p2().x()/DBscale, ovlBox.p2().y()/DBscale); OPstack.push(DEBUG_NEW telldata::TtBox( p1DB, p2DB )); delete layObject; return EXEC_NEXT; }
bool laydata::DrawIterator<DataT>::secureNonEmptyDown() { assert(_drawprop); DBbox clip = _drawprop->clipRegion(); DBbox areal = Iterator<DataT>::_cQuad->_overlap.overlap(_ctm); if (0ll == clip.cliparea(areal) ) return false; else if (!areal.visible(_drawprop->scrCtm(), _drawprop->visualLimit())) return false; while (0 == Iterator<DataT>::_cQuad->_props._numObjects) { return this->nextSubQuad(0,Iterator<DataT>::_cQuad->_props.numSubQuads()); } Iterator<DataT>::_cData = 0; return true; }
/*! A temporary Draw (during move/copy operations) of the container contents on the screen using the virtual quadTree::tmp_draw() method of the parent object. */ void laydata::tdtlayer::tmp_draw(const layprop::DrawProperties& drawprop, ctmqueue& transtack) const { // check the entire layer for clipping... DBbox clip = drawprop.clipRegion(); if (empty()) return; DBbox areal = overlap() * transtack.front(); areal.normalize(); if (clip.cliparea(areal) == 0) return; else { areal = areal * drawprop.ScrCTM(); if (areal.area() < MIN_VISUAL_AREA) return; } quadTree::tmp_draw(drawprop, transtack); }
void trend::TrendBase::pushCell(std::string cname, const CTM& trans, const DBbox& overlap, bool active, bool selected) { TrxCellRef* cRefBox = DEBUG_NEW TrxCellRef(cname, trans * _cellStack.top()->ctm(), overlap, _cellStack.size() ); if (selected || (!_drawprop->cellBoxHidden())) _refLayer->addCellOBox(cRefBox, _cellStack.size(), selected); else // This list is to keep track of the hidden cRefBox - so we can clean // them up. Don't get confused - we need cRefBox during the collecting // and drawing phase so we can't really delete them here or after they're // poped-up from _cellStack. The confusion is coming from the "duality" // of the TrxCellRef - once as a cell reference with CTM, view depth etc. // and then as a placeholder of the overlapping reference box _hiddenRefBoxes.push_back(cRefBox); _cellStack.push(cRefBox); if (active) { assert(NULL == _activeCS); _activeCS = cRefBox; } else if (!_drawprop->cellMarksHidden()) { _marks->addRefMark(overlap.p1(), _cellStack.top()->ctm()); } }
/*! Temporary draw of the container contents on the screen using the virtual tmp_draw methods of the tdtddata objects. This happens only if the current quadTree object is visible. Current clip region data is obtained from LayoutCanvas. In a sence this method is the same as openGL_draw without fill and not handling selected shapes*/ void laydata::quadTree::motion_draw(const layprop::DrawProperties& drawprop, ctmqueue& transtack) const { if (empty()) return; // check the entire holder for clipping... DBbox clip = drawprop.clipRegion(); DBbox areal = _overlap.overlap(transtack.front()); if (clip.cliparea(areal) == 0 ) return; else if (!areal.visible(drawprop.ScrCTM())) return; tdtdata* wdt = _first; while(wdt) { wdt->motion_draw(drawprop, transtack, NULL); wdt = wdt->next(); } for(byte i = 0; i < 4; i++) if (_quads[i]) _quads[i]->motion_draw(drawprop, transtack); }
//tui::CanvasStatus::CanvasStatus(){}; void tui::StatusLine::update(const int4b width, const CTM& _LayCTM) { _sb_BL = TP(0,0) * _LayCTM; _sb_TR = TP(width, 30) * _LayCTM; DBbox pixelbox = DBbox(TP(),TP(14,14)) * _LayCTM; _scaledpix = ((double)(pixelbox.p2().x()-pixelbox.p1().x())); _cY = TP(width-150, 17) * _LayCTM; _cX = TP(width-300, 17) * _LayCTM; _dY = TP(width-450, 17) * _LayCTM; _dX = TP(width-600, 17) * _LayCTM; _Ycoord = DBbox(TP(width - 130, 28), TP(width - 2, 2)) * _LayCTM; _Xcoord = DBbox(TP(width - 280, 28), TP(width - 162, 2)) * _LayCTM; _wcY = TP(width-120, 16) * _LayCTM; _wcX = TP(width-270, 16) * _LayCTM; }
void tui::LayoutCanvas::OnZoom(wxCommandEvent& evt) { DBbox* box = NULL; switch (evt.GetInt()) { case ZOOM_WINDOW : box = static_cast<DBbox*>(evt.GetClientData());break; case ZOOM_WINDOWM: box = DEBUG_NEW DBbox(presspoint.x(),presspoint.y(), ScrMARK.x(),ScrMARK.y());break; case ZOOM_IN : box = DEBUG_NEW DBbox( (3*lp_BL.x() + lp_TR.x())/4, //in (3*lp_BL.y() + lp_TR.y())/4, (3*lp_TR.x() + lp_BL.x())/4, (3*lp_TR.y() + lp_BL.y())/4); break; case ZOOM_OUT : box = DEBUG_NEW DBbox( (5*lp_BL.x() - lp_TR.x())/4, //out (5*lp_BL.y() - lp_TR.y())/4, (5*lp_TR.x() - lp_BL.x())/4, (5*lp_TR.y() - lp_BL.y())/4); break; case ZOOM_LEFT : box = DEBUG_NEW DBbox( ( lp_TR.x() + lp_BL.x())/2, //left lp_BL.y() , (3*lp_BL.x() - lp_TR.x())/2, lp_TR.y() ); break; case ZOOM_RIGHT : box = DEBUG_NEW DBbox( (3*lp_TR.x() - lp_BL.x())/2, // right lp_BL.y() , ( lp_TR.x() + lp_BL.x())/2, lp_TR.y() ); break; case ZOOM_UP : box = DEBUG_NEW DBbox( lp_BL.x() , // up (3*lp_BL.y() - lp_TR.y())/2, lp_TR.x() , ( lp_TR.y() + lp_BL.y())/2); break; case ZOOM_DOWN : box = DEBUG_NEW DBbox( lp_BL.x() , // down ( lp_TR.y() + lp_BL.y())/2, lp_TR.x() , (3*lp_TR.y() - lp_BL.y())/2); break; case ZOOM_EMPTY : box = DEBUG_NEW DBbox(-10,-10,90,90); break; case ZOOM_REFRESH: invalid_window = true; Refresh(); return; default: assert(false); } int Wcl, Hcl; GetClientSize(&Wcl,&Hcl); // To prevent a loss of precision in the following lines - don't use // integer variables (Wcl & Hcl) directly double W = Wcl; double H = Hcl; double w = abs(box->p1().x() - box->p2().x()); double h = abs(box->p1().y() - box->p2().y()); double sc = ((W/H < w/h) ? w/W : h/H); double tx = ((box->p1().x() + box->p2().x()) - W*sc) / 2; double ty = ((box->p1().y() + box->p2().y()) - H*sc) / 2; _LayCTM.setCTM( sc, 0.0, 0.0, sc, tx, ty); _LayCTM.FlipX((box->p1().y() + box->p2().y())/2); // flip Y coord towards the center DATC->setScrCTM(_LayCTM.Reversed()); delete box; invalid_window = true; Refresh(); }
/*!Cut with polygon is pretty expensive operation and despite the fact that it is executed over selected shapes only, there is no guarantee that the user will not do select_all() and then polycut(), and of course nobody can trust the user. So this method is trying to minimize the calculations by executing cutpoly only on the shapes that overlap somehow with the cutting polygon */ void laydata::quadTree::cutpoly_selected(pointlist& plst, DBbox& cut_overlap, shapeList** decure) { // check the entire holder for clipping... if (cut_overlap.cliparea(_overlap) == 0) return; // now start traversing the shapes in the current horlder one by one tdtdata* wdt = _first; while(wdt) { // for fully selected shpes if they overlap with the cutting polygon if ((sh_selected == wdt->status()) && (cut_overlap.cliparea(wdt->overlap()) != 0)) // go and clip it wdt->polycut(plst, decure); wdt = wdt->next(); } for(byte i = 0; i < 4; i++) if (_quads[i]) _quads[i]->cutpoly_selected(plst, cut_overlap, decure); }
/*! Temporary draw of the container contents on the screen using the virtual tmp_draw methods of the tdtddata objects. This happens only if the current quadTree object is visible. Current clip region data is obtained from LayoutCanvas. In a sence this method is the same as openGL_draw without fill and not handling selected shapes*/ void laydata::quadTree::tmp_draw(const layprop::DrawProperties& drawprop, ctmqueue& transtack) const { if (empty()) return; // check the entire holder for clipping... DBbox clip = drawprop.clipRegion(); DBbox areal = _overlap * transtack.front(); areal.normalize(); if (clip.cliparea(areal) == 0) return; else { areal = areal * drawprop.ScrCTM(); if (areal.area() < MIN_VISUAL_AREA) return; } tdtdata* wdt = _first; while(wdt) { wdt->tmp_draw(drawprop, transtack); wdt = wdt->next(); } for(byte i = 0; i < 4; i++) if (_quads[i]) _quads[i]->tmp_draw(drawprop, transtack); }
/*! Draw the contents of the container on the screen using the virtual openGL_draw methods of the tdtddata objects. This happens only if the current quadTree object is visible. Current clip region data is obtained from LayoutCanvas. Draws also the select marks in case shape is selected. \n This is the cherry of the quadTree algorithm cake*/ void laydata::quadTree::openGL_draw(ctmstack& transtack, const layprop::DrawProperties& drawprop, const dataList* slst) const { if (empty()) return; // check the entire holder for clipping... DBbox clip = drawprop.clipRegion(); DBbox areal = _overlap * transtack.top(); areal.normalize(); if (clip.cliparea(areal) == 0) return; else { areal = areal * drawprop.ScrCTM(); if (areal.area() < MIN_VISUAL_AREA) return; // std::cout << " ... with area " << areal.area() << "\n"; } tdtdata* wdt = _first; // The drawing will be faster like this for the cells without selected shapes // that will be the wast majority of the cases. A bit bigger code though. // Seems the bargain is worth it. if (slst) while(wdt) { wdt->openGL_draw(transtack,drawprop); // in case the shape is somehow selected... if (sh_selected == wdt->status()) wdt->draw_select(transtack.top()); else if (sh_partsel == wdt->status()) { dataList::const_iterator SI; for (SI = slst->begin(); SI != slst->end(); SI++) if (SI->first == wdt) break; assert(SI != slst->end()); wdt->draw_select(transtack.top(), SI->second); } wdt = wdt->next(); } else // if there are no selected shapes while(wdt) { wdt->openGL_draw(transtack,drawprop); wdt = wdt->next(); } for(byte i = 0; i < 4; i++) if (_quads[i]) _quads[i]->openGL_draw(transtack, drawprop, slst); }
/*! Perform the data selection using select_in box. Called by the corresponding select methods of the parent structures in the data base - tdtlayer and tdtcell */ void laydata::quadTree::select_inBox(DBbox& select_in, dataList* selist, bool pselect) { // check the entire holder for clipping... if (select_in.cliparea(_overlap) == 0) return; // now start selecting one by one tdtdata* wdt = _first; while(wdt) { wdt->select_inBox(select_in, selist, pselect); wdt = wdt->next(); } for(byte i = 0; i < 4; i++) if (_quads[i]) _quads[i]->select_inBox(select_in, selist, pselect); }
void trend::TrendBase::text (const std::string* txt, const CTM& ftmtrx, const DBbox& ovl, const TP& cor, bool sel) { if (sel) _clayer->text(txt, ftmtrx, &ovl, cor, true); else if (_drawprop->textBoxHidden()) _clayer->text(txt, ftmtrx, NULL, cor, false); else _clayer->text(txt, ftmtrx, &ovl, cor, false); if (!_drawprop->textMarksHidden()) { _marks->addTextMark(ovl.p1(),ftmtrx*_cellStack.top()->ctm()); } }
/*! Checks whether a single layout object shape will fit into one of the childrens quadTree. Returns the index of the child quadTree which fits the shape or -1 otherwise. */ int laydata::quadTree::fitsubtree(DBbox shovl, DBbox* maxsubbox ) { float clipedarea[4]; // check the clipping to see in witch region to place the shape for (byte i = 0; i < 4 ; i++) { clipedarea[i] = maxsubbox[i].cliparea(shovl,true); if (-1 == clipedarea[i]) {//entirely inside the area return i; } } // if we got to this point - means that the shape does not fit // entirely inside neither of the four sub-areas. // It is a decision time then byte candidate = biggest(clipedarea); // now calculate the eventual new overlaping box DBbox newovl = maxsubbox[candidate]; newovl.overlap(shovl); // if the max area of the candidate does not blow more than 10% - // then seems to be OK to get it if (newovl.area() < 1.1 * (_overlap.area() / 4)) { return candidate; } return -1; // shape can not be fit into any subtree }
void trend::TrendBase::arefOBox(std::string cname, const CTM& trans, const DBbox& overlap, bool selected) { if (!_drawprop->cellMarksHidden()) { _marks->addARefMark(overlap.p1(), trans * _cellStack.top()->ctm()); } if (selected || (!_drawprop->cellBoxHidden())) { TrxCellRef* cRefBox = DEBUG_NEW TrxCellRef(cname, trans * _cellStack.top()->ctm(), overlap, _cellStack.size() ); _refLayer->addCellOBox(cRefBox, _cellStack.size(), selected); } }
/*! Unselects already selected data using unselect_in box. Called by the corresponding unselect methods of the parent structures in the data base - tdtlayer and tdtcell */ void laydata::quadTree::unselect_inBox(DBbox& unselect_in, dataList* unselist, bool pselect) { // check the entire holder for clipping... if (unselect_in.cliparea(_overlap) == 0) return; tdtdata* wdt = _first; while (wdt) { // now start unselecting from the list dataList::iterator DI = unselist->begin(); while ( DI != unselist->end() ) if ((wdt == DI->first) && (DI->first->unselect(unselect_in, *DI, pselect))) DI = unselist->erase(DI); else DI++; wdt = wdt->next(); } for(byte i = 0; i < 4; i++) if (_quads[i]) _quads[i]->unselect_inBox(unselect_in, unselist, pselect); }
void tui::LayoutCanvas::OnZoom(wxCommandEvent& evt) { DBbox* box = NULL; switch (evt.GetInt()) { case ZOOM_WINDOW : box = static_cast<DBbox*>(evt.GetClientData());break; case ZOOM_WINDOWM: box = new DBbox(presspoint.x(),presspoint.y(), ScrMARK.x(),ScrMARK.y());break; case ZOOM_IN : box = new DBbox((3*lp_BL.x() + lp_TR.x())/4, //in (3*lp_BL.y() + lp_TR.y())/4, (3*lp_TR.x() + lp_BL.x())/4, (3*lp_TR.y() + lp_BL.y())/4); break; case ZOOM_OUT : box = new DBbox((5*lp_BL.x() - lp_TR.x())/4, //out (5*lp_BL.y() - lp_TR.y())/4, (5*lp_TR.x() - lp_BL.x())/4, (5*lp_TR.y() - lp_BL.y())/4); break; case ZOOM_LEFT : box = new DBbox(( lp_TR.x() + lp_BL.x())/2, //left lp_BL.y() , (3*lp_BL.x() - lp_TR.x())/2, lp_TR.y() ); break; case ZOOM_RIGHT : box = new DBbox((3*lp_TR.x() - lp_BL.x())/2, // right lp_BL.y() , ( lp_TR.x() + lp_BL.x())/2, lp_TR.y() ); break; case ZOOM_UP : box = new DBbox( lp_BL.x() , // up (3*lp_BL.y() - lp_TR.y())/2, lp_TR.x() , ( lp_TR.y() + lp_BL.y())/2); break; case ZOOM_DOWN : box = new DBbox( lp_BL.x() , // down ( lp_TR.y() + lp_BL.y())/2, lp_TR.x() , (3*lp_TR.y() - lp_BL.y())/2); break; case ZOOM_EMPTY : box = new DBbox(-10,-10,90,90); break; default: assert(false); } int W, H; GetClientSize(&W,&H); double w = abs(box->p1().x() - box->p2().x()); double h = abs(box->p1().y() - box->p2().y()); double sc = (W/H < w/h) ? w/W : h/H; double tx = ((box->p1().x() + box->p2().x()) - W*sc) / 2; double ty = ((box->p1().y() + box->p2().y()) - H*sc) / 2; _LayCTM.setCTM( sc, 0.0, 0.0, sc, tx, ty); _LayCTM.FlipX((box->p1().y() + box->p2().y())/2); // flip Y coord towards the center Properties->setScrCTM(_LayCTM.Reversed()); invalid_window = true; delete box; Refresh(); }
/*! Draw the contents of the container on the screen using the virtual openGL_draw methods of the tdtddata objects. This happens only if the current quadTree object is visible. Current clip region data is obtained from LayoutCanvas. Draws also the select marks in case shape is selected. \n This is the cherry of the quadTree algorithm cake*/ void laydata::quadTree::openGL_draw(layprop::DrawProperties& drawprop, const dataList* slst, bool fill, bool bound) const { if (empty()) return; // check the entire holder for clipping... DBbox clip = drawprop.clipRegion(); DBbox areal = _overlap * drawprop.topCTM(); areal.normalize(); if (clip.cliparea(areal) == 0) return; else { areal = areal * drawprop.ScrCTM(); if (areal.area() < MIN_VISUAL_AREA) return; // std::cout << " ... with area " << areal.area() << "\n"; } tdtdata* wdt = _first; // bool fill = drawprop.getCurrentFill(); // The drawing will be faster like this for the cells without selected shapes // that will be the wast majority of the cases. A bit bigger code though. // Seems the bargain is worth it. if (slst) { while(wdt) { pointlist points; // precalculate drawing data wdt->openGL_precalc(drawprop, points); if (0 != points.size()) { // draw the shape fill (contents of refs, arefs and texts) if (fill) wdt->openGL_drawfill(drawprop, points); // draw the outline of the shapes and overlapping boxes if (bound) wdt->openGL_drawline(drawprop, points); if ((sh_selected == wdt->status()) || (sh_partsel == wdt->status())) { drawprop.setLineProps(true); if (sh_selected == wdt->status()) wdt->openGL_drawsel(points, NULL); else if (sh_partsel == wdt->status()) { dataList::const_iterator SI; for (SI = slst->begin(); SI != slst->end(); SI++) if (SI->first == wdt) break; assert(SI != slst->end()); wdt->openGL_drawsel(points, SI->second); } drawprop.setLineProps(false); } wdt->openGL_postclean(drawprop, points); } wdt = wdt->next(); } } else { // if there are no selected shapes while(wdt) { pointlist points; // precalculate drawing data wdt->openGL_precalc(drawprop, points); // draw the shape fill (contents of refs, arefs and texts) if (fill) wdt->openGL_drawfill(drawprop, points); // draw the outline of the shapes and overlapping boxes if (bound) wdt->openGL_drawline(drawprop, points); // clean-up wdt->openGL_postclean(drawprop, points); wdt = wdt->next(); } } /* // The drawing will be faster like this for the cells without selected shapes // that will be the wast majority of the cases. A bit bigger code though. // Seems the bargain is worth it. if (slst) while(wdt) { wdt->openGL_draw(drawprop); // in case the shape is somehow selected... if (sh_selected == wdt->status()) wdt->draw_select(drawprop.topCTM()); else if (sh_partsel == wdt->status()) { dataList::const_iterator SI; for (SI = slst->begin(); SI != slst->end(); SI++) if (SI->first == wdt) break; assert(SI != slst->end()); wdt->draw_select(drawprop.topCTM(), SI->second); } wdt = wdt->next(); } else // if there are no selected shapes while(wdt) { wdt->openGL_draw(drawprop); wdt = wdt->next(); }*/ for(byte i = 0; i < 4; i++) if (_quads[i]) _quads[i]->openGL_draw(drawprop, slst, fill, bound); }