Package ca.eandb.jmist.framework.geometry

Source Code of ca.eandb.jmist.framework.geometry.ConstructiveSolidGeometry$CsgIntersectionRecorder$CsgIntersection

/**
* Java Modular Image Synthesis Toolkit (JMIST)
* Copyright (C) 2008-2013 Bradley W. Kimmel
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
package ca.eandb.jmist.framework.geometry;

import java.util.BitSet;
import java.util.Comparator;
import java.util.Iterator;
import java.util.SortedSet;
import java.util.TreeSet;

import ca.eandb.jmist.framework.Intersection;
import ca.eandb.jmist.framework.IntersectionDecorator;
import ca.eandb.jmist.framework.IntersectionRecorder;
import ca.eandb.jmist.framework.SceneElement;
import ca.eandb.jmist.framework.ShadingContext;
import ca.eandb.jmist.math.Interval;
import ca.eandb.jmist.math.Ray3;

/**
* An abstract <code>SceneElement</code> that combines other geometries using a
* boolean expression.
* @author Brad Kimmel
*/
public abstract class ConstructiveSolidGeometry extends CompositeGeometry {

  /** Serialization version ID. */
  private static final long serialVersionUID = 2972169138865609527L;

  /* (non-Javadoc)
   * @see ca.eandb.jmist.framework.SceneElement#intersect(ca.eandb.jmist.toolkit.Ray3, ca.eandb.jmist.framework.IntersectionRecorder)
   */
  public void intersect(Ray3 ray, IntersectionRecorder recorder) {

    /* Use a special intersection recorder that knows how to combine the
     * results of multiple sets of intersections.
     */
    CsgIntersectionRecorder csg = new CsgIntersectionRecorder();

    /* Compute the ray-geometry intersections for each child geometry in
     * turn.
     */
    for (SceneElement geometry : this.children()) {

      geometry.intersect(ray, csg);

      /* Advance to next argument. */
      csg.advance();

    }

    /* combine the results and transfer the resulting intesections to the
     * provided intersection recorder.
     */
    csg.transfer(recorder);

  }

  /**
   * Evaluates the boolean expression for this class of
   * <code>ConstructiveSolidGeometry</code>.
   * @param nArgs The number of child geometries.
   * @param args A <code>BitSet</code> of values indicating whether the ray
   *     is inside each of the child geometries.  This argument should not
   *     be modified by the method.
   * @return A value indicating whether the ray is inside the combined
   *     geometry.  The result should be deterministic.  That is, two calls
   *     to this method with the same value for <code>nArgs</code> and for
   *     <code>args</code> should yield the same result.
   */
  protected abstract boolean isInside(int nArgs, BitSet args);

  /**
   * An <code>IntersectionRecorder</code> that combines the results of
   * multiple sets of intersections using a boolean expression.
   * @author Brad Kimmel
   */
  private final class CsgIntersectionRecorder implements IntersectionRecorder {

    /* (non-Javadoc)
     * @see ca.eandb.jmist.framework.IntersectionRecorderDecorator#needAllIntersections()
     */
    public boolean needAllIntersections() {
      return true;
    }

    /* (non-Javadoc)
     * @see ca.eandb.jmist.framework.IntersectionRecorder#isEmpty()
     */
    public boolean isEmpty() {
      return this.intersectionSet.isEmpty();
    }

    /* (non-Javadoc)
     * @see ca.eandb.jmist.framework.IntersectionRecorderDecorator#interval()
     */
    public Interval interval() {
      return Interval.UNIVERSE;
    }

    /* (non-Javadoc)
     * @see ca.eandb.jmist.framework.IntersectionRecorderDecorator#record(ca.eandb.jmist.framework.Intersection)
     */
    public void record(Intersection intersection) {
      this.intersectionSet.add(new CsgIntersection(this.argumentIndex, intersection));
    }

