Пример #1
0
 /**
  * This takes a complicated expression assumed to contain multiple instances of leafA and returns
  * the equivalent CSG expression involving just leafA.
  *
  * @param leafA
  * @return equivalent CSG expression involving just leafA
  */
 private RrCSG categorise(RrCSG leafA) {
   RrHalfPlane a = leafA.plane();
   Rr2Point an = a.normal();
   Rr2Point x = Rr2Point.add(a.pLine().origin(), an);
   if (value(x) <= 0) return leafA.complement();
   else return leafA;
 }
Пример #2
0
  /**
   * Replace duplicate of leaf with leaf itself TODO: this should also use known complements
   *
   * @param leaf
   * @param tolerance
   */
  private void replaceAllSameLeaves(RrCSG leaf, double tolerance) {
    int same;
    switch (op) {
      case LEAF:
      case NULL:
      case UNIVERSE:
        // System.out.println("replace_all_same_leaves(): at a leaf!");
        break;

      case UNION:
      case INTERSECTION:
        RrHalfPlane hp = leaf.hp;
        if (c1.op == RrCSGOp.LEAF) {
          same = RrHalfPlane.same(hp, c1.hp, tolerance);
          if (same == 0) c1 = leaf;
          if (same == -1) c1 = leaf.complement();
        } else c1.replaceAllSameLeaves(leaf, tolerance);

        if (c2.op == RrCSGOp.LEAF) {
          same = RrHalfPlane.same(hp, c2.hp, tolerance);
          if (same == 0) c2 = leaf;
          if (same == -1) c2 = leaf.complement();
        } else c2.replaceAllSameLeaves(leaf, tolerance);
        break;

      default:
        Debug.e("replace_all_same(): invalid operator.");
    }
  }
Пример #3
0
  /**
   * Convert to a string
   *
   * @param result
   * @param white
   * @return string representation
   */
  private String toString_r(String result, String white) {
    switch (op) {
      case LEAF:
        result = result + white + hp.toString() + "\n";
        break;

      case NULL:
        result = result + white + "0\n";
        break;

      case UNIVERSE:
        result = result + white + "U\n";
        break;

      case UNION:
        result = result + white + "+\n";
        white = white + " ";
        result = c1.toString_r(result, white);
        result = c2.toString_r(result, white);
        break;

      case INTERSECTION:
        result = result + white + "&\n";
        white = white + " ";
        result = c1.toString_r(result, white);
        result = c2.toString_r(result, white);
        break;

      default:
        Debug.e("toString_r(): invalid operator.");
    }
    return result;
  }
Пример #4
0
  /**
   * Prune the set to a box
   *
   * @param b
   * @return pruned box as new CSG object
   */
  public RrCSG prune(RrRectangle b) {
    RrCSG result = this;

    switch (op) {
      case LEAF:
        RrInterval i = hp.value(b);
        if (i.empty()) Debug.e("RrCSG.prune(RrBox): empty interval!");
        else if (i.neg()) result = universe();
        else if (i.pos()) result = nothing();
        break;

      case NULL:
      case UNIVERSE:
        break;

      case UNION:
        result = union(c1.prune(b), c2.prune(b));
        break;

      case INTERSECTION:
        result = intersection(c1.prune(b), c2.prune(b));
        break;

      default:
        Debug.e("RrCSG.prune(RrBox): dud op value!");
    }

    return result;
  }
Пример #5
0
  /**
   * The interval value of a box (analagous to point)
   *
   * @param b
   * @return value of a box
   */
  public RrInterval value(RrRectangle b) {
    RrInterval result;

    switch (op) {
      case LEAF:
        result = hp.value(b);
        break;

      case NULL:
        result = new RrInterval(1, 1.01); // Is this clever?  Or dumb?
        break;

      case UNIVERSE:
        result = new RrInterval(-1.01, -1); // Ditto.
        break;

      case UNION:
        result = RrInterval.min(c1.value(b), c2.value(b));
        break;

      case INTERSECTION:
        result = RrInterval.max(c1.value(b), c2.value(b));
        break;

      default:
        Debug.e("value(RrBox): invalid operator.");
        result = new RrInterval();
    }

    return result;
  }
Пример #6
0
  /**
   * "Potential" value of a point; i.e. a membership test -ve means inside; 0 means on the surface;
   * +ve means outside
   *
   * @param p
   * @return potential value of a point
   */
  public double value(Rr2Point p) {
    double result = 1;
    //		RrCSG c = leaf(p);
    switch (op) {
      case LEAF:
        result = hp.value(p);
        break;

      case NULL:
        result = 1;
        break;

      case UNIVERSE:
        result = -1;
        break;

      case UNION:
        result = Math.min(c1.value(p), c2.value(p));
        break;

      case INTERSECTION:
        result = Math.max(c1.value(p), c2.value(p));
        break;

      default:
        Debug.e("RrCSG.value(): dud operator.");
    }
    return result;
  }
Пример #7
0
  /**
   * Offset by a distance (+ve or -ve) TODO: this should keep track of complements
   *
   * @param d
   * @return offset CSG object by distance d
   */
  public RrCSG offset(double d) {
    RrCSG result;

    switch (op) {
      case LEAF:
        result = new RrCSG(hp.offset(d));
        break;

      case NULL:
      case UNIVERSE:
        result = this;
        break;

      case UNION:
        result = union(c1.offset(d), c2.offset(d));
        break;

      case INTERSECTION:
        result = intersection(c1.offset(d), c2.offset(d));
        break;

      default:
        Debug.e("offset(): invalid operator.");
        result = nothing();
    }
    return result;
  }
