#ifndef DEMO_TAB_H #define DEMO_TAB_H /*! demo_tab.h contain the definetion and implementation of * the demo tab classes and the tabs traits classes. * all the possible shared code is in Qt_widget_demo_tab where * the differences is in the traits classes. */ #include #include #include #include #include #include #include #include "cgal_types.h" #include "seg_notif.h" #include "pol_notif.h" #include "conic_notif.h" #include #include #include #include #include /*! class Qt_widget_base_tab - inherits from CGAL::Qt_widget * contain all data members that are not part of the traits */ class Qt_widget_base_tab : public CGAL::Qt_widget { public: /*! */ Qt_widget_base_tab(TraitsType t , Strategy _straregy, QWidget *parent = 0, int tab_number = 1 ) : CGAL::Qt_widget( parent ), current_state(0), index(tab_number), snap_mode(NONE), mode(INSERT), m_line_width(2), m_vertex_width(3), first_time(true), active(false), traits_type(t), bbox(CGAL::Bbox_2(-10, -10, 10, 10)), wasrepainted(true), on_first(false), change_pm_color(false), snap(false), grid(false), conic_type(SEGMENT), cube_size(1), ray_shooting_direction(true), remove_org_curve(true), read_from_file(false), empty(true), first_time_merge(true), draw_vertex(true), fill_face_color(def_bg_color), strategy(_straregy) { static_cast(*this) << CGAL::LineWidth(2) << CGAL::BackgroundColor (CGAL::BLACK); set_window(0, 700, 0, 700); setMouseTracking(TRUE); colors[1] = Qt::blue; colors[2] = Qt::gray; colors[3] = Qt::green; colors[4] = Qt::cyan; colors[5] = Qt::magenta; colors[6] = Qt::darkRed; colors[7] = Qt::darkGreen; colors[8] = Qt::darkBlue; colors[9] = Qt::darkMagenta; colors[10] = Qt::darkCyan; colors[11] = Qt::yellow; pm_color = colors[index]; } /*! Destructor */ virtual ~Qt_widget_base_tab(){} /*! current_state - indecates when a tab state is changed */ int current_state; /*! index - each tab has a uniqe index */ int index; /*! pl_point - the point for point location */ Coord_point pl_point; /*! snap_mode - current snap mode (none, grid or closest point) */ SnapMode snap_mode; /*! mode - current mode (insert,delete or point location) */ Mode mode; /*! m_line_width - line width */ int m_line_width; /*! m_vertex_width - vertex width */ int m_vertex_width; /*! first_time - true when it is the first mouse click of the object */ bool first_time; /*! active - true if the first point was inserted */ bool active; /*! traits_type - the actual tab traits */ TraitsType traits_type; /*! bbox - bounding box */ CGAL::Bbox_2 bbox; /*! for use of drag mode */ int first_x, first_y; int x2, y2; bool wasrepainted; bool on_first; /*! array of colors */ QColor colors[20]; /*! planar map color */ QColor pm_color; /*! flag to know that pm color has changed */ bool change_pm_color; /*! snap flag */ bool snap; /*! grid flag */ bool grid; /*! conic insert type */ ConicType conic_type; /*! grid cube size */ int cube_size; /*! ray shooting direction */ bool ray_shooting_direction; // true for up /*! remove all original curve or only a part */ bool remove_org_curve; /*! pm read from file - need a spcial treatment */ bool read_from_file; /*! true if pm is empty */ bool empty; /*! true when it is the first time in merge mode */ bool first_time_merge; /*! true when you want to draw all vertex, false if * only the intersecting vertex */ bool draw_vertex; /*! the color for filling faces ( obtained by fill button) */ QColor fill_face_color; /*! point location strategy */ Strategy strategy; /*! get the color of the unbounded face (its the same as the background * color of the tab) */ QColor unbounded_face_color() { return this->backgroundColor(); } /*! set the colo of the unbounded face (its the same as the background * color of the tab) */ void set_unbounded_face_color(QColor c) { this->setBackgroundColor(c); } /*! increment current_state to inidicate that something has changed */ void something_changed(){ current_state++ ; } }; /*! check if two segemnts are mergeable */ template bool merge_segments_precondition(Pm_point_2 s, Pm_point_2 t, Pm_point_2 s1, Pm_point_2 t1 ,int s_degree , int t_degree) { return // cannot be the same curve as closest_curve (!((s1 == s && t1 == t) || (s1 == t && t1 == s)) && // must be one shared point (s1 == s || t1 == t || s1 == t || t1 == s) && (!(((s == s1 || s == t1) && s_degree != 2) || // vertex degree must be exactly 2 ((t == s1 || t == t1) && t_degree != 2))) && ((s == s1 && ((t.x() < s.x() && t1.x() > s.x()) || (t.x() > s.x() && t1.x() < s.x()))) || (s == t1 && ((t.x() < s.x() && s1.x() > s.x()) || (t.x() > s.x() && s1.x() < s.x()))) || (t == s1 && ((t.x() < s.x() && t1.x() < t.x()) || (t.x() > s.x() && t1.x() > t.x()))) || (t == t1 && ((t.x() < s.x() && s1.x() < t.x()) || // checking x-monotone (t.x() > s.x() && s1.x() > t.x()))) || // dealing with vertical curves ((s.x() == s1.x())&&( t.x() == t1.x()) && (s.x()==t.x())))); } /*! */ template QColor blend_colors(ColorsIterator begin_colors , ColorsIterator end_colors) { ColorsIterator clr_itr; int red = 0, green = 0, blue = 0, counter = 0; QColor avg_color = def_bg_color; // the average color for(clr_itr = begin_colors ; clr_itr!= end_colors ; ++clr_itr) { QColor curr_color = *clr_itr; if( curr_color.isValid() && curr_color != def_bg_color) { red += curr_color.red(); green += curr_color.green(); blue += curr_color.blue(); counter++; } } if( counter) // make sure counter is not equal zero avg_color = QColor(red / counter , green / counter , blue / counter); return avg_color ; } /*! template class Qt_widget_demo_tab gets a Tab_traits class as * a template parameter. all the Tab_traits classes must support * a set of demands. */ template class Qt_widget_demo_tab : public Qt_widget_base_tab { private: typedef typename Tab_traits::Curves_list Curves_list; typedef typename Tab_traits::Curves_arr Curves_arr; typedef typename Tab_traits::Traits Traits; typedef typename Tab_traits::Curve Curve; typedef typename Tab_traits::Xcurve Xcurve; typedef typename Tab_traits::Base_curve Base_curve; typedef typename Tab_traits::Data Data; typedef typename Tab_traits::Pm_curve_iter Pm_curve_iter; typedef typename Tab_traits::Pm_curve_const_iter Pm_curve_const_iter; typedef typename Tab_traits::Locate_type Locate_type; typedef typename Tab_traits::Pm_point_2 Pm_point_2; typedef typename Tab_traits::Halfedge_handle Halfedge_handle; typedef typename Tab_traits::Face_handle Face_handle; typedef typename Tab_traits::Ccb_halfedge_circulator Ccb_halfedge_circulator; typedef typename Tab_traits::Holes_iterator Holes_iterator; typedef typename Tab_traits::Halfedge_iterator Halfedge_iterator; typedef typename Tab_traits::Hafledge_list Hafledge_list; typedef typename Tab_traits::Hafledge_list_iterator Hafledge_list_iterator; typedef typename Tab_traits::Pm Pm; typedef typename Tab_traits::Vertex_iterator Vertex_iterator; typedef typename Tab_traits::Halfedge_around_vertex_circulator Halfedge_around_vertex_circulator; typedef typename Tab_traits::Edge_iterator Edge_iterator; typedef typename Tab_traits::Halfedge Halfedge; typedef typename Tab_traits::Face_iterator Face_iterator; typedef typename Tab_traits::Trap_point_location Trap_point_location; typedef typename Tab_traits::Naive_point_location Naive_point_location; typedef typename Tab_traits::Simple_point_location Simple_point_location; typedef typename Tab_traits::Walk_point_location Walk_point_location; private: // function object - FillFace class FillFace { /*! */ Qt_widget_demo_tab *ptr; public: /*! constructor */ FillFace(Qt_widget_demo_tab* tab) : ptr(tab){} /*! */ void operator()(typename Qt_widget_demo_tab::Face_handle& face) { ptr->m_tab_traits.fill_face(ptr,face); } }; /*! */ class OverLay { Qt_widget_demo_tab *ptr; std::vector overlay_colors ; public: /*! constructor */ OverLay(Qt_widget_demo_tab * tab, std::vector colors) : ptr(tab),overlay_colors(colors){} /*! */ void operator()(typename Qt_widget_demo_tab::Face_handle& face) { ptr->overlay(face,overlay_colors); } }; public: /*! m_tab_traits - the traits object */ Tab_traits m_tab_traits; /*! m_curves_arr - pointer for the tab planar map */ Curves_arr *m_curves_arr; /*! prev_curves_arr - for undo operation */ Curves_arr m_prev_curves_arr; /*! Original Traits */ Traits m_traits; /*! the curve to be merged */ Halfedge_iterator closest_curve; /*! the second curve to be merged */ Halfedge_iterator second_curve; /*! the first point in the split curve */ Pm_point_2 split_point; /*! list of removable halfedge iterators (created by move event when * DELETE option is on */ Hafledge_list removable_halfedges; /*! pointer to the point location strategy */ void * m_strategy; /*! constructor *\ param t - widget traits type *\ param parent - widget parent window *\ param tab_number - widget program index */ Qt_widget_demo_tab(TraitsType t, Strategy _strategy, QWidget * parent = 0, int tab_number = 1): Qt_widget_base_tab(t ,_strategy, parent, tab_number) { switch(strategy) { case NAIVE: { m_strategy = new Naive_point_location(); m_curves_arr = new Curves_arr((Naive_point_location*)m_strategy); break; } case TRAP: { m_strategy = new Trap_point_location(); m_curves_arr = new Curves_arr((Trap_point_location*)m_strategy); break; } case SIMPLE: { m_strategy = new Simple_point_location(); m_curves_arr = new Curves_arr((Simple_point_location*)m_strategy); break; } case WALK: { m_strategy = new Walk_point_location(); m_curves_arr = new Curves_arr((Walk_point_location*)m_strategy); break; } } // set the unbounded face initial color m_curves_arr->unbounded_face()->set_info(def_bg_color); } /*! destructor - delete the planar map and the point location pointer */ virtual ~Qt_widget_demo_tab() { delete m_curves_arr; // delete the point location strategy object switch(strategy) { case NAIVE: delete (Naive_point_location*)m_strategy; break; case TRAP: delete (Trap_point_location*)m_strategy; break; case SIMPLE: delete (Simple_point_location*)m_strategy; break; case WALK: delete (Walk_point_location*)m_strategy; break; } } ///*! save previous pm */ //void save_prev_pm() //{ // m_prev_curves_arr = m_curves_arr; //} /*! draw - called everytime something changed, draw the PM and mark the * point location if the mode is on. */ void draw() { QCursor old = cursor(); setCursor(Qt::WaitCursor); if ( mode == FILLFACE ) { Locate_type lt; Face_handle f; Pm_point_2 temp_p (pl_point.x(), pl_point.y()); Halfedge_handle e = m_curves_arr->locate(temp_p, lt); if(lt == Curves_arr::UNBOUNDED_FACE ) f = m_curves_arr->unbounded_face(); else f = e->face(); set_face_color(f,fill_face_color); } // draw all faces (fill them with their color) visit_faces(FillFace(this)); if (snap_mode == GRID || grid) draw_grid(); for (Edge_iterator ei = m_curves_arr->edges_begin(); ei != m_curves_arr->edges_end(); ++ei) { if (change_pm_color) setColor(pm_color); else { int i = (ei->curve()).get_data().m_index; setColor(colors[i]); } m_tab_traits.draw_xcurve(this , ei->curve() ); } // Go over all vertices and for each vertex check the // index numbers of the base curves that go through // it and paint the point if they are different (beacuse ew want to // color red the intersection opints between two different planar maps // which are overlayed *this << CGAL::DISC; static_cast(*this) << CGAL::LineWidth(m_vertex_width); Vertex_iterator vit; for (vit = m_curves_arr->vertices_begin(); vit != m_curves_arr->vertices_end(); vit++) { Halfedge_around_vertex_circulator eit,eit2, first = (*vit).incident_halfedges(); eit = first; setColor(Qt::red); int ind1, ind2; eit2 = first; do { // find (if exist) a different index than the tab index ind2 = (*eit2).curve().get_data().m_index; if (ind2 != index) break; eit2++; } while (eit2 != first); do { ind1 = (*eit).curve().get_data().m_index; // Keep track of IDs we haven't seen before. if (ind1 != ind2 && ind1 != index && ind2 != index) { //const Pm_point_2& p = (*vit).point(); Coord_point p(CGAL::to_double((*vit).point().x()) / m_tab_traits.COORD_SCALE, CGAL::to_double((*vit).point().y()) / m_tab_traits.COORD_SCALE); static_cast(*this) << p; break; } eit++; // draw all vertexes of the planar map is 'draw_vertex' is true // draw_vertex is a flag that indicates if we draw the vertexes if (eit == first && draw_vertex) { if (change_pm_color) setColor(pm_color); else setColor(colors[ind2]); //const Pm_point_2& p = (*vit).point(); Coord_point p(CGAL::to_double((*vit).point().x()) / m_tab_traits.COORD_SCALE, CGAL::to_double((*vit).point().y()) / m_tab_traits.COORD_SCALE); static_cast(*this) << p; } } while (eit != first); } if (mode == POINT_LOCATION && ! (m_curves_arr->halfedges_begin() == m_curves_arr->halfedges_end())) { static_cast(*this) << CGAL::LineWidth(3); setColor(Qt::yellow); Locate_type lt; Pm_point_2 temp_p (pl_point.x(), pl_point.y()); Halfedge_handle e = m_curves_arr->locate(temp_p, lt); //color the outer face Face_handle f = e->face(); if (f->does_outer_ccb_exist()) // its an inside face { Ccb_halfedge_circulator cc=f->outer_ccb(); do { m_tab_traits.draw_xcurve(this , cc->curve() ); } while (++cc != f->outer_ccb()); } //color the holes Holes_iterator hit, eit = f->holes_end(); for (hit = f->holes_begin(); hit != eit; ++hit) { Ccb_halfedge_circulator cc = *hit; do { m_tab_traits.draw_xcurve(this , cc->curve() ); cc++; } while (cc != *hit); } static_cast(*this) << CGAL::LineWidth(m_line_width); } if (mode == RAY_SHOOTING && !(m_curves_arr->halfedges_begin() == m_curves_arr->halfedges_end())) { Coord_point up; Locate_type lt; Pm_point_2 temp_p (pl_point.x(), pl_point.y()); Halfedge_handle e = m_curves_arr->vertical_ray_shoot(temp_p, lt ,ray_shooting_direction); setColor(Qt::black); static_cast(*this) << CGAL::LineWidth(1); Coord_point pl_draw(pl_point.x() / m_tab_traits.COORD_SCALE , pl_point.y() / m_tab_traits.COORD_SCALE); if (ray_shooting_direction) { if (lt == Curves_arr::UNBOUNDED_FACE) { up = Coord_point(pl_draw.x() , y_max()); static_cast(*this) << Coord_segment(pl_draw, up); } else // we shoot something { Pm_point_2 p1c1(pl_point.x() , y_max() * m_tab_traits.COORD_SCALE); Pm_point_2 p2c1(pl_point.x() , pl_point.y()); const Xcurve c1 = m_tab_traits.curve_make_x_monotone(p1c1 , p2c1); const Xcurve c2 = e->curve(); Pm_point_2 most_left(x_min() * m_tab_traits.COORD_SCALE, pl_point.y()); CGAL::Object res = m_traits.nearest_intersection_to_right(c1, c2, most_left); Pm_point_2 p1; if (CGAL::assign(p1, res)) { Coord_type y1 = CGAL::to_double(p1.y()) / m_tab_traits.COORD_SCALE; up = Coord_point(pl_draw.x(), y1); static_cast(*this) << Coord_segment(pl_draw, up); } //! \todo what if the intersection is empty, or a subcurve? } // draw an arrow that points to 'up' point int x = this->x_pixel(CGAL::to_double(up.x())); int y = this->y_pixel(CGAL::to_double(up.y())); this->get_painter().drawLine(x-7 , y+7 , x , y); this->get_painter().drawLine(x+7 , y+7 , x , y); } else // down ray shooting { Coord_point down; if (lt == Curves_arr::UNBOUNDED_FACE) { down = Coord_point(pl_draw.x() , y_min()); static_cast(*this) << Coord_segment(pl_draw , down); } else // we shoot something { Pm_point_2 p1c1(pl_point.x() , y_min() * m_tab_traits.COORD_SCALE); Pm_point_2 p2c1(pl_point.x() , pl_point.y()); const Xcurve c1 = m_tab_traits.curve_make_x_monotone(p1c1 , p2c1); const Xcurve c2 = e->curve(); Pm_point_2 most_right(x_max() * m_tab_traits.COORD_SCALE, pl_point.y()); CGAL::Object res = m_traits.nearest_intersection_to_left(c1, c2, most_right); Pm_point_2 p1; if (CGAL::assign(p1, res)) { Coord_type y1 = CGAL::to_double(p1.y()) / m_tab_traits.COORD_SCALE; down = Coord_point(pl_draw.x(),y1); static_cast(*this) << Coord_segment(pl_draw, down); } //! \todo what if the intersection is empty, or a subcurve? } // draw an arrow that points to 'down' point int x = this->x_pixel(CGAL::to_double(down.x())); int y = this->y_pixel(CGAL::to_double(down.y())); this->get_painter().drawLine(x-7 , y-7 , x , y); this->get_painter().drawLine(x+7 , y-7 , x , y); } static_cast(*this) << CGAL::LineWidth(3); setColor(Qt::red); switch (lt) { case (Curves_arr::VERTEX): { Coord_point p(CGAL::to_double(e->target()->point().x()) / m_tab_traits.COORD_SCALE, CGAL::to_double(e->target()->point().y()) / m_tab_traits.COORD_SCALE); static_cast(*this) << p; break; } case (Curves_arr::UNBOUNDED_VERTEX) : { Coord_point p(CGAL::to_double(e->target()->point().x()) / m_tab_traits.COORD_SCALE, CGAL::to_double(e->target()->point().y()) / m_tab_traits.COORD_SCALE); static_cast(*this) << p; break; } case (Curves_arr::EDGE): m_tab_traits.draw_xcurve(this , e->curve() ); break; case (Curves_arr::UNBOUNDED_EDGE) : m_tab_traits.draw_xcurve(this , e->curve() ); break; case (Curves_arr::FACE) : break; case (Curves_arr::UNBOUNDED_FACE) : break; } static_cast(*this) << CGAL::LineWidth(m_line_width); } setCursor(old); } /*! */ void update_colors(std::vector colors) { OverLay overlay_ob(this, colors); visit_faces(overlay_ob); } /*! */ void set_face_color(Face_handle &f ,QColor& c) { f->set_info(c); if( ! f->does_outer_ccb_exist() || empty) set_unbounded_face_color(c); } /*! */ template void visit_faces(Function func) { Face_iterator fi=m_curves_arr->faces_begin(); for( ; fi != m_curves_arr->faces_end() ; ++fi ) fi->set_visited(false); Face_handle ub = m_curves_arr->unbounded_face(); visit_face_rec (ub,func) ; } /*! antenna - return true if the halfedge and its * twin point to the same face. */ bool antenna(Halfedge & h) { Halfedge twin = *(h.opposite()); return (twin.face() == h.face()); } /*! draw a face and all its holes recursively */ template void visit_face_rec( Face_handle &f, Function func ) { if (! f->visited()) { Holes_iterator hit; // holes iterator func(f); f->set_visited(true); for(hit= f->holes_begin() ; hit!=f->holes_end() ; ++hit) { Ccb_halfedge_circulator cc = *hit; do { Halfedge he = *cc; Halfedge he2 = *(he.opposite()); Face_handle inner_face = he2.face(); // not sure about that if (antenna(he)) continue; // move on to next hole visit_ccb_faces(inner_face , func); }while (++cc != *hit); }// for } }// visit_face_rec template void visit_ccb_faces(Face_handle & fh, Function func) { visit_face_rec(fh,func); Ccb_halfedge_circulator cc=fh->outer_ccb(); do { Halfedge he = *cc; if(! he.opposite()->face()->visited()) { Face_handle nei = (Face_handle) he.opposite()->face(); visit_ccb_faces( nei ,func ); } //created from the outer boundary of the face } while (++cc != fh->outer_ccb()); } /*! */ void overlay (Face_handle f , std::vector & colors) { f->assign_overlay_info(colors); if (f->does_outer_ccb_exist()) // f is not the unbounded face { /* running around the outer of the face */ Ccb_halfedge_circulator cc = f->outer_ccb(); do { Halfedge he = *cc; // get the halfedge Data d = he.curve().get_data(); // get the data of the halfedge // get the original halfedge (from the original PM) Halfedge_handle original_he = d.halfedge_handle, temp_he; // getting the index of the original PM of the curve int index = d.m_index; if(m_tab_traits.curve_has_same_direction(cc)) temp_he = original_he; else temp_he=(Halfedge_handle)original_he->opposite(); // the original color of the face QColor original_face_color = temp_he->face()->info(); // update the colors vector in the face f->set_overlay_info( index , original_face_color); // we want to update the colors vector to pass colors[index] = original_face_color; // the information down the recurtion process. } while (++cc != f->outer_ccb()); // blend the colors QColor c = blend_colors(f->OverlayInfoBegin() , f-> OverlayInfoEnd()); f->set_info(c); } else // f is the unbounded face { // blend the colors QColor c = blend_colors(colors.begin() , colors.end() ); f->set_info(c); set_unbounded_face_color(c); } } /*! draw_grid - draw the grid */ void draw_grid() { setColor(Qt::white); static_cast(*this) << CGAL::LineWidth(1); // get the edge coordinate int min_x = static_cast (x_min()); int max_x = static_cast (x_max()); int min_y = static_cast (y_min()); int max_y = static_cast (y_max()); // calculate cube size (minimum of 1) //int cube_size_x = std::max(1, abs(max_x - min_x)/20); //int cube_size_y = std::max(1, abs(max_y - min_y)/20); if (cube_size < std::abs(max_x - min_x)/40 || cube_size < std::abs(max_y - min_y)/40) cube_size = std::max(std::max(1, std::abs(max_x - min_x)/20), std::max(1, std::abs(max_y - min_y)/20)); int cube_size_x = cube_size; int cube_size_y = cube_size; // draw the grid lines for (int i = min_x; i <= max_x; i += cube_size_x) static_cast(*this) << Coord_segment(Coord_point(i, max_y + cube_size_y), Coord_point( i , min_y - cube_size_y)); for (int i = min_y; i <= max_y; i += cube_size_y) static_cast(*this) << Coord_segment(Coord_point( max_x + cube_size_x , i ), Coord_point( min_x - cube_size_x , i )); } /*! mousePressEvent - mouse click on the tab *\ param e - mouse click event */ void mousePressEvent(QMouseEvent *e) { QCursor old = cursor(); setCursor(Qt::WaitCursor); if (mode == POINT_LOCATION || mode == RAY_SHOOTING || mode == FILLFACE) { mousePressEvent_point_location( e ); setCursor(old); return; } if (mode == DELETE) { Hafledge_list_iterator itr; for (itr = removable_halfedges.begin(); itr != removable_halfedges.end() ; ++itr) m_curves_arr->remove_edge(*itr); removable_halfedges.clear(); // clear the list which is now irrelevant redraw(); if( m_curves_arr->number_of_vertices() == 0 ) empty = true; setCursor(old); return; } if (mode == INSERT) { Coord_type x, y; x_real(e->x(), x); y_real(e->y(), y); Coord_point p = get_point(x,y); lock(); QColor old_color = color(); RasterOp old_rasterop=rasterOp(); get_painter().setRasterOp(XorROP); insert( e , p); setRasterOp(old_rasterop); setColor(old_color); unlock(); if( m_curves_arr->number_of_vertices() > 0 ) empty = false; setCursor(old); return; } if (mode == DRAG) { mousePressEvent_drag(e); setCursor(old); return; } if (mode == MERGE) { mousePressEvent_merge(e); setCursor(old); return; } if (mode == SPLIT) { Coord_type x, y; x_real(e->x(), x); y_real(e->y(), y); Coord_point p = get_point(x,y); lock(); QColor old_color = color(); RasterOp old_rasterop=rasterOp(); get_painter().setRasterOp(XorROP); split( e , p); setRasterOp(old_rasterop); setColor(old_color); unlock(); first_time = true; redraw(); setCursor(old); return; } } /*! insert - insert a curve to the planar map *\ param e - mouse click event *\ param p - the pressed point */ void insert( QMouseEvent *e , Coord_point p) { if(e->button() == Qt::LeftButton && is_pure(e->state())) { if(!active) { active = true; m_tab_traits.first_point( p , mode ); } else { //show the last rubber as edge of the polygon m_tab_traits.middle_point( p , this ); } } // finish polyline draw with right button click else if (active && e->button() == Qt::RightButton && is_pure(e->state())) { m_tab_traits.last_point( p , this ); } } /*! split - split a xcurve in to 2 xcurves *\ param e - mouse click event *\ param p - the pressed point */ void split( QMouseEvent *e , Coord_point p) { if(e->button() == Qt::LeftButton && is_pure(e->state())) { if(!active) { active = true; m_tab_traits.first_point( p , mode); split_point = Pm_point_2( p.x() * m_tab_traits.COORD_SCALE , p.y() * m_tab_traits.COORD_SCALE); } else { active = false; Pm_point_2 split_point2 = Pm_point_2(p.x() * m_tab_traits.COORD_SCALE, p.y() * m_tab_traits.COORD_SCALE); const Xcurve split_curve = m_tab_traits.curve_make_x_monotone(split_point , split_point2); Pm_point_2 p1; Pm_point_2 p_right; if (split_point.x() < split_point2.x()) p_right = split_point; else p_right = split_point2; Halfedge_iterator hei; for (hei = m_curves_arr->halfedges_begin(); hei != m_curves_arr->halfedges_end(); ++hei) { const Xcurve & xcurve = hei->curve(); m_tab_traits.draw_xcurve(this, xcurve); CGAL::Object res = m_traits.nearest_intersection_to_right(split_curve, xcurve,p_right); if (CGAL::assign(p1, res)) break; } Vertex_iterator vit; bool is_already_vertex = false; // we dont want to split an already existed vertex... for (vit = m_curves_arr->vertices_begin(); vit != m_curves_arr->vertices_end(); vit++) { Pm_point_2 temp = (*vit).point(); if (p1 == temp) is_already_vertex = true; } m_tab_traits.draw_xcurve(this, hei->curve()); if (hei != m_curves_arr->halfedges_end() && !is_already_vertex) m_tab_traits.split_edge(hei , p1 , this); }// else } } /*! mousePressEvent_point_location - creats the point location point *\ param e - mouse click event */ void mousePressEvent_point_location(QMouseEvent *e) { if(e->button() == Qt::LeftButton && is_pure(e->state())) { Coord_type x, y; x_real(e->x(), x); y_real(e->y(), y); new_object(make_object(Coord_point(x * m_tab_traits.COORD_SCALE, y * m_tab_traits.COORD_SCALE))); } } /*! is_pure - insure no special button is pressed *\ param s - keyboard modifier flags that existed * immediately before the event occurred. *\ return true if one of them existed, false otherway. */ bool is_pure(Qt::ButtonState s) { if((s & Qt::ControlButton) || (s & Qt::ShiftButton) || (s & Qt::AltButton)) return 0; else return 1; } /*! dist *\ param x1,y1,x2,y2 - points coordinates *\ return the distance between 2 points */ Coord_type dist(Coord_type x1, Coord_type y1, Coord_type x2, Coord_type y2) { return sqrt(pow(x1 - x2, 2) + pow(y1 - y2, 2)); } /*! getMid *\ param coord - coord vulue apon the grid *\ return the closest grid point */ Coord_type getMid(Coord_type coord, int my_min, int my_max) { //int cube_size = std::max(1, abs(my_max - my_min)/20); Coord_type d = static_cast(cube_size)/2; for (int i = my_min - cube_size; i <= my_max; i += cube_size) { Coord_type id = static_cast(i); if (coord >= id - d && coord <= id + d) { Coord_type ans = static_cast(i); return ans; } } return 0; } /*! find_removeable_halfedges - find removable curve in the tab *\ param e - mouse click event */ void find_removable_halfedges(QMouseEvent *e) { // if the PM is empty do nothing if( m_curves_arr->number_of_vertices() == 0) return; if(!removable_halfedges.empty()) { int i = (removable_halfedges.front()->curve()).get_data().m_index; setColor(colors[i]); Hafledge_list_iterator itr; for (itr = removable_halfedges.begin(); itr != removable_halfedges.end() ; ++itr) m_tab_traits.draw_xcurve(this,(*itr)->curve()); // clear the previous list which is now irrelevant removable_halfedges.clear(); } // get the point of the mouse Coord_point p(x_real(e->x()) * m_tab_traits.COORD_SCALE , y_real(e->y()) * m_tab_traits.COORD_SCALE); bool is_first = true; Coord_type min_dist = 0; Halfedge_iterator hei; Halfedge_iterator closest_hei; for (hei = m_curves_arr->halfedges_begin(); hei != m_curves_arr->halfedges_end(); ++hei) { Xcurve & xcurve = hei->curve(); Coord_type dist = m_tab_traits.xcurve_point_distance(p, xcurve , this); if (is_first || dist < min_dist) { min_dist = dist; closest_hei = hei; is_first = false; } } // now 'closest_hei' holds the cloeset halfedge to the point of the mouse if (remove_org_curve && !read_from_file) { const Base_curve * org_curve = m_tab_traits.get_origin_curve(closest_hei->curve()); Hafledge_list li; Hafledge_list_iterator result; for (hei = m_curves_arr->halfedges_begin(); hei != m_curves_arr->halfedges_end(); ++hei) { const Base_curve * curve = m_tab_traits.get_origin_curve(hei->curve()); result = std::find(li.begin(), li.end(), hei); if (curve == org_curve && result == li.end()) { li.push_back(hei->twin()); //m_curves_arr->remove_edge(hei); setColor(Qt::red); // highlight the removable edge with red color m_tab_traits.draw_xcurve(this,hei->curve()); removable_halfedges.push_back(hei); } } } else { // m_curves_arr->remove_edge(closest_hei); setColor(Qt::red); // highlight the removable edge with red color m_tab_traits.draw_xcurve(this,closest_hei->curve()); removable_halfedges.push_back(closest_hei); } } /*! mouseMoveEvent - enable seeing the line to be drawen *\ param e - mouse click event */ void mouseMoveEvent(QMouseEvent *e) { static_cast(*this) << CGAL::LineWidth(m_line_width); if (mode == DELETE) // find removable edges , store them in the list find_removable_halfedges(e); //'removable_halfedges' and highlight them if (mode == DRAG) { mouseMoveEvent_drag(e); return; } if (mode == MERGE && !first_time_merge) { if (second_curve != m_curves_arr->halfedges_end()) { int i = (second_curve->curve()).get_data().m_index; setColor(colors[i]); m_tab_traits.draw_xcurve(this,second_curve->curve()); } Coord_type x, y; x_real(e->x(), x); y_real(e->y(), y); Coord_point p(x * m_tab_traits.COORD_SCALE, y * m_tab_traits.COORD_SCALE); second_curve = m_curves_arr->halfedges_end(); m_tab_traits.find_close_curve(closest_curve, second_curve, p, this, true); setColor(Qt::red); m_tab_traits.draw_xcurve(this,closest_curve->curve()); if (second_curve != m_curves_arr->halfedges_end()) { setColor(Qt::green); m_tab_traits.draw_xcurve(this,second_curve->curve()); } else { first_time_merge = true; redraw(); } return; }// merge if(active) { Coord_type x, y; x_real(e->x(), x); y_real(e->y(), y); Coord_point p = get_point(x,y); RasterOp old_raster = rasterOp();//save the initial raster mode setRasterOp(XorROP); lock(); setColor(Qt::green); if(!first_time) m_tab_traits.draw_last_segment(this); m_tab_traits.draw_current_segment( p , this); unlock(); setRasterOp(old_raster); first_time = false; } } /*! leaveEvent - hide the line if you leave the widget's area on the screen *\ param e - mouse click event */ void leaveEvent(QEvent *e) { if(active) { RasterOp old_raster = rasterOp();//save the initial raster mode QColor old_color = color(); lock(); setRasterOp(XorROP); setColor(Qt::green); m_tab_traits.draw_last_segment(this); setRasterOp(old_raster); setColor(old_color); unlock(); first_time = true; } } /*! get_point *\ params x,y - the mouse clicked point coordinates *\ return a point according to the current snap mode and * recent points. */ Coord_point get_point(Coord_type x, Coord_type y) { int xmin = static_cast (x_min()); int xmax = static_cast (x_max()); int ymin = static_cast (y_min()); int ymax = static_cast (y_max()); Coord_type d = std::max(0.5 , (x_max() - x_min())/40); switch ( snap_mode ) { case POINT: { Coord_type min_dist = 0; Coord_point closest; if( m_curves_arr->number_of_vertices() == 0 ) return Coord_point(x , y); min_dist = m_tab_traits.closest_point(x,y,closest,this); if (min_dist <= d) return closest; else return Coord_point(x , y); break; } case GRID: return Coord_point(getMid(x, xmin, xmax), getMid(y, ymin, ymax) ); case NONE: break; } return Coord_point(x,y); } /*! mousePressEvent_drag - change the Cursor on the drag mode * mouse pressed event *\ param e - mouse click event */ void mousePressEvent_drag(QMouseEvent *e) { if(e->button() == Qt::LeftButton && is_pure(e->state())) { setCursor(QCursor( QPixmap( (const char**)holddown_xpm))); if (!on_first){ first_x = e->x(); first_y = e->y(); on_first = TRUE; } } } /*! mouseReleaseEvent - change the Cursor on the drag mode * mouse pressed event and move the widget center according * to the drag distance. *\ param e - mouse release event */ void mouseReleaseEvent(QMouseEvent *e) { if(e->button() == Qt::LeftButton && mode == DRAG && is_pure(e->state())) { setCursor(QCursor( QPixmap( (const char**)hand_xpm))); double x, y, xfirst2, yfirst2; x_real(e->x(), x); y_real(e->y(), y); x_real(first_x, xfirst2); y_real(first_y, yfirst2); double xmin, xmax, ymin, ymax, distx, disty; if(x < xfirst2) {xmin = x; xmax = xfirst2;} else {xmin = xfirst2; xmax = x;}; if(y < yfirst2) {ymin = y; ymax = yfirst2;} else {ymin = yfirst2; ymax = y;}; distx = xfirst2 - x; disty = yfirst2 - y; move_center(distx, disty); on_first = FALSE; } } /*! mouseMoveEvent_drag - calculate new widget position *\ param e - mouse release event */ void mouseMoveEvent_drag(QMouseEvent *e) { if(on_first) { int x = e->x(); int y = e->y(); //save the last coordinates to redraw the screen x2 = x; y2 = y; wasrepainted = FALSE; } }; /*! mousePressEvent_merge - merge mode * mouse pressed event *\ param e - mouse click event */ void mousePressEvent_merge(QMouseEvent *e) { if(e->button() == Qt::LeftButton && is_pure(e->state())) { if( m_curves_arr->number_of_vertices() == 0 ) return; setColor(Qt::red); Coord_point p(x_real(e->x()) * m_tab_traits.COORD_SCALE , y_real(e->y()) * m_tab_traits.COORD_SCALE); bool is_first = true; Coord_type min_dist = 0; if (first_time_merge) { first_time_merge = false; Halfedge_iterator hei; //closest_curve = m_curves_arr->halfedges_end(); for (hei = m_curves_arr->halfedges_begin(); hei != m_curves_arr->halfedges_end(); ++hei) { Vertex_iterator vis = hei->source(); Vertex_iterator vit = hei->target(); if (vis->degree() != 2 && vit->degree() != 2) continue; Xcurve & xcurve = hei->curve(); Coord_type dist = m_tab_traits.xcurve_point_distance(p, xcurve, this); if (is_first || dist < min_dist) { min_dist = dist; closest_curve = hei; is_first = false; } } if (is_first) // we didn't find any "good" curve { first_time_merge = true; return; } m_tab_traits.draw_xcurve(this , closest_curve->curve() ); second_curve = m_curves_arr->halfedges_end(); } else { first_time_merge = true; m_tab_traits.find_close_curve(closest_curve, second_curve, p, this, false); redraw(); } } } /*! */ void update_curves_date_after_split(Halfedge_handle & e1, Xcurve & c1, Xcurve & c2) { Xcurve my_c1 , my_c2; //temp variable // check that e1 is indeed the halfede of c1 if(m_tab_traits.is_curve_and_halfedge_same_direction(e1,c1)) { my_c1 = c1; my_c2 = c2; } else { my_c1 = c2; my_c2 = c1; } // update my_c1 Data d1 = my_c1.get_data(); if(m_tab_traits.is_curve_and_halfedge_same_direction(e1 , my_c1)) d1.halfedge_handle = e1; else d1.halfedge_handle = (Halfedge_handle)e1->opposite(); e1->curve().set_data( d1 ); e1->opposite()->curve().set_data( d1 ); // update my_c2 Data d2 = my_c2.get_data(); if (m_tab_traits.is_curve_and_halfedge_same_direction ((Halfedge_handle)e1->next() , my_c2)) d2.halfedge_handle = (Halfedge_handle)e1->next(); else d2.halfedge_handle = (Halfedge_handle) e1->next()->opposite(); e1->next()->curve().set_data( d2 ); e1->next()->opposite()->curve().set_data( d2 ); } /*! */ void update_curve_data_after_merge(Halfedge_handle &h ,Xcurve &c) { Data d = c.get_data(); if(m_tab_traits.is_curve_and_halfedge_same_direction(h , c)) d.halfedge_handle = h; else d.halfedge_handle = (Halfedge_handle)h->opposite(); h->curve().set_data( d ); h->opposite()->curve().set_data( d ); } }; ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// /*! class Segment_tab_traits defines the segment traits */ class Segment_tab_traits { public: typedef Pm_seg_list Curves_list; typedef Seg_arr Curves_arr; typedef Seg_traits Traits; typedef Pm_seg_iter Pm_curve_iter; typedef Pm_seg_const_iter Pm_curve_const_iter; typedef Seg_locate_type Locate_type; typedef Pm_seg_point_2 Pm_point_2; typedef Seg_halfedge_handle Halfedge_handle; typedef Pm_seg_2 Curve; typedef Pm_xseg_2 Xcurve; typedef Pm_base_seg_2 Base_curve; typedef Seg_face_handle Face_handle; typedef Seg_ccb_halfedge_circulator Ccb_halfedge_circulator; typedef Seg_holes_iterator Holes_iterator; typedef Seg_pm::Halfedge_iterator Halfedge_iterator; typedef std::list Hafledge_list; typedef Hafledge_list::iterator Hafledge_list_iterator; typedef Curves_arr::Vertex_iterator Vertex_iterator; typedef Seg_pm Pm; typedef Curves_arr::Vertex_iterator Vertex_iterator; typedef Curves_arr::Halfedge_around_vertex_circulator Halfedge_around_vertex_circulator; typedef Curves_arr::Edge_iterator Edge_iterator; typedef Curve_data Data; typedef Seg_halfedge Halfedge; typedef Seg_face_iterator Face_iterator; //point location typedef Seg_trap_point_location Trap_point_location; typedef Seg_naive_point_location Naive_point_location; typedef Seg_simple_point_location Simple_point_location; typedef Seg_walk_point_location Walk_point_location; //typedef Seg_lenmarks_point_location Lenmarks_point_location; public: /*! coordinate scale - used in conics*/ int COORD_SCALE; /*! constructor */ Segment_tab_traits(): COORD_SCALE(1) {} /*! distructor */ ~Segment_tab_traits() {} /*! curve_has_same_direction - return true if the halfegde and * its curve has the same direction */ bool curve_has_same_direction( Ccb_halfedge_circulator &cc) { return (cc->curve().source() == cc->source()->point()); } /*! check if curve and its halfedge are at the same direction */ bool is_curve_and_halfedge_same_direction (const Halfedge_handle & he, const Xcurve & cv) { return (he->source()->point() == cv.source()); } /*! fill_face - fill a face with its color (which is stored at the face) * it creates a polyong from the outer boundary of the face and * uses CGAL opertaor << of polygons */ void fill_face(Qt_widget_demo_tab * w , Face_handle f) { if (f->does_outer_ccb_exist()) // f is not the unbounded face { std::list< Coord_point > pts; // holds the points of the polygon /* running with around the outer of the face and generate from it * polygon */ Ccb_halfedge_circulator cc=f->outer_ccb(); do { Coord_type x = CGAL::to_double(cc->source()->point().x()); Coord_type y = CGAL::to_double(cc->source()->point().y()); Coord_point coord_source(x , y); pts.push_back(coord_source ); //created from the outer boundary of the face } while (++cc != f->outer_ccb()); // make polygon from the outer ccb of the face 'f' Polygon pgn (pts.begin() , pts.end()); w->setFilled(true); // fill the face according to its color (stored at any of her // incidents curves) if (! f->info().isValid()) w->setFillColor(def_bg_color); else w->setFillColor(f->info()); QPen old_penstyle = w->get_painter().pen(); w->get_painter().setPen(Qt::NoPen); (*w) << pgn ; // draw the polyong w->setFilled(false); w->get_painter().setPen(old_penstyle); } else { Coord_point points[4]; points[0] = (Coord_point(w->x_min(),w->y_min())); points[1] = (Coord_point(w->x_min(),w->y_max())); points[2] = (Coord_point(w->x_max(),w->y_max())); points[3] = (Coord_point(w->x_max(),w->y_min())); w->setFilled(true); w->setFillColor(w->unbounded_face_color()); QPen old_penstyle = w->get_painter().pen(); w->get_painter().setPen(Qt::NoPen); (*w)<setFilled(false); w->get_painter().setPen(old_penstyle); } } /*! draw_xcurve - use Qt_Widget operator to draw *\ param w - the demo widget *\ c - curve to be drawen */ void draw_xcurve(Qt_widget_demo_tab * w , Xcurve c ) { (*w) << c; } /*! first_point - a first point of inserted sgment */ void first_point( Coord_point p , Mode m ) { m_p1 = m_p2 = p; } /*! middle_point - the last point of a segment */ void middle_point(Coord_point p , Qt_widget_demo_tab * w) { if(m_p1.x() != p.x() || m_p1.y() != p.y()) { get_segment( Coord_segment( m_p1 , p ) , w ); w->active = false; //w->redraw(); // not working so I use new_object insted w->new_object(make_object(Coord_segment(m_p1 , p))); } } /*! last_point - meaningless for segments */ void last_point( Coord_point p , Qt_widget_demo_tab * w ) { return; } /*! get_segment - create a new segment, insert him into curves_list * and planar map */ void get_segment( Coord_segment coord_seg , Qt_widget_demo_tab * w) { Seg_notification seg_notif; const Coord_point & coord_source = coord_seg.source(); const Coord_point & coord_target = coord_seg.target(); Pm_seg_point_2 source(coord_source.x(), coord_source.y()); Pm_seg_point_2 target(coord_target.x(), coord_target.y()); Pm_base_seg_2 * base_seg_p = new Pm_base_seg_2(source, target); Curve_data cd; cd.m_type = Curve_data::LEAF; cd.m_index = w->index; cd.m_ptr.m_curve = base_seg_p; Pm_seg_2 * seg = new Pm_seg_2( *base_seg_p, cd ); Halfedge_handle hh = w->m_curves_arr->insert(*seg, &seg_notif); CGAL::Bbox_2 curve_bbox = seg->bbox(); w->bbox = w->bbox + curve_bbox; //Curve_data d = hh->curve().get_data(); // get the data of the halfedge // Halfedge_handle original_he = d.halfedge_handle; } /*! curve_point_distance - return the distance between a point * and a segment */ Coord_type curve_point_distance(Coord_point p, Curve * c , Qt_widget_demo_tab * w) { const Pm_seg_point_2 & source = (*c).source(); const Pm_seg_point_2 & target = (*c).target(); Coord_type x1 = CGAL::to_double(source.x()); Coord_type y1 = CGAL::to_double(source.y()); Coord_type x2 = CGAL::to_double(target.x()); Coord_type y2 = CGAL::to_double(target.y()); Coord_point coord_source(x1 , y1); Coord_point coord_target(x2 , y2); Coord_segment coord_seg(coord_source, coord_target); return CGAL::squared_distance( p, coord_seg); } /*! xcurve_point_distance - return the distance between a point * and a xsegment */ Coord_type xcurve_point_distance(Coord_point p, Xcurve & c , Qt_widget_demo_tab * w) { const Pm_seg_point_2 & source = c.source(); const Pm_seg_point_2 & target = c.target(); Coord_type x1 = CGAL::to_double(source.x()); Coord_type y1 = CGAL::to_double(source.y()); Coord_type x2 = CGAL::to_double(target.x()); Coord_type y2 = CGAL::to_double(target.y()); Coord_point coord_source(x1 , y1); Coord_point coord_target(x2 , y2); Coord_segment coord_seg(coord_source, coord_target); return CGAL::squared_distance( p, coord_seg); } /*! get_origin_curve - return the origin base curve */ const Pm_base_seg_2* get_origin_curve(const Pm_xseg_2 & xseg ) { const Curve_data & curve_data = xseg.get_data(); if (curve_data.m_type == Curve_data::LEAF) return curve_data.m_ptr.m_curve; else // curve_data.m_type == Curve_data::INTERNAL { const Pm_xseg_2* xseg_p = curve_data.m_ptr.m_x_motonote_curve; return get_origin_curve( *xseg_p ); } } /*! draw_last_segment - call from mouse move event */ void draw_last_segment( Qt_widget_demo_tab * w) { *w << Coord_segment( m_p1 , m_p2 ); } /*! draw_current_segment - call from mouse move event */ void draw_current_segment( Coord_point p , Qt_widget_demo_tab * w) { *w << Coord_segment( m_p1 , p); m_p2 = p; } /*! closest_point - find the closest point in the planar map * to a clicked point */ Coord_type closest_point(Coord_type x, Coord_type y, Coord_point &closest, Qt_widget_demo_tab * w) { bool first = true; Coord_type x1,y1,dt,min_dist = 0; Vertex_iterator vit; for (vit = w->m_curves_arr->vertices_begin(); vit != w->m_curves_arr->vertices_end(); vit++) { const Pm_point_2& p = (*vit).point(); x1 = CGAL::to_double(p.x()); y1 = CGAL::to_double(p.y()); dt = w->dist(x1 , y1 , x , y); if ( dt < min_dist || first) { min_dist = dt; closest = Coord_point(x1 , y1); first = false; } } return min_dist; } /*! curve_make_x_monotone */ const Xcurve curve_make_x_monotone(Pm_point_2 p1 , Pm_point_2 p2) { Data d; const Curve cv(Base_curve(p1 , p2) , d); std::list xcurve_list; m_traits.curve_make_x_monotone(cv, std::back_inserter(xcurve_list)); const Xcurve c1 = xcurve_list.front(); return c1; } /*! */ void find_close_curve(Halfedge_iterator &closest_curve ,Halfedge_iterator &second_curve ,Coord_point &p , Qt_widget_demo_tab *w, bool move_event) { bool is_first = true; Coord_type min_dist = 0; Halfedge_iterator hei; Pm_point_2 s = closest_curve->source()->point(); Pm_point_2 t = closest_curve->target()->point(); Vertex_iterator vis = closest_curve->source(); Vertex_iterator vit = closest_curve->target(); Kernel ker; for (hei = w->m_curves_arr->halfedges_begin(); hei != w->m_curves_arr->halfedges_end(); ++hei) { Pm_point_2 s1 = hei->source()->point(); Pm_point_2 t1 = hei->target()->point(); if (merge_segments_precondition(s, t, s1, t1, vis->degree(), vit->degree()) && ker.compare_slope_2_object()(Kernel::Segment_2(s, t), Kernel::Segment_2(s1, t1)) == CGAL::EQUAL) { Xcurve & xcurve = hei->curve(); Coord_type dist = xcurve_point_distance( p, xcurve , w); if (is_first || dist < min_dist) { min_dist = dist; second_curve = hei; is_first = false; } } } if (is_first) // didn't find any "good" curve return; else if (!move_event) { Pm_point_2 s1 = second_curve->source()->point(); Pm_point_2 t1 = second_curve->target()->point(); Base_curve * base = 0; if ( t == s1 ) base = new Base_curve(s, t1); else if ( t == t1 ) base = new Base_curve(s, s1); else if ( s == s1 ) base = new Base_curve(t, t1); else if ( s == t1 ) base = new Base_curve(t, s1); Curve_data cd; cd.m_type = Curve_data::LEAF; cd.m_index = w->index; cd.m_ptr.m_curve = base; Curve *seg = new Curve( *base, cd ); std::list xcurve_list; m_traits.curve_make_x_monotone(*seg, std::back_inserter(xcurve_list)); Xcurve c = xcurve_list.front(); Halfedge_handle h = w->m_curves_arr->merge_edge( closest_curve , second_curve , c); w->update_curve_data_after_merge(h , c); //// update c // // Curve_data d = c.get_data(); //if(is_curve_and_halfedge_same_direction(h , c)) // d.halfedge_handle = h; //else // d.halfedge_handle = (Halfedge_handle)h->opposite(); //h->curve().set_data( d ); //h->opposite()->curve().set_data( d ); } } /*! */ void split_edge(Halfedge_iterator &hei ,Pm_point_2 &p , Qt_widget_demo_tab *w) { std::list xcurve_list; Base_curve *base1 = new Base_curve; Base_curve *base2 = new Base_curve; Base_seg_traits base_seg_traits; base_seg_traits.curve_split (hei->curve(), *base1, *base2, p); Curve_data cd1; cd1.m_type = Curve_data::LEAF; cd1.m_index = hei->curve().get_data().m_index; cd1.m_ptr.m_curve = base1; Curve *seg1 = new Curve( *base1, cd1 ); m_traits.curve_make_x_monotone(*seg1, std::back_inserter(xcurve_list)); Xcurve c1 = xcurve_list.front(); Curve_data cd2; cd2.m_type = Curve_data::LEAF; cd2.m_index = hei->curve().get_data().m_index; cd2.m_ptr.m_curve = base2; Curve *seg2 = new Curve( *base2, cd2 ); xcurve_list.clear(); m_traits.curve_make_x_monotone(*seg2, std::back_inserter(xcurve_list)); Xcurve c2 = xcurve_list.front(); // split hei into curves : c1 ,c2 and store halfedge e1 (halfedge of c1) Halfedge_handle e1 = w->m_curves_arr->split_edge(hei , c1 , c2); // update the halfedge_handle field in the Curve_Data of c1 ,c2 // Curve_Data w->update_curves_date_after_split(e1 , c1, c2); } /*! temporary points of the created segment */ Traits m_traits; Coord_point m_p1,m_p2; }; ////////////////////////////////////////////////////////////////////////////// /*! class Polyline_tab_traits defines the polyline traits */ class Polyline_tab_traits { public: typedef Pm_pol_list Curves_list; typedef Pol_arr Curves_arr; typedef Pol_traits Traits; typedef Pm_pol_iter Pm_curve_iter; typedef Pm_pol_const_iter Pm_curve_const_iter; typedef Pol_locate_type Locate_type; typedef Pm_pol_point_2 Pm_point_2; typedef Pol_halfedge_handle Halfedge_handle; typedef Pm_pol_2 Curve; typedef Pm_xpol_2 Xcurve; typedef Pm_base_pol_2 Base_curve; typedef Pol_face_handle Face_handle; typedef Pol_ccb_halfedge_circulator Ccb_halfedge_circulator; typedef Pol_holes_iterator Holes_iterator; typedef Pol_pm::Halfedge_iterator Halfedge_iterator; typedef std::list Hafledge_list; typedef Hafledge_list::iterator Hafledge_list_iterator; typedef std::vector::iterator Point_vector_iterator; typedef Curve::const_iterator Curve_const_iterator; typedef Pol_pm Pm; typedef Curves_arr::Vertex_iterator Vertex_iterator; typedef Curves_arr::Halfedge_around_vertex_circulator Halfedge_around_vertex_circulator; typedef Curves_arr::Edge_iterator Edge_iterator; typedef Curve_pol_data Data; typedef Pol_halfedge Halfedge; typedef Pol_face_iterator Face_iterator; //point location typedef Pol_trap_point_location Trap_point_location; typedef Pol_naive_point_location Naive_point_location; typedef Pol_simple_point_location Simple_point_location; typedef Pol_walk_point_location Walk_point_location; //typedef Pol_lenmarks_point_location Lenmarks_point_location; /*! coordinate scale - used in conics*/ int COORD_SCALE; /*! constructor */ Polyline_tab_traits(): COORD_SCALE(1) {} /*! distructor */ ~Polyline_tab_traits() {} /*! curve_has_same_direction - return true if the curve and * the halfedge has the same direction */ bool curve_has_same_direction( Ccb_halfedge_circulator &cc) { return ( *(cc->curve().begin()) == cc->source()->point()); } /*! */ bool is_curve_and_halfedge_same_direction(const Halfedge_handle & he, const Xcurve & cv) { return (he->source()->point() == *(cv.begin())); } /*! fill_face - fill a face with its color (which is stored at the curves) * it creates a polyong from the outer boundary of the face and * uses CGAL opertaor << of polygons */ void fill_face(Qt_widget_demo_tab * w , Face_handle f) { if (f->does_outer_ccb_exist()) // f is not the unbounded face { std::list< Coord_point > pts; // holds the points of the polygon Xcurve::const_iterator pt_itr; Xcurve cv; /* running with around the outer of the face and generate from it * polygon */ Ccb_halfedge_circulator cc=f->outer_ccb(); do { cv = cc->curve(); if( curve_has_same_direction (cc) ) { for( pt_itr = cv.begin() , ++pt_itr ; pt_itr != cv.end(); ++pt_itr) { Coord_type x = CGAL::to_double((*pt_itr).x()); Coord_type y = CGAL::to_double((*pt_itr).y()); Coord_point coord_source(x , y); pts.push_back(coord_source ); } } else { for( pt_itr = cv.rbegin() , ++pt_itr ; pt_itr != cv.rend(); ++pt_itr) { Coord_type x = CGAL::to_double((*pt_itr).x()); Coord_type y = CGAL::to_double((*pt_itr).y()); Coord_point coord_source(x , y); pts.push_back(coord_source ); } } //created from the outer boundary of the face } while (++cc != f->outer_ccb()); // make polygon from the outer ccb of the face 'f' Polygon pgn (pts.begin() , pts.end()); w->setFilled(true); // fill the face according to its color (stored at any of her // incidents curves) if (! f->info().isValid()) w->setFillColor(def_bg_color); else w->setFillColor(f->info()); QPen old_penstyle = w->get_painter().pen(); w->get_painter().setPen(Qt::NoPen); (*w) << pgn ; // draw the polyong w->setFilled(false); w->get_painter().setPen(old_penstyle); } else { Coord_point points[4]; points[0] = (Coord_point(w->x_min(),w->y_min())); points[1] = (Coord_point(w->x_min(),w->y_max())); points[2] = (Coord_point(w->x_max(),w->y_max())); points[3] = (Coord_point(w->x_max(),w->y_min())); w->setFilled(true); w->setFillColor(w->unbounded_face_color()); QPen old_penstyle = w->get_painter().pen(); w->get_painter().setPen(Qt::NoPen); (*w)<setFilled(false); w->get_painter().setPen(old_penstyle); } } /*! draw_xcurve - go over the polyline parts and use Qt_Widget operator * to draw */ void draw_xcurve(Qt_widget_demo_tab * w , Xcurve pol ) { Curve::const_iterator ps = pol.begin(); Curve::const_iterator pt = ps; pt++; while (pt != pol.end()) { const Pm_point_2 & source = *ps; const Pm_point_2 & target = *pt; Coord_segment coord_seg = convert(source , target); *w << coord_seg; ps++; pt++; } } /*! first_point - a first point of inserted polyline or a splitter */ void first_point( Coord_point p , Mode m) { last_of_poly = p; if (m == INSERT) points.push_back(Pm_pol_point_2(p.x(),p.y())); } /*! middle_point - a middle point of a polyline */ void middle_point( Coord_point p , Qt_widget_demo_tab * w) { if (last_of_poly == p) return; rubber_old = p; points.push_back(Pm_pol_point_2(p.x(),p.y())); *w << CGAL::WHITE; *w << Coord_segment(rubber, last_of_poly); *w << CGAL::GREEN; *w << Coord_segment(rubber, last_of_poly); last_of_poly = p; } /*! last_point - last point of the polyline, create new * polyline and reset */ void last_point( Coord_point p ,Qt_widget_demo_tab * w) { get_polyline(w); points.clear(); w->active = false; w->first_time = true; //w->redraw(); // not working so I use new_object insted w->new_object(make_object(Coord_segment(p , p))); } /*! curve_point_distance - return the distance between a point * and a polyline */ Coord_type curve_point_distance(Coord_point p, Curve * c , Qt_widget_demo_tab * w) { Curve_const_iterator ps = c->begin(); Curve_const_iterator pt = ps; pt++; bool first = true; Coord_type min_dist = 0; while (pt != c->end()) { const Pm_point_2 & source = *ps; const Pm_point_2 & target = *pt; Coord_segment coord_seg = convert(source , target); Coord_type dist = CGAL::squared_distance( p, coord_seg); if( dist < min_dist || first) { first = false; min_dist = dist; } ps++; pt++; } return min_dist; } /*! xcurve_point_distance - return the distance between a point * and a polyline */ Coord_type xcurve_point_distance(Coord_point p, Xcurve & c, Qt_widget_demo_tab * w) { Curve_const_iterator ps = c.begin(); Curve_const_iterator pt = ps; pt++; bool first = true; Coord_type min_dist = 0; while (pt != c.end()) { const Pm_point_2 & source = *ps; const Pm_point_2 & target = *pt; Coord_segment coord_seg = convert(source , target); Coord_type dist = CGAL::squared_distance( p, coord_seg); if( dist < min_dist || first) { first = false; min_dist = dist; } ps++; pt++; } return min_dist; } /*! draw_last_segment - call from mouse move event */ void draw_last_segment( Qt_widget_demo_tab * w) { *w << Coord_segment(rubber_old, last_of_poly); } /*! draw_current_segment - call from mouse move event */ void draw_current_segment( Coord_point p , Qt_widget_demo_tab * w) { *w << Coord_segment(p, last_of_poly); rubber = p; rubber_old = p; } /*! closest_point - find the closest point in the planar map * to a clicked point */ Coord_type closest_point(Coord_type x, Coord_type y, Coord_point &closest, Qt_widget_demo_tab * w) { bool first = true; Coord_type x1,y1,dt,min_dist = 0; Halfedge_iterator heit; for (heit = w->m_curves_arr->halfedges_begin(); heit != w->m_curves_arr->halfedges_end(); heit++) { const Xcurve& curve = heit->curve(); Curve_const_iterator cit; for (cit = curve.begin(); cit != curve.end(); cit++) { const Pm_point_2& p = *cit; x1 = CGAL::to_double(p.x()); y1 = CGAL::to_double(p.y()); dt = w->dist(x1 , y1 , x , y); if ( dt < min_dist || first) { min_dist = dt; closest = Coord_point(x1 , y1); first = false; } } } Point_vector_iterator it; for (it = points.begin(); it != points.end(); it++) { const Pm_pol_point_2& p = *it; x1 = CGAL::to_double(p.x()); y1 = CGAL::to_double(p.y()); dt = w->dist(x1 , y1 , x , y); if ( dt < min_dist || first) { min_dist = dt; closest = Coord_point(x1 , y1); first = false; } } return min_dist; } /*! get_origin_curve - return the origin base curve */ const Pm_base_pol_2* get_origin_curve(const Pm_xpol_2 & xseg ) { const Curve_pol_data & curve_data = xseg.get_data(); if (curve_data.m_type == Curve_pol_data::LEAF) return curve_data.m_ptr.m_curve; else // curve_data.m_type == Curve_data::INTERNAL { const Pm_xpol_2* xseg_p = curve_data.m_ptr.m_x_motonote_curve; return get_origin_curve( *xseg_p ); } } /*! curve_make_x_monotone */ const Xcurve curve_make_x_monotone(Pm_point_2 p1 , Pm_point_2 p2) { std::vector temp_points; temp_points.push_back(p1); temp_points.push_back(p2); Data d; Curve cv(Base_curve(temp_points.begin(), temp_points.end() ) , d); std::list xcurve_list; m_traits.curve_make_x_monotone(cv, std::back_inserter(xcurve_list)); const Xcurve c1 = xcurve_list.front(); return c1; } /*! */ void find_close_curve(Halfedge_iterator & closest_curve, Halfedge_iterator & second_curve, Coord_point & p, Qt_widget_demo_tab * w, bool move_event) { bool is_first = true; Coord_type min_dist = 0; Halfedge_iterator hei; Pm_point_2 s; Pm_point_2 t; Vertex_iterator vis; Vertex_iterator vit; if (closest_curve->source()->point() == *(closest_curve->curve().begin())) { vis = closest_curve->source(); vit = closest_curve->target(); } else { vit = closest_curve->source(); vis = closest_curve->target(); } s = *(closest_curve->curve().begin()); t = *(closest_curve->curve().rbegin()); for (hei = w->m_curves_arr->halfedges_begin(); hei != w->m_curves_arr->halfedges_end(); ++hei) { Pm_point_2 s1 = *(hei->curve().begin()); Pm_point_2 t1 = *(hei->curve().rbegin()); if (merge_segments_precondition(s, t, s1, t1, vis->degree(), vit->degree())) { Xcurve & xcurve = hei->curve(); Coord_type dist = xcurve_point_distance( p, xcurve , w); if (is_first || dist < min_dist) { min_dist = dist; second_curve = hei; is_first = false; } } } if (is_first) // didn't find any "good" curve return; else if (!move_event) { Xcurve & c = closest_curve->curve(); Xcurve & c1 = second_curve->curve(); Pm_point_2 s1 = *(second_curve->curve().begin()); Pm_point_2 t1 = *(second_curve->curve().rbegin()); std::vector temp_points; Curve_const_iterator cit; if (t == s1 || t == t1) { for (cit = c.begin(); cit != c.end(); cit++) { temp_points.push_back(*cit); } } else { for (cit = c.rbegin(); cit != c.rend(); cit++) { temp_points.push_back(*cit); } } Kernel ker; if (ker.compare_slope_2_object()(Kernel::Segment_2 (s, t), Kernel::Segment_2 (s1, t1)) == CGAL::EQUAL) { temp_points.pop_back(); } if (s1 == s || s1 == t) { cit = c1.begin(), cit++; for ( ; cit != c1.end(); cit++) { temp_points.push_back(*cit); } } else { cit = c1.rbegin(), cit++; for (; cit != c1.rend(); cit++) { temp_points.push_back(*cit); } } Base_curve *base = new Base_curve(temp_points.begin(), temp_points.end()); Curve_pol_data cd; cd.m_type = Curve_pol_data::LEAF; cd.m_index = w->index; cd.m_ptr.m_curve = base; Curve *curve = new Curve( *base, cd ); std::list xcurve_list; m_traits.curve_make_x_monotone(*curve, std::back_inserter(xcurve_list)); Xcurve cc = xcurve_list.front(); Halfedge_handle h = w->m_curves_arr->merge_edge(closest_curve , second_curve, cc); w->update_curve_data_after_merge(h , cc); } } /*! */ void split_edge(Halfedge_iterator &hei ,Pm_point_2 &p , Qt_widget_demo_tab *w) { Base_curve *base1 = new Base_curve; Base_curve *base2 = new Base_curve; Base_pol_traits base_pol_traits; base_pol_traits.curve_split (hei->curve(), *base1, *base2, p); std::list xcurve_list; //Base_curve *base1 = new Base_curve(temp_points1.begin(), // temp_points1.end()); Curve_pol_data cd1; cd1.m_type = Curve_pol_data::LEAF; cd1.m_index = hei->curve().get_data().m_index; cd1.m_ptr.m_curve = base1; Curve *seg1 = new Curve( *base1, cd1 ); m_traits.curve_make_x_monotone(*seg1, std::back_inserter(xcurve_list)); Xcurve c1 = xcurve_list.front(); xcurve_list.clear(); // Base_curve *base2 = new Base_curve(temp_points2.begin(), // temp_points2.end()); Curve_pol_data cd2; cd2.m_type = Curve_pol_data::LEAF; cd2.m_index = hei->curve().get_data().m_index; cd2.m_ptr.m_curve = base2; Curve *seg2 = new Curve( *base2, cd2 ); m_traits.curve_make_x_monotone(*seg2, std::back_inserter(xcurve_list)); Xcurve c2 = xcurve_list.front(); Halfedge_handle e1 = w->m_curves_arr->split_edge(hei , c1 , c2); w->update_curves_date_after_split(e1 , c1, c2); } private: /*! get_polyline - create a new polyline */ void get_polyline(Qt_widget_demo_tab * w) { Pol_notification pol_notif; Pm_base_pol_2 * base_pol_p = new Pm_base_pol_2(points.begin(), points.end()); Curve_pol_data cd; cd.m_type = Curve_pol_data::LEAF; cd.m_index = w->index; cd.m_ptr.m_curve = base_pol_p; Curve * pol = new Curve( *base_pol_p, cd ); w->m_curves_arr->insert( *pol , &pol_notif); CGAL::Bbox_2 curve_bbox = pol->bbox(); w->bbox = w->bbox + curve_bbox; } /*! convert - convert from Pm_pol_curve to Coord_segment */ Coord_segment convert(Pm_pol_point_2 & source , Pm_pol_point_2 & target) { Coord_type x1 = CGAL::to_double(source.x()); Coord_type y1 = CGAL::to_double(source.y()); Coord_point coord_source(x1, y1); Coord_type x2 = CGAL::to_double(target.x()); Coord_type y2 = CGAL::to_double(target.y()); Coord_point coord_target(x2, y2); return Coord_segment(coord_source, coord_target); } /*! convert - convert from const Pm_pol_curve to Coord_segment */ Coord_segment convert(const Pm_pol_point_2 & source , const Pm_pol_point_2 & target) { Coord_type x1 = CGAL::to_double(source.x()); Coord_type y1 = CGAL::to_double(source.y()); Coord_point coord_source(x1, y1); Coord_type x2 = CGAL::to_double(target.x()); Coord_type y2 = CGAL::to_double(target.y()); Coord_point coord_target(x2, y2); return Coord_segment(coord_source, coord_target); } Traits m_traits; /*! the new point of the rubber band */ Coord_point rubber; /*! the last point of the polygon */ Coord_point last_of_poly; /*! the old point of the rubber band */ Coord_point rubber_old; /*! container to hold the point during polyline creation */ std::vector points; }; ////////////////////////////////////////////////////////////////////////////// /*! */ class Conic_tab_traits { public: typedef Pm_xconic_list Curves_list; typedef Conic_arr Curves_arr; typedef Conic_traits Traits; typedef Pm_xconic_iter Pm_curve_iter; typedef Pm_xconic_const_iter Pm_curve_const_iter; typedef Conic_locate_type Locate_type; typedef Pm_conic_point_2 Pm_point_2; typedef Conic_halfedge_handle Halfedge_handle; typedef Pm_xconic_2 Curve; typedef Pm_xconic_2 Xcurve; typedef Pm_base_conic_2 Base_curve; typedef Conic_face_handle Face_handle; typedef Conic_ccb_halfedge_circulator Ccb_halfedge_circulator; typedef Conic_holes_iterator Holes_iterator; typedef Conic_pm::Halfedge_iterator Halfedge_iterator; typedef std::list Hafledge_list; typedef Hafledge_list::iterator Hafledge_list_iterator; typedef Conic_pm Pm; typedef Curves_arr::Vertex_iterator Vertex_iterator; typedef Curves_arr::Halfedge_around_vertex_circulator Halfedge_around_vertex_circulator; typedef Curves_arr::Edge_iterator Edge_iterator; typedef Curve_conic_data Data; typedef Conic_halfedge Halfedge; typedef Conic_face_iterator Face_iterator; //point location typedef Conic_trap_point_location Trap_point_location; typedef Conic_naive_point_location Naive_point_location; typedef Conic_simple_point_location Simple_point_location; typedef Conic_walk_point_location Walk_point_location; //typedef Conic_lenmarks_point_location Lenmarks_point_location; /*! coordinate scale - used in conics*/ int COORD_SCALE; int DRAW_FACTOR; /*! constructor */ Conic_tab_traits(): COORD_SCALE(1), DRAW_FACTOR(5) {} /*! distructor */ ~Conic_tab_traits() {} /*! curve_has_same_direction - return true if the curve and * the halfedge has the same direction */ bool curve_has_same_direction( Ccb_halfedge_circulator &cc) { return (cc->curve().source() == cc->source()->point()); } /*! check if curve and its halfedge are at the same direction */ bool is_curve_and_halfedge_same_direction(const Halfedge_handle & he, const Xcurve & cv) { return (he->source()->point() == cv.source()); } /*! */ void fill_face(Qt_widget_demo_tab * w , Face_handle f) { if (f->does_outer_ccb_exist()) // f is not the unbounded face { std::list< Coord_point > pts; // holds the points of the polygon /* running with around the outer of the face and generate from it * polygon */ Ccb_halfedge_circulator cc=f->outer_ccb(); do { if(w->antenna(*cc)) continue; Xcurve c = cc->curve(); // Get the co-ordinates of the curve's source and target. double sx = CGAL::to_double(cc->source()->point().x()), sy = CGAL::to_double(cc->source()->point().y()), tx = CGAL::to_double(cc->target()->point().x()), ty = CGAL::to_double(cc->target()->point().y()); Coord_point coord_source(sx / COORD_SCALE, sy / COORD_SCALE); Coord_point coord_target(tx / COORD_SCALE, ty / COORD_SCALE); if (c.is_segment()) pts.push_back(coord_source ); else { // If the curve is monotone, than its source and its target has the // extreme x co-ordinates on this curve. if (c.is_x_monotone()) { bool is_source_left = (sx < tx); int x_min = is_source_left ? (*w).x_pixel(sx) : (*w).x_pixel(tx); int x_max = is_source_left ? (*w).x_pixel(tx) : (*w).x_pixel(sx); double curr_x, curr_y; int x; Pm_conic_point_2 ps[2]; int nps; pts.push_back(coord_source ); if (is_source_left) { for (x = x_min + DRAW_FACTOR; x < x_max; x+=DRAW_FACTOR) //= COORD_SCALE) { curr_x = (*w).x_real(x); nps = c.get_points_at_x(Pm_conic_point_2(curr_x, 0), ps); if (nps == 1) { curr_y = CGAL::to_double(ps[0].y()); pts.push_back(Coord_point(curr_x / COORD_SCALE, curr_y / COORD_SCALE)); }// if }// for } else { for (x = x_max; x > x_min; x-=DRAW_FACTOR) { curr_x = (*w).x_real(x); nps = c.get_points_at_x(Pm_conic_point_2(curr_x, 0), ps); if (nps == 1) { curr_y = CGAL::to_double(ps[0].y()); pts.push_back(Coord_point(curr_x / COORD_SCALE, curr_y / COORD_SCALE)); }// if }// for }// else pts.push_back(coord_target ); }// if else { // We should never reach here. CGAL_assertion(false); }// else }// else //created from the outer boundary of the face } while (++cc != f->outer_ccb()); // make polygon from the outer ccb of the face 'f' Polygon pgn (pts.begin() , pts.end()); QPen old_penstyle = w->get_painter().pen(); w->get_painter().setPen(Qt::NoPen); w->setFilled(true); // fill the face according to its color (stored at any of her incidents // curves) if (! f->info().isValid()) w->setFillColor(def_bg_color); else w->setFillColor(f->info()); (*w) << pgn ; // draw the polyong w->get_painter().setPen(old_penstyle); w->setFilled(false); } else { Coord_point points[4]; points[0] = (Coord_point(w->x_min(),w->y_min())); points[1] = (Coord_point(w->x_min(),w->y_max())); points[2] = (Coord_point(w->x_max(),w->y_max())); points[3] = (Coord_point(w->x_max(),w->y_min())); w->setFilled(true); w->setFillColor(w->unbounded_face_color()); QPen old_penstyle = w->get_painter().pen(); w->get_painter().setPen(Qt::NoPen); (*w)<setFilled(false); w->get_painter().setPen(old_penstyle); } } /*! draw_xcurve - same as draw_curve */ void draw_xcurve(Qt_widget_demo_tab * w , Xcurve c ) { // Get the co-ordinates of the curve's source and target. double sx = CGAL::to_double(c.source().x()), sy = CGAL::to_double(c.source().y()), tx = CGAL::to_double(c.target().x()), ty = CGAL::to_double(c.target().y()); if (c.is_segment()) { Coord_point coord_source(sx / COORD_SCALE, sy / COORD_SCALE); Coord_point coord_target(tx / COORD_SCALE, ty / COORD_SCALE); Coord_segment coord_seg(coord_source, coord_target); *w << coord_seg; } else { // If the curve is monotone, than its source and its target has the // extreme x co-ordinates on this curve. if (c.is_x_monotone()) { bool is_source_left = (sx < tx); int x_min = is_source_left ? (*w).x_pixel(sx) : (*w).x_pixel(tx); int x_max = is_source_left ? (*w).x_pixel(tx) : (*w).x_pixel(sx); double prev_x = is_source_left ? sx : tx; double prev_y = is_source_left ? sy : ty; double end_x = is_source_left ? tx : sx; double end_y = is_source_left ? ty : sy; double curr_x, curr_y; int x; Pm_conic_point_2 ps[2]; int nps; for (x = x_min + DRAW_FACTOR; x < x_max; x+=DRAW_FACTOR) { curr_x = (*w).x_real(x); nps = c.get_points_at_x(Pm_conic_point_2(curr_x, 0), ps); if (nps == 1) { curr_y = CGAL::to_double(ps[0].y()); (*w) << Coord_segment (Coord_point(prev_x / COORD_SCALE, prev_y / COORD_SCALE), Coord_point(curr_x / COORD_SCALE, curr_y / COORD_SCALE)); prev_x = curr_x; prev_y = curr_y; } } (*w) << Coord_segment (Coord_point(prev_x / COORD_SCALE, prev_y / COORD_SCALE), Coord_point(end_x / COORD_SCALE, end_y / COORD_SCALE)); } else { // We should never reach here. CGAL_assertion(false); } } } /*! get_origin_curve - return the origin base curve */ const Pm_base_conic_2* get_origin_curve(const Pm_xconic_2 & xseg ) { const Curve_conic_data & curve_data = xseg.get_data(); if (curve_data.m_type == Curve_conic_data::LEAF) return curve_data.m_ptr.m_curve; else // curve_data.m_type == Curve_data::INTERNAL { Pm_xconic_2* xseg_p = curve_data.m_ptr.m_x_motonote_curve; return get_origin_curve( *xseg_p ); } } //////////////////////////////////////////////////////////////////////////// /*! first_point - a first point of inserted sgment */ void first_point( Coord_point p , Mode m) { m_p_old = m_p1 = m_p2 = m_p3 = m_p4 = p; num_points = 1; first_time = true; } /*! middle_point - the last point of a segment */ void middle_point( Coord_point p , Qt_widget_demo_tab * w) { CfNT r, s, t, u, v, ww; // The conic coefficients. CfNT a, b, c, a_sq, b_sq; CfNT x, y, x1, y1, x0, y0, temp; CfNT sq_rad; x1 = CfNT(static_cast(COORD_SCALE * m_p1.x())); y1 = CfNT(static_cast(COORD_SCALE * m_p1.y())); x = CfNT(static_cast(COORD_SCALE * p.x())); y = CfNT(static_cast(COORD_SCALE * p.y())); if(x != x1 || y != y1) { Pm_base_conic_2 *cv = NULL; switch (w->conic_type) { case CIRCLE: sq_rad = CGAL::square(x - x1) + CGAL::square(y - y1); cv = new Pm_base_conic_2(Int_circle_2 (Int_point_2(x1, y1), sq_rad)); break; case SEGMENT: cv = new Pm_base_conic_2(Int_segment_2 (Int_point_2(x,y), Int_point_2(x1,y1))); break; case ELLIPSE: if (y == y1 || x == x1) { QMessageBox::information( w, "Insert Ellipse", "Invalid Ellipse"); w->active = false; return; } a = CORE::abs(x1 - x)/2; b = CORE::abs(y1 - y)/2; a_sq = a*a; b_sq = b*b; x0 = (x + x1)/2; y0 = (y + y1)/2; r = b_sq; s = a_sq; t = 0; u = -2*x0*b_sq; v = -2*y0*a_sq; ww = x0*x0*b_sq + y0*y0*a_sq - a_sq*b_sq; cv = new Pm_base_conic_2(r, s, t, u, v, ww); break; // RWRW: Do nothing ... case PARABOLA: *w << CGAL::LineWidth(3); if (num_points == 1) { m_p2 = p; num_points++; *w << m_p2; return; } if (num_points == 2) { CfNT x2 = CfNT(static_cast(COORD_SCALE * m_p2.x())); CfNT y2 = CfNT(static_cast(COORD_SCALE * m_p2.y())); Int_kernel ker; // the three points of the parabola cannot be collinear ( if (ker.collinear_2_object()(Int_point_2(x1,y1), Int_point_2(x,y),Int_point_2(x2,y2))) { QMessageBox::information( w, "Insert Conic", "Invalid Conic"); w->active = false; *w << m_p1 << m_p2 ; return; } cv = new Pm_base_conic_2 (Int_point_2(x1,y1),Int_point_2(x2,y2), Int_point_2(x,y)); } break; case HYPERBOLA: *w << CGAL::LineWidth(3); if (num_points == 1) { m_p2 = p; num_points++; *w << m_p2; return; } if (num_points == 2) { m_p3 = p; num_points++; *w << m_p3; return; } if (num_points == 3) { m_p4 = p; num_points++; *w << m_p4; return; } if (num_points == 4) { *w << p; CfNT x2 = CfNT(static_cast(COORD_SCALE * m_p2.x())); CfNT y2 = CfNT(static_cast(COORD_SCALE * m_p2.y())); CfNT x3 = CfNT(static_cast(COORD_SCALE * m_p3.x())); CfNT y3 = CfNT(static_cast(COORD_SCALE * m_p3.y())); CfNT x4 = CfNT(static_cast(COORD_SCALE * m_p4.x())); CfNT y4 = CfNT(static_cast(COORD_SCALE * m_p4.y())); cv = new Pm_base_conic_2 (Int_point_2(x1,y1),Int_point_2(x2,y2), Int_point_2(x3,y3),Int_point_2(x4,y4), Int_point_2(x,y)); if (! cv->is_valid()) { QMessageBox::information( w, "Insert Conic", "Invalid Conic"); w->active = false; *w << m_p1 << m_p2 << m_p3 << m_p4 << p; return; } } break; } Curve_conic_data cd; cd.m_type = Curve_conic_data::LEAF; cd.m_index = w->index; cd.m_ptr.m_curve = cv; Conic_notification conic_notif; w->m_curves_arr->insert(Pm_conic_2( *cv , cd), & conic_notif); CGAL::Bbox_2 curve_bbox = cv->bbox(); w->bbox = w->bbox + curve_bbox; w->active = false; //w->redraw(); // not working so I use new_object insted w->new_object(make_object(Coord_segment(m_p1 , p))); } } /*! last_point - meaningless for conics - at least for now */ void last_point( Coord_point p , Qt_widget_demo_tab * w ) { return; } /*! draw_last_segment - call from mouse move event */ void draw_last_segment( Qt_widget_demo_tab * w) { if (w->mode == SPLIT) *w << Coord_segment( m_p1 , m_p_old ); else { switch (w->conic_type) { case CIRCLE: *w << Coord_circle(m_p1, pow(m_p1.x() - m_p_old.x(), 2) + pow(m_p1.y() - m_p_old.y(),2)); break; case SEGMENT: *w << Coord_segment( m_p1 , m_p_old ); break; case ELLIPSE: { *w << Coord_segment( Coord_point(m_p1.x(),m_p_old.y()) , m_p_old ); *w << Coord_segment( Coord_point(m_p1.x(),m_p_old.y()) , m_p1 ); *w << Coord_segment( Coord_point(m_p_old.x(),m_p1.y()) , m_p_old ); *w << Coord_segment( Coord_point(m_p_old.x(),m_p1.y()) , m_p1 ); break; } case PARABOLA: if (first_time) { *w << CGAL::LineWidth(3); *w << m_p1; first_time = false; } break; case HYPERBOLA: if (first_time) { *w << CGAL::LineWidth(3); *w << m_p1; first_time = false; } break; } } } /*! draw_current_segment - call from mouse move event */ void draw_current_segment( Coord_point p , Qt_widget_demo_tab * w) { m_p_old = p; draw_last_segment(w); } /*! closest_point - find the closest point in the planar map * to a clicked point */ Coord_type closest_point(Coord_type x, Coord_type y, Coord_point &closest, Qt_widget_demo_tab * w) { bool first = true; Coord_type x1,y1,dt,min_dist = 0; //Coord_type x_scale = COORD_SCALE * x; //Coord_type y_scale = COORD_SCALE * y; Vertex_iterator vit; for (vit = w->m_curves_arr->vertices_begin(); vit != w->m_curves_arr->vertices_end(); vit++) { const Pm_point_2& p = (*vit).point(); x1 = CGAL::to_double(p.x()) / COORD_SCALE; y1 = CGAL::to_double(p.y()) / COORD_SCALE; dt = w->dist(x1 , y1 , x , y); if ( dt < min_dist || first) { min_dist = dt; closest = Coord_point(x1 , y1); first = false; } } return min_dist; } /*! curve_point_distance - return the distance between * a point and a conic */ Coord_type curve_point_distance(Coord_point p, Curve * c , Qt_widget_demo_tab * w) { // Get the co-ordinates of the curve's source and target. double sx = CGAL::to_double(c->source().x()), sy = CGAL::to_double(c->source().y()), tx = CGAL::to_double(c->target().x()), ty = CGAL::to_double(c->target().y()); if (c->is_segment()) { Coord_point coord_source(sx , sy); Coord_point coord_target(tx , ty); Coord_segment coord_seg(coord_source, coord_target); return CGAL::squared_distance( p, coord_seg); } else { // If the curve is monotone, than its source and its target has the // extreme x co-ordinates on this curve. if (c->is_x_monotone()) { bool is_source_left = (sx < tx); int x_min = is_source_left ? (*w).x_pixel(sx) : (*w).x_pixel(tx); int x_max = is_source_left ? (*w).x_pixel(tx) : (*w).x_pixel(sx); double prev_x = is_source_left ? sx : tx; double prev_y = is_source_left ? sy : ty; //double end_x = is_source_left ? tx : sx; //double end_y = is_source_left ? ty : sy; double curr_x, curr_y; int x; Pm_conic_point_2 ps[2]; int nps; bool first = true; Coord_type min_dist = 0; for (x = x_min + 1; x < x_max; x++) { curr_x = (*w).x_real(x); nps = c->get_points_at_x(Pm_conic_point_2(curr_x, 0), ps); if (nps == 1) { curr_y = CGAL::to_double(ps[0].y()); Coord_segment coord_seg( Coord_point(prev_x, prev_y) , Coord_point(curr_x, curr_y) ); Coord_type dist = CGAL::squared_distance( p, coord_seg); if( dist < min_dist || first) { first = false; min_dist = dist; } prev_x = curr_x; prev_y = curr_y; } } return min_dist; }// if is_x_monotone else { // We should never reach here. CGAL_assertion(false); return 0; } } // else } // /*! xcurve_point_distance - return the distance between * a point and a conic */ Coord_type xcurve_point_distance(Coord_point p, Xcurve & c , Qt_widget_demo_tab * w) { // Get the co-ordinates of the curve's source and target. double sx = CGAL::to_double(c.source().x()), sy = CGAL::to_double(c.source().y()), tx = CGAL::to_double(c.target().x()), ty = CGAL::to_double(c.target().y()); if (c.is_segment()) { Coord_point coord_source(sx , sy); Coord_point coord_target(tx , ty); Coord_segment coord_seg(coord_source, coord_target); return CGAL::squared_distance( p, coord_seg); } else { // If the curve is monotone, than its source and its target has the // extreme x co-ordinates on this curve. if (c.is_x_monotone()) { bool is_source_left = (sx < tx); int x_min = is_source_left ? (*w).x_pixel(sx) : (*w).x_pixel(tx); int x_max = is_source_left ? (*w).x_pixel(tx) : (*w).x_pixel(sx); double prev_x = is_source_left ? sx : tx; double prev_y = is_source_left ? sy : ty; double curr_x, curr_y; int x; Pm_conic_point_2 ps[2]; int nps; bool first = true; Coord_type min_dist = 100000000; for (x = x_min + 1; x < x_max; x++) { curr_x = (*w).x_real(x); nps = c.get_points_at_x(Pm_conic_point_2(curr_x, 0), ps); if (nps == 1) { curr_y = CGAL::to_double(ps[0].y()); Coord_segment coord_seg( Coord_point(prev_x, prev_y) , Coord_point(curr_x, curr_y) ); Coord_type dist = CGAL::squared_distance( p, coord_seg); if( dist < min_dist || first) { first = false; min_dist = dist; } prev_x = curr_x; prev_y = curr_y; } } return min_dist; }// if is_x_monotone else { // We should never reach here. CGAL_assertion(false); return 0; } } // else } // /*! curve_make_x_monotone */ const Xcurve curve_make_x_monotone(Pm_point_2 p1 , Pm_point_2 p2) { /*! */ Data d; // RWRW: Int_point_2 my_p1 (static_cast (CGAL::to_double(p1.x())), static_cast (CGAL::to_double(p1.y()))); Int_point_2 my_p2 (static_cast (CGAL::to_double(p2.x())), static_cast (CGAL::to_double(p2.y()))); Pm_base_conic_2 base (Int_segment_2 (my_p1, my_p2)); // Pm_base_conic_2 base(Pm_conic_segment_2(p1 , p2)); const Pm_conic_2 cv( base , d); std::list xcurve_list; m_traits.curve_make_x_monotone(cv, std::back_inserter(xcurve_list)); const Xcurve c1 = xcurve_list.front(); return c1; } /*! */ void find_close_curve(Halfedge_iterator & closest_curve, Halfedge_iterator & second_curve, Coord_point & p, Qt_widget_demo_tab * w, bool move_event) { bool is_first = true; Coord_type min_dist = 0; const Xcurve first = closest_curve->curve(); Halfedge_iterator hei; Pm_point_2 s = closest_curve->curve().source(); Pm_point_2 t = closest_curve->curve().target(); Vertex_iterator vis; Vertex_iterator vit; if ( closest_curve->curve().source() == closest_curve->source()->point()) { vis = closest_curve->source(); vit = closest_curve->target(); } else { vit = closest_curve->source(); vis = closest_curve->target(); } for (hei = w->m_curves_arr->halfedges_begin(); hei != w->m_curves_arr->halfedges_end(); ++hei) { if (first.has_same_base_conic(hei->curve())) { Pm_point_2 s1 = hei->curve().source(); Pm_point_2 t1 = hei->curve().target(); if( merge_segments_precondition(s,t, s1,t1, vis->degree(), vit->degree())) { Xcurve & xcurve = hei->curve(); Coord_type dist = xcurve_point_distance( p, xcurve , w); if (is_first || dist < min_dist) { min_dist = dist; second_curve = hei; is_first = false; } } } } if (is_first) // didn't find any "good" curve return; else if (!move_event) { Xcurve curve; const Xcurve second = second_curve->curve(); m_traits.curve_merge (first, second, curve); Curve_conic_data cd1; cd1.m_type = Curve_conic_data::LEAF; cd1.m_index = first.get_data().m_index; cd1.m_ptr.m_curve = first.get_data().m_ptr.m_curve; Conic_notification conic_notif; // save the colors of the incident faces (to restore them later) QColor color1 = closest_curve->face()->info(); QColor color2 = closest_curve->opposite()->face()->info(); Pm_point_2 closest_curve_source = closest_curve->source()->point(); Pm_point_2 closest_curve_target = closest_curve->target()->point(); w->m_curves_arr->remove_edge(closest_curve); w->m_curves_arr->remove_edge(second_curve); Pm_conic_2 c( curve , cd1); Halfedge_handle h = w->m_curves_arr->insert(c ); //restore the color of the incident faces of 'h' //check that 'closest_curev' and 'h' are at the dame direction if(closest_curve_source == h->source()->point() || closest_curve_target == h->target()->point() ) { h->face()->set_info(color1); h->opposite()->face()->set_info(color2); } else { h->face()->set_info(color2); h->opposite()->face()->set_info(color1); } Data d = c.get_data(); if(is_curve_and_halfedge_same_direction(h , curve)) d.halfedge_handle = h; else d.halfedge_handle = (Halfedge_handle)h->opposite(); h->curve().set_data( d ); h->opposite()->curve().set_data( d ); //w->update_curve_data_after_merge(h , c); //// update c // // Curve_conic_data d = c.get_data(); //d.halfedge_handle = h; //h->curve().set_data( d ); //h->opposite()->curve().set_data( d ); } } /*! */ void split_edge(Halfedge_iterator &hei ,Pm_point_2 & p, Qt_widget_demo_tab * w) { const Xcurve split_curve = hei->curve(); Xcurve sbc1; Xcurve sbc2; m_traits.curve_split(split_curve , sbc1 , sbc2 , p); Curve_conic_data cd1; cd1.m_type = Curve_conic_data::LEAF; cd1.m_index = hei->curve().get_data().m_index; cd1.m_ptr.m_curve = hei->curve().get_data().m_ptr.m_curve; Pm_conic_2 sub_curve1 (sbc1, cd1); Curve_conic_data cd2; cd2.m_type = Curve_conic_data::LEAF; cd2.m_index = hei->curve().get_data().m_index; cd2.m_ptr.m_curve =hei->curve().get_data().m_ptr.m_curve; Pm_conic_2 sub_curve2 (sbc2, cd2); Conic_notification conic_notif; // w->m_curves_arr->remove_edge(hei); Halfedge_handle h1 = w->m_curves_arr->insert(sub_curve1 , & conic_notif); Halfedge_handle h2 = w->m_curves_arr->insert(sub_curve2 , & conic_notif); // // w->update_curves_date_after_split(hei , sub_curve1, sub_curve2); //// update data // // Curve_conic_data d1 = sub_curve1.get_data(); //d1.halfedge_handle = h1; //h1->curve().set_data( d1 ); //h1->opposite()->curve().set_data( d1 ); // Curve_conic_data d2 = sub_curve2.get_data(); //d2.halfedge_handle = h2; //h2->curve().set_data( d2 ); //h2->opposite()->curve().set_data( d2 ); } Traits m_traits; /*! temporary points of the created conic */ Coord_point m_p_old,m_p1,m_p2,m_p3,m_p4; /*! bool flag for hyperbola insertion */ bool first_time; /*! counter for the number of points */ int num_points; }; typedef Qt_widget_demo_tab Qt_widget_segment_tab; typedef Qt_widget_demo_tab Qt_widget_polyline_tab; typedef Qt_widget_demo_tab Qt_widget_conic_tab; #endif //DEMO_TAB_H