int main() { Hashtable<int, int> hashtable; for (int i = 0; i < 100; i++) { hashtable.set(string("k") + to_string(i), i); } for (int i = 0; i < 100; i++) { hashtable.set(string("k") + to_string(i), 100); } for (int i = 0; i < 100; i++) { cout << i << ": " << hashtable.get(string("k") + to_string(i)) << endl; } return 0; }
Ref<SparseMatrix> TriangleSubdivision::loop_matrix() const { if (loop_matrix_) return ref(loop_matrix_); // Build matrix of Loop subdivision weights Hashtable<Vector<int,2>,T> A; int offset = coarse_mesh->nodes(); RawArray<const Vector<int,2> > segments = coarse_mesh->segment_soup()->elements; Nested<const int> neighbors = coarse_mesh->sorted_neighbors(); Nested<const int> boundary_neighbors = coarse_mesh->boundary_mesh()->neighbors(); unordered_set<int> corners_set(corners.begin(),corners.end()); // Fill in node weights for (int i=0;i<offset;i++){ if (!neighbors.valid(i) || !neighbors.size(i) || corners_set.count(i) || (boundary_neighbors.valid(i) && boundary_neighbors.size(i) && boundary_neighbors.size(i)!=2)) A.set(vec(i,i),1); else if (boundary_neighbors.valid(i) && boundary_neighbors.size(i)==2) { // Regular boundary node A.set(vec(i,i),(T).75); for (int a=0;a<2;a++) A.set(vec(i,boundary_neighbors(i,a)),(T).125); } else { // Interior node RawArray<const int> ni = neighbors[i]; T alpha = new_loop_alpha(ni.size()); A.set(vec(i,i),alpha); T other = (1-alpha)/ni.size(); for (int j : ni) A.set(vec(i,j),other); } } // Fill in edge values for (int s=0;s<segments.size();s++) { int i = offset+s; Vector<int,2> e = segments[s]; RawArray<const int> n[2] = {neighbors.valid(e[0])?neighbors[e[0]]:RawArray<const int>(), neighbors.valid(e[1])?neighbors[e[1]]:RawArray<const int>()}; if (boundary_neighbors.valid(e[0]) && boundary_neighbors.valid(e[1]) && boundary_neighbors.size(e[0]) && boundary_neighbors.size(e[1]) && boundary_neighbors[e[0]].contains(e[1])) // Boundary edge for (int a=0;a<2;a++) A.set(vec(i,e[a]),(T).5); else if (n[0].size()==6 && n[1].size()==6) { // Edge between regular vertices int j = n[0].find(e[1]); int c[2] = {n[0][(j-1+n[0].size())%n[0].size()], n[0][(j+1)%n[0].size()]}; for (int a=0;a<2;a++) { A.set(vec(i,e[a]),(T).375); A.set(vec(i,c[a]),(T).125); } } else { // Edge between one or two irregular vertices T factor = n[0].size()!=6 && n[1].size()!=6 ?.5:1; for (int k=0;k<2;k++) if (n[k].size()!=6) { A[vec(i,e[k])] += factor*(1-new_loop_beta(n[k].size())); int start = n[k].find(e[1-k]); for (int j=0;j<n[k].size();j++) A[vec(i,n[k][(start+j)%n[k].size()])] += factor*new_loop_weight(n[k].size(),j); } } } // Finalize construction loop_matrix_ = new_<SparseMatrix>(A,vec(offset+segments.size(),offset)); return ref(loop_matrix_); }
Ref<SegmentSoup> PolygonSoup::segment_soup() const { if (!segment_soup_) { Hashtable<Vector<int,2>> hash; Array<Vector<int,2>> segments; int offset = 0; for (int p=0;p<counts.size();p++) { for (int i=0,j=counts[p]-1;i<counts[p];j=i,i++) { Vector<int,2> segment=vec(vertices[offset+i],vertices[offset+j]).sorted(); if(hash.set(segment)) segments.append(segment); } offset += counts[p]; } segment_soup_ = new_<SegmentSoup>(segments,nodes()); } return ref(segment_soup_); }
static void clean_evaluate(bool aggressive, int depth, board_t board) { check_board(board); symmetry_t symmetry; superstandardize(board).get(board,symmetry); if (known.contains(tuple(depth,board))) return; cout << "clean evaluate: depth "<<depth<<", board "<<board<<endl; clear_supertable(); const super_t all = ~super_t(0); const side_t side0 = unpack(board,0), side1 = unpack(board,1); auto data = super_shallow_evaluate(aggressive,depth,side0,side1,all); superinfo_t info = data.lookup.info; if (depth>=1) info = super_evaluate_recurse<false>(aggressive,depth,side0,side1,data,all); GEODE_ASSERT(info.known==all); known.set(tuple(depth,board),info); }
GEODE_NEVER_INLINE static void add_constraint_edges(MutableTriangleTopology& mesh, RawField<const EV,VertexId> X, RawArray<const Vector<int,2>> edges, const bool validate) { if (!edges.size()) return; IntervalScope scope; Hashtable<Vector<VertexId,2>> constrained; Array<VertexId> left_cavity, right_cavity; // List of vertices for both cavities const auto random = new_<Random>(key+7); for (int i=0;i<edges.size();i++) { // Randomly choose an edge to ensure optimal time complexity const auto edge = edges[int(random_permute(edges.size(),key+5,i))].sorted(); auto v0 = VertexId(edge.x), v1 = VertexId(edge.y); const auto vs = vec(v0,v1); GEODE_ASSERT(mesh.valid(v0) && mesh.valid(v1)); { // Check if the edge already exists in the triangulation. To ensure optimal complexity, // we loop around both vertices interleaved so that our time is O(min(degree(v0),degree(v1))). const auto s0 = mesh.halfedge(v0), s1 = mesh.halfedge(v1); { auto e0 = s0, e1 = s1; do { if (mesh.dst(e0)==v1 || mesh.dst(e1)==v0) goto success; // The edge already exists, so there's nothing to be done. e0 = mesh.left(e0); e1 = mesh.left(e1); } while (e0!=s0 && e1!=s1); } // Find a triangle touching v0 or v1 containing part of the v0-v1 segment. // As above, we loop around both vertices interleaved. auto e0 = s0; { auto e1 = s1; if (mesh.is_boundary(e0)) e0 = mesh.left(e0); if (mesh.is_boundary(e1)) e1 = mesh.left(e1); const auto x0 = Perturbed2(v0.id,X[v0]), x1 = Perturbed2(v1.id,X[v1]); const auto e0d = mesh.dst(e0), e1d = mesh.dst(e1); bool e0o = triangle_oriented(x0,Perturbed2(e0d.id,X[e0d]),x1), e1o = triangle_oriented(x1,Perturbed2(e1d.id,X[e1d]),x0); for (;;) { // No need to check for an end condition, since we're guaranteed to terminate const auto n0 = mesh.left(e0), n1 = mesh.left(e1); const auto n0d = mesh.dst(n0), n1d = mesh.dst(n1); const bool n0o = triangle_oriented(x0,Perturbed2(n0d.id,X[n0d]),x1), n1o = triangle_oriented(x1,Perturbed2(n1d.id,X[n1d]),x0); if (e0o && !n0o) break; if (e1o && !n1o) { // Swap v0 with v1 and e0 with e1 so that our ray starts at v0 swap(v0,v1); swap(e0,e1); break; } e0 = n0; e1 = n1; e0o = n0o; e1o = n1o; } } // If we only need to walk one step, the retriangulation is a single edge flip auto cut = mesh.reverse(mesh.next(e0)); if (mesh.dst(mesh.next(cut))==v1) { if (constrained.contains(vec(mesh.src(cut),mesh.dst(cut)).sorted())) throw DelaunayConstraintConflict(vec(v0.id,v1.id),vec(mesh.src(cut).id,mesh.dst(cut).id)); cut = mesh.flip_edge(cut); goto success; } // Walk from v0 to v1, collecting the two cavities. const auto x0 = Perturbed2(v0.id,X[v0]), x1 = Perturbed2(v1.id,X[v1]); right_cavity.copy(vec(v0,mesh.dst(cut))); left_cavity .copy(vec(v0,mesh.src(cut))); mesh.erase(mesh.face(e0)); for (;;) { if (constrained.contains(vec(mesh.src(cut),mesh.dst(cut)).sorted())) throw DelaunayConstraintConflict(vec(v0.id,v1.id),vec(mesh.src(cut).id,mesh.dst(cut).id)); const auto n = mesh.reverse(mesh.next(cut)), p = mesh.reverse(mesh.prev(cut)); const auto v = mesh.src(n); mesh.erase(mesh.face(cut)); if (v == v1) { left_cavity.append(v); right_cavity.append(v); break; } else if (triangle_oriented(x0,x1,Perturbed2(v.id,X[v]))) { left_cavity.append(v); cut = n; } else { right_cavity.append(v); cut = p; } } // Retriangulate both cavities left_cavity.reverse(); cavity_delaunay(mesh,X,left_cavity,random), cavity_delaunay(mesh,X,right_cavity,random); } success: constrained.set(vs); } // If desired, check that the final mesh is constrained Delaunay if (validate) assert_delaunay("constrained delaunay validate: ",mesh,X,constrained); }
Nested<EV> exact_split_polygons(Nested<const EV> polys, const int depth) { IntervalScope scope; RawArray<const EV> X = polys.flat; // We index segments by the index of their first point in X. For convenience, we make an array to keep track of wraparounds. Array<int> next = (arange(X.size())+1).copy(); for (int i=0;i<polys.size();i++) { GEODE_ASSERT(polys.size(i)>=3,"Degenerate polygons are not allowed"); next[polys.offsets[i+1]-1] = polys.offsets[i]; } // Compute all nontrivial intersections between segments struct Pairs { const BoxTree<EV>& tree; RawArray<const int> next; RawArray<const EV> X; Array<Vector<int,2>> pairs; Pairs(const BoxTree<EV>& tree, RawArray<const int> next, RawArray<const EV> X) : tree(tree), next(next), X(X) {} bool cull(const int n) const { return false; } bool cull(const int n0, const int box1) const { return false; } void leaf(const int n) const { assert(tree.prims(n).size()==1); } void leaf(const int n0, const int n1) { assert(tree.prims(n0).size()==1 && tree.prims(n1).size()==1); const int i0 = tree.prims(n0)[0], i1 = next[i0], j0 = tree.prims(n1)[0], j1 = next[j0]; if (!(i0==j0 || i0==j1 || i1==j0 || i1==j1)) { const auto a0 = Perturbed2(i0,X[i0]), a1 = Perturbed2(i1,X[i1]), b0 = Perturbed2(j0,X[j0]), b1 = Perturbed2(j1,X[j1]); if (segments_intersect(a0,a1,b0,b1)) pairs.append(vec(i0,j0)); } } }; const auto tree = new_<BoxTree<EV>>(segment_boxes(next,X),1); Pairs pairs(tree,next,X); double_traverse(*tree,pairs); // Group intersections by segment. Each pair is added twice: once for each order. Array<int> counts(X.size()); for (auto pair : pairs.pairs) { counts[pair.x]++; counts[pair.y]++; } Nested<int> others(counts,uninit); for (auto pair : pairs.pairs) { others(pair.x,--counts[pair.x]) = pair.y; others(pair.y,--counts[pair.y]) = pair.x; } pairs.pairs.clean_memory(); counts.clean_memory(); // Walk all original polygons, recording which subsegments occur in the final result Hashtable<Vector<int,2>,int> graph; // If (i,j) -> k, the output contains the portion of segment j from ij to jk for (const int p : range(polys.size())) { const auto poly = range(polys.offsets[p],polys.offsets[p+1]); // Compute the depth of the first point in the polygon by firing a ray along the positive x axis. struct Depth { const BoxTree<EV>& tree; RawArray<const int> next; RawArray<const EV> X; const Perturbed2 start; int depth; Depth(const BoxTree<EV>& tree, RawArray<const int> next, RawArray<const EV> X, const int prev, const int i) : tree(tree), next(next), X(X) , start(i,X[i]) // If we intersect no other segments, the depth depends on the orientation of direction = (1,0) relative to segments prev and i , depth(-!local_outwards_x_axis(Perturbed2(prev,X[prev]),start,Perturbed2(next[i],X[next[i]]))) {} bool cull(const int n) const { const auto box = tree.boxes(n); return box.max.x<start.value().x || box.max.y<start.value().y || box.min.y>start.value().y; } void leaf(const int n) { assert(tree.prims(n).size()==1); const int i0 = tree.prims(n)[0], i1 = next[i0]; if (start.seed()!=i0 && start.seed()!=i1) { const auto a0 = Perturbed2(i0,X[i0]), a1 = Perturbed2(i1,X[i1]); const bool above0 = upwards(start,a0), above1 = upwards(start,a1); if (above0!=above1 && above1==triangle_oriented(a0,a1,start)) depth += above1 ? 1 : -1; } } }; Depth ray(tree,next,X,poly.back(),poly[0]); single_traverse(*tree,ray); // Walk around the polygon, recording all subsegments at the desired depth int delta = ray.depth-depth; int prev = poly.back(); for (const int i : poly) { const int j = next[i]; const Vector<Perturbed2,2> segment(Perturbed2(i,X[i]),Perturbed2(j,X[j])); const auto other = others[i]; // Sort intersections along this segment if (other.size() > 1) { struct PairOrder { RawArray<const int> next; RawArray<const EV> X; const Vector<Perturbed2,2> segment; PairOrder(RawArray<const int> next, RawArray<const EV> X, const Vector<Perturbed2,2>& segment) : next(next), X(X), segment(segment) {} bool operator()(const int j, const int k) const { if (j==k) return false; const int jn = next[j], kn = next[k]; return segment_intersections_ordered(segment.x,segment.y, Perturbed2(j,X[j]),Perturbed2(jn,X[jn]), Perturbed2(k,X[k]),Perturbed2(kn,X[kn])); } }; sort(other,PairOrder(next,X,segment)); } // Walk through each intersection of this segment, updating delta as we go and remembering the subsegment if it has the right depth for (const int o : other) { if (!delta) graph.set(vec(prev,i),o); const int on = next[o]; delta += segment_directions_oriented(segment.x,segment.y,Perturbed2(o,X[o]),Perturbed2(on,X[on])) ? -1 : 1; prev = o; } if (!delta) graph.set(vec(prev,i),next[i]); // Advance to the next segment prev = i; } } // Walk the graph to produce output polygons Hashtable<Vector<int,2>> seen; Nested<EV,false> output; for (const auto& start : graph) if (seen.set(start.x)) { auto ij = start.x; for (;;) { const int i = ij.x, j = ij.y, in = next[i], jn = next[j]; output.flat.append(j==next[i] ? X[j] : segment_segment_intersection(Perturbed2(i,X[i]),Perturbed2(in,X[in]),Perturbed2(j,X[j]),Perturbed2(jn,X[jn]))); ij = vec(j,graph.get(ij)); if (ij == start.x) break; seen.set(ij); } output.offsets.append(output.flat.size()); } return output; }