Пример #8
0
 /** Destroy me and all that I point to */
 public void destroy() {
   if (beingDestroyed) // Prevent infinite loop
   return;
   beingDestroyed = true;
   if (c1 != null) c1.destroy();
   c1 = null;
   if (c2 != null) c2.destroy();
   c2 = null;
   if (comp != null) comp.destroy();
   comp = null;
   if (hp != null) hp.destroy();
   hp = null;
   beingDestroyed = false;
 }
Пример #9
0
  /**
   * Lazy evaluation for complement.
   *
   * @return complement
   */
  public RrCSG complement() {
    if (comp != null) return comp;

    RrCSG result;

    switch (op) {
      case LEAF:
        result = new RrCSG(hp.complement());
        break;

      case NULL:
        return universe();

      case UNIVERSE:
        return nothing();

      case UNION:
        result = intersection(c1.complement(), c2.complement());
        break;

      case INTERSECTION:
        result = union(c1.complement(), c2.complement());
        break;

      default:
        Debug.e("complement(): invalid operator.");
        return nothing();
    }

    // Remember, so we don't have to do it again.
    // (I do hope that the Java garbage collector is up to
    // spotting this deadly embrace, or we - I mean it - has
    // a memory leak.)
    // It turned out it was dumb.  Hence addition of destroy() above...

    comp = result;
    result.comp = this;

    return comp;
  }
Пример #10
0
  /**
   * This takes a complicated expression assumed to contain multiple instances of leafA and leafB
   * and returns the equivalent CSG expression involving at most leafA and leafB once (except for
   * non-manifold shapes).
   *
   * @param leafA
   * @param leafB
   * @return equivalent CSG expression involving at most leafA and leafB once
   */
  private RrCSG crossCategorise(RrCSG leafA, RrCSG leafB) {
    RrHalfPlane a = leafA.plane();
    RrHalfPlane b = leafB.plane();
    Rr2Point an = a.normal();
    Rr2Point bn = b.normal();
    Rr2Point v02 = Rr2Point.add(an, bn);
    Rr2Point v31 = Rr2Point.sub(bn, an);
    Rr2Point x, x0, x1, x2, x3;
    int category = 0;
    try {
      x = a.cross_point(b);
      v02 = v02.norm();
      v31 = v31.norm();
      x2 = Rr2Point.add(x, v02);
      x0 = Rr2Point.sub(x, v02);
      x1 = Rr2Point.add(x, v31);
      x3 = Rr2Point.sub(x, v31);
      if (value(x0) <= 0) category |= 1;
      if (value(x1) <= 0) category |= 2;
      if (value(x2) <= 0) category |= 4;
      if (value(x3) <= 0) category |= 8;

      switch (category) {
        case 0:
          return nothing();
        case 1:
          return intersection(leafA, leafB);
        case 2:
          return intersection(leafA, leafB.complement());
        case 3:
          return leafA;
        case 4:
          return intersection(leafA.complement(), leafB.complement());
        case 5:
          Debug.e("RrCSG crossCategorise: non-manifold shape (case 0101)!");
          return union(
              intersection(leafA, leafB), intersection(leafA.complement(), leafB.complement()));
        case 6:
          return leafB.complement();
        case 7:
          return union(leafA, leafB.complement());
        case 8:
          return intersection(leafA.complement(), leafB);
        case 9:
          return leafB;
        case 10:
          Debug.e("RrCSG crossCategorise: non-manifold shape (case 1010)!");
          return union(
              RrCSG.intersection(leafA.complement(), leafB),
              intersection(leafA, leafB.complement()));
        case 11:
          return union(leafA, leafB);
        case 12:
          return leafA.complement();
        case 13:
          return union(leafA.complement(), leafB);
        case 14:
          return union(leafA.complement(), leafB.complement());
        case 15:
          return universe();
        default:
          Debug.e("RrCSG crossCategorise: bitwise | doesn't seem to work...");
          return this;
      }
    } catch (Exception e) {
      // leafA and leafB are parallel

      x0 = Rr2Point.mul(Rr2Point.add(a.pLine().origin(), b.pLine().origin()), 0.5);
      x1 = Rr2Point.mul(Rr2Point.sub(a.pLine().origin(), b.pLine().origin()), 3);
      x2 = Rr2Point.add(x0, x1);
      x1 = Rr2Point.sub(x0, x1);
      if (value(x0) <= 0) category |= 1;
      if (value(x1) <= 0) category |= 2;
      if (value(x2) <= 0) category |= 4;

      if (leafA.value(x0) <= 0) leafA = leafA.complement();

      if (leafB.value(x0) <= 0) leafB = leafB.complement();

      switch (category) {
        case 0:
          return nothing();
        case 1:
          return intersection(leafA.complement(), leafB.complement());
        case 2:
          return leafB;
        case 3:
          return leafA.complement();
        case 4:
          return leafA;
        case 5:
          return union(leafA, leafB);
        case 6:
          return leafB.complement();
        case 7:
          return universe();
        default:
          Debug.e("RrCSG crossCategorise: bitwise | doesn't seem to work...");
          return this;
      }
    }
  }