/// <summary> /// コンストラクタ、比較インターフェースと初期項目を指定して初期化する /// </summary> /// <param name="comparer">比較インターフェース</param> /// <param name="capacity">初期キャパシティ</param> /// <param name="initialValues">初期項目</param> public PriorityQueue(IComparer <T> comparer, int capacity, IEnumerable <T> initialValues) { _List = capacity != 0 ? new FList <T>(capacity) : new FList <T>(); _Comparer = comparer; if (initialValues != null) { _List.AddRange(initialValues); } UpdateHeap(); }
/** * \brief Merge a set of holes into a polygon. (templated) * * Take a polygon loop and a collection of hole loops, and patch * the hole loops into the polygon loop, returning a vector of * vertices from the polygon and holes, which describes a new * polygon boundary with no holes. The new polygon boundary is * constructed via the addition of edges * joining the polygon * loop to the holes. * * This may be applied to arbitrary vertex data (generally * carve::geom3d::Vertex pointers), but a projection function must * be supplied to convert vertices to coordinates in 2-space, in * which the work is performed. * * @tparam project_t A functor which converts vertices to a 2d * projection. * @tparam vert_t The vertex type. * @param project The projection functor. * @param f_loop The polygon loop into which holes are to be * incorporated. * @param h_loops The set of hole loops to be incorporated. * * @return A vector of vertex pointers. */ public static FList <T> incorporateHolesIntoPolygon <T>(Project <T> project, FList <T> f_loop, FList <FList <T> > h_loops) { var N = f_loop.Count; // work out how much space to reserve for the patched in holes. for (int i = h_loops.Count - 1; i != -1; i--) { N += 2 + h_loops[i].Count; } // this is the vector that we will build the result in. var current_f_loop = new FList <T>(N); current_f_loop.AddRange(f_loop); var h_loop_min_vertex = new FList <Iterator <T> >(h_loops.Count); // find the major axis for the holes - this is the axis that we // will sort on for finding vertices on the polygon to join // holes up to. // // it might also be nice to also look for whether it is better // to sort ascending or descending. // // another trick that could be used is to modify the projection // by 90 degree rotations or flipping about an axis. just as // long as we keep the carve::geom3d::Vector pointers for the // real data in sync, everything should be ok. then we wouldn't // need to accomodate axes or sort order in the main loop. // find the bounding box of all the holes. bool first = true; element min_x = element.MaxValue, min_y = element.MaxValue, max_x = element.MinValue, max_y = element.MinValue; for (int i = h_loops.Count - 1; i != -1; i--) { var hole = h_loops[i]; for (int j = hole.Count - 1; j != -1; j--) { var curr = project(hole[j]); if (first) { min_x = max_x = curr.X; min_y = max_y = curr.Y; first = false; } else { if (curr.X < min_x) { min_x = curr.X; } if (curr.Y < min_y) { min_y = curr.Y; } if (max_x < curr.X) { max_x = curr.X; } if (max_y < curr.Y) { max_y = curr.Y; } } } } // choose the axis for which the bbox is largest. int axis = (max_x - min_x) > (max_y - min_y) ? 0 : 1; // for each hole, find the minimum vertex in the chosen axis. for (int i = 0, n = h_loops.Count; i < n; i++) { var hole = h_loops[i]; var best_i = MinElementIndex(hole, new order_h_loops <T>(project, axis)); h_loop_min_vertex.Add(new Iterator <T>(hole, best_i)); } // sort the holes by the minimum vertex. h_loop_min_vertex.Sort(new order_h_loops_iterator <T>(project, axis)); // now, for each hole, find a vertex in the current polygon loop that it can be joined to. for (int i = 0; i < h_loop_min_vertex.Count; ++i) { var N_f_loop = current_f_loop.Count; // the index of the vertex in the hole to connect. var h_loop_connect = h_loop_min_vertex[i].value; var hole_min = project(h_loop_connect); // we order polygon loop vertices that may be able to be connected // to the hole vertex by their distance to the hole vertex var f_loop_heap = new PriorityQueue <int>(new heap_ordering <T>(project, current_f_loop, h_loop_connect, axis), N); for (int j = 0; j < N_f_loop; ++j) { // it is guaranteed that there exists a polygon vertex with // coord < the min hole coord chosen, which can be joined to // the min hole coord without crossing the polygon // boundary. also, because we merge holes in ascending // order, it is also true that this join can never cross // another hole (and that doesn't need to be tested for). if (project(current_f_loop[j])[axis] <= hole_min[axis]) { f_loop_heap.Push(j); } } // we are going to test each potential (according to the // previous test) polygon vertex as a candidate join. we order // by closeness to the hole vertex, so that the join we make // is as small as possible. to test, we need to check the // joining line segment does not cross any other line segment // in the current polygon loop (excluding those that have the // vertex that we are attempting to join with as an endpoint). var attachment_point = current_f_loop.Count; while (f_loop_heap.Count != 0) { var curr = f_loop_heap.Pop(); // test the candidate join from current_f_loop[curr] to hole_min if (!testCandidateAttachment(project, current_f_loop, curr, hole_min)) { continue; } attachment_point = curr; break; } if (attachment_point == current_f_loop.Count) { throw new ApplicationException("didn't manage to link up hole!"); } patchHoleIntoPolygon(current_f_loop, attachment_point, h_loop_min_vertex[i]); } return(current_f_loop); }