/*!*/ 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; }
/*! 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 }
/*!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); }
/*! 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); }
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; }
/*! 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); }
/*! 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); }
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; }
/*! 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); }
/*! 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); }
/*! 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); }
/*! 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); }