Esempio n. 1
0
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;
}
Esempio n. 2
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_);
}
Esempio n. 3
0
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_);
}
Esempio n. 4
0
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);
}
Esempio n. 5
0
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);
}
Esempio n. 6
0
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;
}