    /**
     * Combines the results of each set of intersections and transfers the
     * resulting intersections to the specified
     * <code>IntersectionRecorder</code>.
     * @param recorder The <code>IntersectionRecorder</code> to transfer
     *     the resulting intersections to.
     */
    public void transfer(IntersectionRecorder recorder) {

      int              nArgs      = this.argumentIndex;
      BitSet            args      = new BitSet(nArgs);
      Iterator<CsgIntersection>  i        = this.intersectionSet.iterator();
      boolean            fromInside    = false;
      boolean            toInside;

      /* Loop through each intersection. */
      while (i.hasNext()) {

        CsgIntersection      x        = i.next();
        Intersection      inner      = x.getInnerIntersection();

        assert(x.getArgumentIndex() < nArgs);

        args.set(x.getArgumentIndex(), inner.isFront());
        toInside = isInside(nArgs, args);

        /* If the intersection represents the traversal from
         * outside the geometry to inside, or vice versa, then the
         * intersection is at the boundary of the combined geometry.
         * Only consider this intersection if it is within the
         * range expected by the recorder.
         */
        if (fromInside != toInside
            && recorder.interval().contains(inner.getDistance(), inner.getTolerance())) {

          /* The intersection is a front intersection if the ray
           * is passing into the geometry.
           */
          x.setFront(toInside);
          recorder.record(x);

          /* If we don't need all intersections, then we're
           * done.
           */
          if (!recorder.needAllIntersections()) {
            break;
          }

        }

        fromInside = toInside;

      } /* i.hasNext() */

    }

    /**
     * Completes a set of intersections and advances to the set of
     * intersections for the next geometry.
     */
    public void advance() {
      this.argumentIndex++;
    }

    /**
     * An <code>Intersection</code> decorator that adds functionality
     * needed to support constructive solid geometry.  This decorator
     * keeps track of which child geometry the intersection is for, and it
     * can be flipped, which toggles the {@link Intersection#isFront()}
     * property and negates the basis and normal.
     * @author Brad Kimmel
     */
    private final class CsgIntersection extends IntersectionDecorator {

      /**
       * Creates a new <code>CsgIntersection</code>.
       * @param argumentIndex The
       * @param inner
       */
      public CsgIntersection(int argumentIndex, Intersection inner) {
        super(inner);
        this.argumentIndex = argumentIndex;
      }

      /* (non-Javadoc)
       * @see ca.eandb.jmist.framework.IntersectionDecorator#front()
       */
      @Override
      public boolean isFront() {
        return this.flipped ? !this.inner.isFront() : this.inner.isFront();
      }

      /* (non-Javadoc)
       * @see ca.eandb.jmist.framework.IntersectionDecorator#transformShadingContext(ca.eandb.jmist.framework.ShadingContext)
       */
      @Override
      protected void transformShadingContext(ShadingContext context) {
        context.setPrimitiveIndex(0);
        if (flipped) {
          context.setBasis(context.getBasis().opposite());
          context.setShadingBasis(context.getShadingBasis().opposite());
        }
      }

      /**
       * Gets the value identifying which of the component geometries
       * this <code>Intersection</code> came from.
       * @return The value identifying which of the component geometries
       *     this <code>Intersection</code> came from.
       */
      public int getArgumentIndex() {
        return this.argumentIndex;
      }

      /**
       * Gets the <code>Intersection</code> that was recorded by the
       * component geometry.
       * @return The <code>Intersection</code> that was recorded by the
       *     component geometry.
       */
      public Intersection getInnerIntersection() {
        return this.inner;
      }

      /**
       * Sets whether this <code>CsgIntersection</code> is an entry point
       * or an exit point from the geometry.
       * @param front A value indicating if this
       *     <code>CsgIntersection</code> represents an intersection
       *     with the outside of the geometry.
       */
      public void setFront(boolean front) {
        this.flipped = (front != inner.isFront());
      }

      /**
       * A value indicating if this <code>CsgIntersection</code> was
       * flipped from the underlying <code>Intersection</code>.
       */
      private boolean flipped = false;

      /**
       * A value indicating which component geometry the inner
       * <code>Intersection</code> came from.
       */
      private final int argumentIndex;

    }

    /**
     * The index of the component geometry whose intersections are
     * currently being recorded.
     */
    private int argumentIndex = 0;

    /**
     * The set of all the intersections recorded by each of the component
     * geometries, sorted by distance (least to greatest).
     */
    private final SortedSet<CsgIntersection> intersectionSet = new TreeSet<CsgIntersection>(
        new Comparator<Intersection>() {

          public int compare(Intersection arg0, Intersection arg1) {
            return Double.compare(arg0.getDistance(), arg1.getDistance());
          }

        });

  }

}
TOP

Related Classes of ca.eandb.jmist.framework.geometry.ConstructiveSolidGeometry$CsgIntersectionRecorder$CsgIntersection

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.