public double f1(Vector3f point, Vector3f A, Vector3f B) {
    // ****** basic parameters ******
    Vector3f vec_b = B;
    Vector3f vec_a = A.subtract(vec_b);
    Vector3f vec_r = point;
    double L = vec_a.length();
    Vector3f vec_d = vec_r.subtract(vec_b);
    double d = vec_d.length();
    double h = vec_d.dot(vec_a.normalize());

    // terms
    double s2 = s * s;
    double h2 = h * h;
    double lmh = L - h;
    double d2 = d * d;
    double p2 = 1 + s2 * (d2 - h2);
    double p = Math.sqrt(p2);
    double ww = p2 + s2 * h2;
    double qq = p2 + s2 * lmh * lmh;
    double sdp = s / p;
    double tpp = 2.0 * p2;
    double sp = s * p;
    double term = Math.atan(sdp * h) + Math.atan(sdp * lmh);

    return (h / ww + lmh / qq) / tpp + term / (tpp * sp);
  }
  public Vector3f calculateForce(
      Vector3f location,
      Vector3f velocity,
      float collisionRadius,
      float speed,
      float turnSpeed,
      float tpf,
      List<Obstacle> obstacles) {
    float cautionRange = speed * 1.5f / turnSpeed;
    Line line = new Line(location, velocity.normalize());
    Plane plane = new Plane(velocity, 1);
    Vector3f closest = Vector3f.ZERO;
    float shortestDistance = -1;

    for (Obstacle obs : obstacles) {

      Vector3f target = obs.getLocation();

      Vector3f loc = target.subtract(location);

      // If the obstacle isn't ahead of him, just ignore it
      if (plane.whichSide(loc) != Side.Positive) {
        continue;
      }

      // Check if the target is inside the check range
      if (location.distance(target) <= collisionRadius + cautionRange + obs.getRadius()) {

        // Check if the target will collide with the source
        if (obs.distance(line) < collisionRadius) {

          float newDistance = obs.distance(location);
          // Store the closest target
          if (shortestDistance == -1 || newDistance < shortestDistance)
            shortestDistance = newDistance;
          closest = target;
        }
      }
    }

    // If any target was found
    if (shortestDistance != -1) {

      // Find in wich side the target is
      // To do that, we do a signed distance by
      // subtracing the location from the target
      // and the dot product between the line's normal
      float dot = closest.subtract(location).dot(line.getDirection().cross(Vector3f.UNIT_Y));

      if (dot <= 0) return velocity.cross(Vector3f.UNIT_Y);
      else return velocity.cross(Vector3f.UNIT_Y).negate();
    }

    // No target found, just return a zero value
    return Vector3f.ZERO;
  }
Exemple #3
0
  public void setCameraPosition(Vector3f position) {
    // get vector between planet and camera
    this.planetToCamera = position.subtract(this.getWorldTranslation());
    // get distance to surface
    this.distanceToCamera = this.planetToCamera.length() - this.baseRadius;

    // are we in the atmosphere?
    if (this.atmosphereNode != null) {
      if (this.distanceToCamera < this.atmosphereRadius - this.baseRadius) {
        this.previouslyInAtmosphere = this.currentlyInAtmosphere;
        this.currentlyInAtmosphere = true;
      } else {
        this.previouslyInAtmosphere = this.currentlyInAtmosphere;
        this.currentlyInAtmosphere = false;
      }
    }

    // are we in the water?
    if (this.oceanNode != null) {
      if (this.distanceToCamera <= 1f) {
        this.previouslyInOcean = this.currentlyInOcean;
        this.currentlyInOcean = true;
      } else {
        this.previouslyInOcean = this.currentlyInOcean;
        this.currentlyInOcean = false;
      }
    }

    // Update camera positions for all quads
    int currentTerrainMaxDepth = 0;
    for (int i = 0; i < 6; i++) {
      if (terrainSide[i] != null) {
        terrainSide[i].setCameraPosition(position);
        // get current max depth of quad for skirt toggling
        currentTerrainMaxDepth =
            Math.max(currentTerrainMaxDepth, terrainSide[i].getCurrentMaxDepth());
      }
      if (oceanSide[i] != null) {
        oceanSide[i].setCameraPosition(position);
      }
      if (atmosphereSide[i] != null) {
        atmosphereSide[i].setCameraPosition(position);
      }
    }

    // toggle skirting on the terrain if needed
    boolean skirting;
    // Are we at minDepth?
    if (currentTerrainMaxDepth == this.minDepth) {
      // Turn off skirting if entire terrain is at minDepth
      skirting = false;
    } else {
      // otherwise turn on skirting
      skirting = true;
    }
    // Go through and set skirting on all terrain quads
    for (int i = 0; i < 6; i++) {
      if (terrainSide[i] != null) terrainSide[i].setSkirting(skirting);
    }
  }
  @Override
  public void update(float tpf) {

    if (forward ^ backward) {
      //            float yCoord = charControl.getRigidBody().getLinearVelocity().getY();
      Vector3f charLocation = charControl.getPhysicsLocation();
      Vector3f walkDir =
          charLocation
              .subtract(app.getCamera().getLocation().clone().setY(charLocation.getY()))
              .normalizeLocal();
      if (backward) {
        walkDir.negateLocal();
      }

      charControl.setWalkDirection(walkDir);
      charControl.setMove(true);
    } else {
      charControl.setMove(false);
    }

    if (jump) {
      charControl.setJump();
      jump = false;
    }
    Vector3f camdir = app.getCamera().getDirection().clone();
    Quaternion newRot = new Quaternion();
    newRot.lookAt(camdir.setY(0), Vector3f.UNIT_Y);
    charControl.setRotationInUpdate(newRot);
  }
  public double flt(Vector3f point, Vector3f A, Vector3f B) {
    Vector3f vec_b = B;
    Vector3f vec_a = A.subtract(vec_b);
    double L = vec_a.length();

    return L * f1(point, A, B) - ft(point, A, B);
  }
  @SuppressWarnings("unused")
  private double cauchy(Vector3f point, Vector3f center) {
    Vector3f vec_r = point.subtract(center);
    double s = 0.85; // 0.85 - example on thesis; //kernel width

    double r_2 = vec_r.lengthSquared();
    return 1.0 / ((1 + s * s * r_2) * (1 + s * s * r_2));
  }
 public Bullet(
     SimpleApplication sa, Vector3f bulletWorldTranslation, Vector3f tankWorldTranslation) {
   this.sa = sa;
   this.position = bulletWorldTranslation;
   this.tankWorldTranslation = tankWorldTranslation;
   velocity = position.subtract(tankWorldTranslation).subtract(new Vector3f(0, 2f, 0)).mult(1.2f);
   initBullet();
 }
  /**
   * Centers the spatial in the origin of the world bound.
   *
   * @return The spatial on which this method is called, e.g <code>this</code>.
   */
  public Spatial center() {
    Vector3f worldTrans = getWorldTranslation();
    Vector3f worldCenter = getWorldBound().getCenter();

    Vector3f absTrans = worldTrans.subtract(worldCenter);
    setLocalTranslation(absTrans);

    return this;
  }
  /**
   * Using this slot's camera, construct a pick ray for the specified screen coordinates.
   *
   * @param screenLocation screen coordinates (in pixels, measured from the lower left, not null,
   *     unaffected)
   * @return new instance
   */
  @Override
  public Ray pickRay(Vector2f screenLocation) {
    Validate.nonNull(screenLocation, "screen location");

    Vector3f startLocation = cam.getWorldCoordinates(screenLocation, 0f);
    Vector3f farPoint = cam.getWorldCoordinates(screenLocation, 1f);
    Vector3f direction = farPoint.subtract(startLocation).normalizeLocal();
    Ray result = new Ray(startLocation, direction);

    return result;
  }
  public double ft(Vector3f point, Vector3f A, Vector3f B) {
    // ****** basic parameters ******
    Vector3f vec_b = B;
    Vector3f vec_a = A.subtract(vec_b);
    Vector3f vec_r = point;
    double L = vec_a.length();
    Vector3f vec_d = vec_r.subtract(vec_b);
    double d = vec_d.length();
    double h = vec_d.dot(vec_a.normalize());

    // terms
    double s2 = s * s;
    double h2 = h * h;
    double lmh = L - h;
    double d2 = d * d;
    double p2 = 1 + s2 * (d2 - h2);
    double ww = p2 + s2 * h2;
    double qq = p2 + s2 * lmh * lmh;

    double ts2 = 2.0 * s2;
    return h * f1(point, A, B) + (1.0 / ww - 1.0 / qq) / ts2;
  }
Exemple #11
0
  /**
   * Compute bounds from an array of points
   *
   * @param pts
   * @param transform
   * @return
   */
  public static BoundingBox computeBoundForPoints(Vector3f[] pts, Transform transform) {
    Vector3f min = new Vector3f(Vector3f.POSITIVE_INFINITY);
    Vector3f max = new Vector3f(Vector3f.NEGATIVE_INFINITY);
    Vector3f temp = new Vector3f();
    for (int i = 0; i < pts.length; i++) {
      transform.transformVector(pts[i], temp);

      min.minLocal(temp);
      max.maxLocal(temp);
    }
    Vector3f center = min.add(max).multLocal(0.5f);
    Vector3f extent = max.subtract(min).multLocal(0.5f);
    return new BoundingBox(center, extent.x, extent.y, extent.z);
  }
  void lookAt(Vector3f pos) {
    Vector3f location = spatial.getLocalTranslation();
    Vector3f target = pos.clone();

    Vector3f distance = target.subtract(location);
    if (distance.length() < 0.3f) {
      return;
    }
    Vector3f newVel = distance.normalize();
    Quaternion q = new Quaternion();
    q.lookAt(newVel, Vector3f.UNIT_Y);
    // q.addLocal(playerInfo.initalRot);
    spatial.setLocalRotation(q);
  }
  void moveTo(Vector3f pos) {
    float speed = playerInfo.getRealSpeed();
    Vector3f location = spatial.getLocalTranslation();
    Vector3f target = pos.clone();

    Vector3f distance = target.subtract(location);
    if (distance.length() < 0.3f) {
      return;
    }
    Vector3f newVel = distance.normalize().mult(speed);
    // Vector3f steering = desierdVel.subtract(velocity).negate();

    spatial.setLocalTranslation(location.add(newVel));
  }
Exemple #14
0
  private void refreshFont() {
    Camera cam = IsoCamera.getInstance().getCam();

    Vector3f start = from.getPlanet().getPosition();
    Vector3f end = to.getPlanet().getPosition();

    float width = label.getLineWidth();
    Random r = new Random();
    //        float height = r.nextFloat() * end.subtract(start).z;

    Vector3f position = new Vector3f(width / 2, .15f, 0);
    Vector3f fontPos = start.add(end.subtract(start).mult(0.4f + 0.75f * r.nextFloat()));
    position.addLocal(fontPos);

    Vector3f up = cam.getUp().clone();
    Vector3f dir = cam.getDirection().clone().negateLocal().normalizeLocal();
    Vector3f left = cam.getLeft().clone().normalizeLocal().negateLocal();

    Quaternion look = new Quaternion();
    look.fromAxes(left, up, dir);

    label.setLocalTransform(new Transform(position, look));

    //        Vector3f camPos = IsoCamera.getInstance().getCam().getLocation();
    //        Vector3f fontPos = to.getPlanet().getPosition().
    //                subtract(from.getPlanet().getPosition());
    //        Vector3f up = IsoCamera.getInstance().getCam().getUp().clone();
    //        Vector3f dir = camPos.subtract(fontPos);
    ////        Vector3f dir = Vector3f.UNIT_Y.clone().subtract(fontPos);
    //
    //        Vector3f left = IsoCamera.getInstance().getCam().getLeft().clone();
    //        dir.normalizeLocal();
    //        left.negateLocal();
    //        left.normalizeLocal();
    //        up.normalizeLocal();
    ////        dir.negateLocal();
    //
    //        Quaternion look = new Quaternion();
    //        look.fromAxes(left, up, dir);
    //
    //        Vector3f newPos = to.getPlanet().getPosition().
    //                subtract(from.getPlanet().getPosition());
    //
    //        newPos.x -= label.getLineWidth() / 2;
    //
    //        Transform t = new Transform(newPos, look);
    //
    //        label.setLocalTransform(t);
  }
 public void locationChecker(Monster monster) {
   Vector3f playerLocation = player.Model.getLocalTranslation();
   Vector3f monsterLocation = monster.Model.getLocalTranslation();
   float distance = playerLocation.distance(monsterLocation);
   Vector3f playerDirection = playerLocation.subtract(monsterLocation);
   monsterRotater(monster, playerDirection);
   if (distance < 3) {
     if (monster.attackDelay == 10) {
       monster.attackDelay = 0;
       monster.attack(monster.Model, player);
     } else {
       monster.attackDelay++;
     }
   } else {
     monster.anim.animChange("UnarmedRun", "RunAction", monster.Model);
   }
 }
Exemple #16
0
  public float getHeadingAtWP(int index) {
    float heading = 0;
    Waypoint nextWayPoint = getNextWayPoint(index);

    // if next way point available, compute heading towards it
    if (nextWayPoint != null) {
      // compute driving direction by looking at next way point from current position
      Vector3f targetPosition = nextWayPoint.getPosition().clone();
      targetPosition.setY(0);

      Vector3f currentPosition = waypointList.get(index).getPosition().clone();
      currentPosition.setY(0);

      Vector3f drivingDirection = targetPosition.subtract(currentPosition).normalize();

      // compute heading (orientation) from driving direction vector for
      // angle between driving direction and heading "0"
      float angle0 = drivingDirection.angleBetween(new Vector3f(0, 0, -1));
      // angle between driving direction and heading "90"
      float angle90 = drivingDirection.angleBetween(new Vector3f(1, 0, 0));

      // get all candidates for heading
      // find the value from {heading1,heading2} which matches with one of {heading3,heading4}
      float heading1 = (2.0f * FastMath.PI + angle0) % FastMath.TWO_PI;
      float heading2 = (2.0f * FastMath.PI - angle0) % FastMath.TWO_PI;
      float heading3 = (2.5f * FastMath.PI + angle90) % FastMath.TWO_PI;
      float heading4 = (2.5f * FastMath.PI - angle90) % FastMath.TWO_PI;

      float diff_1_3 = FastMath.abs(heading1 - heading3);
      float diff_1_4 = FastMath.abs(heading1 - heading4);
      float diff_2_3 = FastMath.abs(heading2 - heading3);
      float diff_2_4 = FastMath.abs(heading2 - heading4);

      if ((diff_1_3 < diff_1_4 && diff_1_3 < diff_2_3 && diff_1_3 < diff_2_4)
          || (diff_1_4 < diff_1_3 && diff_1_4 < diff_2_3 && diff_1_4 < diff_2_4)) {
        // if diff_1_3 or diff_1_4 are smallest --> the correct heading is heading1
        heading = heading1;
      } else {
        // if diff_2_3 or diff_2_4 are smallest --> the correct heading is heading2
        heading = heading2;
      }
    }
    return heading;
  }
  /**
   * Compute bounds from an array of points
   *
   * @param pts
   * @param mat
   * @return
   */
  public static BoundingBox computeBoundForPoints(Vector3f[] pts, Matrix4f mat) {
    Vector3f min = new Vector3f(Vector3f.POSITIVE_INFINITY);
    Vector3f max = new Vector3f(Vector3f.NEGATIVE_INFINITY);
    Vector3f temp = new Vector3f();

    for (int i = 0; i < pts.length; i++) {
      float w = mat.multProj(pts[i], temp);

      temp.x /= w;
      temp.y /= w;
      // Why was this commented out?
      temp.z /= w;

      min.minLocal(temp);
      max.maxLocal(temp);
    }

    Vector3f center = min.add(max).multLocal(0.5f);
    Vector3f extent = max.subtract(min).multLocal(0.5f);
    // Nehon 08/18/2010 : Added an offset to the extend to avoid banding artifacts when the frustum
    // are aligned
    return new BoundingBox(center, extent.x + 2.0f, extent.y + 2.0f, extent.z + 2.5f);
  }
  /**
   * Rebuilds the cylinder based on a new set of parameters.
   *
   * @param axisSamples the number of samples along the axis.
   * @param radialSamples the number of samples around the radial.
   * @param radius the radius of the bottom of the cylinder.
   * @param radius2 the radius of the top of the cylinder.
   * @param height the cylinder's height.
   * @param closed should the cylinder have top and bottom surfaces.
   * @param inverted is the cylinder is meant to be viewed from the inside.
   */
  public void updateGeometry(
      int axisSamples,
      int radialSamples,
      float radius,
      float radius2,
      float height,
      boolean closed,
      boolean inverted) {
    this.axisSamples = axisSamples + (closed ? 2 : 0);
    this.radialSamples = radialSamples;
    this.radius = radius;
    this.radius2 = radius2;
    this.height = height;
    this.closed = closed;
    this.inverted = inverted;

    //        VertexBuffer pvb = getBuffer(Type.Position);
    //        VertexBuffer nvb = getBuffer(Type.Normal);
    //        VertexBuffer tvb = getBuffer(Type.TexCoord);

    // Vertices
    int vertCount = axisSamples * (radialSamples + 1) + (closed ? 2 : 0);

    setBuffer(Type.Position, 3, createVector3Buffer(getFloatBuffer(Type.Position), vertCount));

    // Normals
    setBuffer(Type.Normal, 3, createVector3Buffer(getFloatBuffer(Type.Normal), vertCount));

    // Texture co-ordinates
    setBuffer(Type.TexCoord, 2, createVector2Buffer(vertCount));

    int triCount = ((closed ? 2 : 0) + 2 * (axisSamples - 1)) * radialSamples;

    setBuffer(Type.Index, 3, createShortBuffer(getShortBuffer(Type.Index), 3 * triCount));

    // generate geometry
    float inverseRadial = 1.0f / radialSamples;
    float inverseAxisLess = 1.0f / (closed ? axisSamples - 3 : axisSamples - 1);
    float inverseAxisLessTexture = 1.0f / (axisSamples - 1);
    float halfHeight = 0.5f * height;

    // Generate points on the unit circle to be used in computing the mesh
    // points on a cylinder slice.
    float[] sin = new float[radialSamples + 1];
    float[] cos = new float[radialSamples + 1];

    for (int radialCount = 0; radialCount < radialSamples; radialCount++) {
      float angle = FastMath.TWO_PI * inverseRadial * radialCount;
      cos[radialCount] = FastMath.cos(angle);
      sin[radialCount] = FastMath.sin(angle);
    }
    sin[radialSamples] = sin[0];
    cos[radialSamples] = cos[0];

    // calculate normals
    Vector3f[] vNormals = null;
    Vector3f vNormal = Vector3f.UNIT_Z;

    if ((height != 0.0f) && (radius != radius2)) {
      vNormals = new Vector3f[radialSamples];
      Vector3f vHeight = Vector3f.UNIT_Z.mult(height);
      Vector3f vRadial = new Vector3f();

      for (int radialCount = 0; radialCount < radialSamples; radialCount++) {
        vRadial.set(cos[radialCount], sin[radialCount], 0.0f);
        Vector3f vRadius = vRadial.mult(radius);
        Vector3f vRadius2 = vRadial.mult(radius2);
        Vector3f vMantle = vHeight.subtract(vRadius2.subtract(vRadius));
        Vector3f vTangent = vRadial.cross(Vector3f.UNIT_Z);
        vNormals[radialCount] = vMantle.cross(vTangent).normalize();
      }
    }

    FloatBuffer nb = getFloatBuffer(Type.Normal);
    FloatBuffer pb = getFloatBuffer(Type.Position);
    FloatBuffer tb = getFloatBuffer(Type.TexCoord);

    // generate the cylinder itself
    Vector3f tempNormal = new Vector3f();
    for (int axisCount = 0, i = 0; axisCount < axisSamples; axisCount++, i++) {
      float axisFraction;
      float axisFractionTexture;
      int topBottom = 0;
      if (!closed) {
        axisFraction = axisCount * inverseAxisLess; // in [0,1]
        axisFractionTexture = axisFraction;
      } else {
        if (axisCount == 0) {
          topBottom = -1; // bottom
          axisFraction = 0;
          axisFractionTexture = inverseAxisLessTexture;
        } else if (axisCount == axisSamples - 1) {
          topBottom = 1; // top
          axisFraction = 1;
          axisFractionTexture = 1 - inverseAxisLessTexture;
        } else {
          axisFraction = (axisCount - 1) * inverseAxisLess;
          axisFractionTexture = axisCount * inverseAxisLessTexture;
        }
      }

      // compute center of slice
      float z = -halfHeight + height * axisFraction;
      Vector3f sliceCenter = new Vector3f(0, 0, z);

      // compute slice vertices with duplication at end point
      int save = i;
      for (int radialCount = 0; radialCount < radialSamples; radialCount++, i++) {
        float radialFraction = radialCount * inverseRadial; // in [0,1)
        tempNormal.set(cos[radialCount], sin[radialCount], 0.0f);

        if (vNormals != null) {
          vNormal = vNormals[radialCount];
        } else if (radius == radius2) {
          vNormal = tempNormal;
        }

        if (topBottom == 0) {
          if (!inverted) nb.put(vNormal.x).put(vNormal.y).put(vNormal.z);
          else nb.put(-vNormal.x).put(-vNormal.y).put(-vNormal.z);
        } else {
          nb.put(0).put(0).put(topBottom * (inverted ? -1 : 1));
        }

        tempNormal.multLocal((radius - radius2) * axisFraction + radius2).addLocal(sliceCenter);
        pb.put(tempNormal.x).put(tempNormal.y).put(tempNormal.z);

        tb.put((inverted ? 1 - radialFraction : radialFraction)).put(axisFractionTexture);
      }

      BufferUtils.copyInternalVector3(pb, save, i);
      BufferUtils.copyInternalVector3(nb, save, i);

      tb.put((inverted ? 0.0f : 1.0f)).put(axisFractionTexture);
    }

    if (closed) {
      pb.put(0).put(0).put(-halfHeight); // bottom center
      nb.put(0).put(0).put(-1 * (inverted ? -1 : 1));
      tb.put(0.5f).put(0);
      pb.put(0).put(0).put(halfHeight); // top center
      nb.put(0).put(0).put(1 * (inverted ? -1 : 1));
      tb.put(0.5f).put(1);
    }

    IndexBuffer ib = getIndexBuffer();
    int index = 0;
    // Connectivity
    for (int axisCount = 0, axisStart = 0; axisCount < axisSamples - 1; axisCount++) {
      int i0 = axisStart;
      int i1 = i0 + 1;
      axisStart += radialSamples + 1;
      int i2 = axisStart;
      int i3 = i2 + 1;
      for (int i = 0; i < radialSamples; i++) {
        if (closed && axisCount == 0) {
          if (!inverted) {
            ib.put(index++, i0++);
            ib.put(index++, vertCount - 2);
            ib.put(index++, i1++);
          } else {
            ib.put(index++, i0++);
            ib.put(index++, i1++);
            ib.put(index++, vertCount - 2);
          }
        } else if (closed && axisCount == axisSamples - 2) {
          ib.put(index++, i2++);
          ib.put(index++, inverted ? vertCount - 1 : i3++);
          ib.put(index++, inverted ? i3++ : vertCount - 1);
        } else {
          ib.put(index++, i0++);
          ib.put(index++, inverted ? i2 : i1);
          ib.put(index++, inverted ? i1 : i2);
          ib.put(index++, i1++);
          ib.put(index++, inverted ? i2++ : i3++);
          ib.put(index++, inverted ? i3++ : i2++);
        }
      }
    }

    updateBound();
  }
 public Vector3f getDirectionToWaypoint() {
   Vector3f waypt = nextWaypoint.getPosition();
   return waypt.subtract(currentPos3d).normalizeLocal();
 }
  private double basicCSG(Vector3f point, Skeleton currentSkeleton) {
    double sum = 0;
    boolean isCSG = SceneManager.get().csgEnabled;

    for (int i = 0; i < currentSkeleton.branches.size(); i++) {
      SkeletonBranch branch = currentSkeleton.branches.get(i);
      for (int j = 0; j < branch.points.size() - 1; j++) {
        SkeletonPoint SP1 = branch.points.get(j);
        SkeletonPoint SP2 = branch.points.get(j + 1);
        //            TriangulationPoint P1 = SP1.point;
        //            TriangulationPoint P2 = SP2.point;
        //            Vector3f p = new Vector3f(P1.getXf(), P1.getYf(), P1.getZf());
        //            Vector3f q = new Vector3f(P2.getXf(), P2.getYf(), P2.getZf());
        Vector3f p = SP1.point;
        Vector3f q = SP2.point;

        // calculate radius of influence
        float Rp = (float) SP1.radius;
        float Rq = (float) SP2.radius;

        // calculate surface points Sp and Sq
        Vector3f PQ = q.subtract(p);
        Vector3f normalVector = new Vector3f(-PQ.getY(), PQ.getX(), PQ.getZ()).normalize();
        Vector3f Sp = p.add(normalVector.mult(Rp));
        Vector3f Sq = q.add(normalVector.mult(Rq));
        Vector3f Smid = Sp.add(Sq).divide(2f);

        // System.out.println("L: " + PQ.length() + " Sp: " + Sp + " Sq: " +
        // Sq + " Smid: " + Smid);

        // calculate weights
        double w0 = T / flt(Sp, p, q);
        double w1 = T / ft(Sq, p, q);

        // division factor
        w0 /= (double) SP1.divisionFactor;
        w1 /= (double) SP2.divisionFactor;

        double k = T / (w0 * flt(Smid, p, q) + w1 * ft(Smid, p, q));

        // scale factor
        w0 *= k;
        w1 *= k;

        // System.out.println("j " + j);
        // System.out.println("w0 " + w0 + " w1 " + w1);

        // CSG blending
        if (isCSG) {
          double fx = cauchy(point, p, q, w0, w1);
          double R = cauchy(Smid, p, q, w0, w1);
          double blending = blending(-fx + T, R);
          sum += blending;
        } else {
          // common sum
          sum += cauchy(point, p, q, w0, w1);
        }
      }
    }

    // if(sum > 1)
    // blendingGTone++;
    // else if(sum < 1)
    // blendingLTone++;

    // sum /= n;

    // Vector3f A = new Vector3f(-5f, 0.0f, 0.0f);
    // Vector3f B = new Vector3f(5f, 0.0f, 0.0f);
    // Vector3f C = new Vector3f(-5f, 4.0f, 0.0f);
    // Vector3f D = new Vector3f(5f, 4.0f, 0.0f);
    //
    // // define threshold based on a pre determined surface point
    // float radius = 5.0f;
    // Vector3f AB = B.subtract(A);
    // Vector3f normalVectorAB = new Vector3f(-AB.getY(), AB.getX(),
    // AB.getZ()).normalize().mult(radius);
    // Vector3f midPointAB = (A.add(B)).divide(2f);
    // Vector3f surfacePointAB = midPointAB.add(normalVectorAB);
    //
    // T = 1.0;
    //
    // sum += blending(-cauchy(point, A, B) + T, cauchy(surfacePointAB, A,
    // B));
    // sum += blending(-cauchy(point, C, D) + T, cauchy(surfacePointAB, C,
    // D));

    // sum = cauchy(point, A, B) + cauchy(point, C, D);

    //      if(!single) //i.e. is multiple
    //      {
    //          // common sum
    ////          double result = -sum + T;
    ////          if (result > 0)
    ////             positive++;
    ////          else if (result < 0)
    ////             negative++;
    ////          return result;
    //          return sum;
    //      }
    //      else
    //      {
    if (!isCSG) return T - sum;
    else
      // CSG composition
      return 1 - sum;
    //      }
  }
 // check if the area is greater than zero
 private static boolean isDegenerateTriangle(Vector3f a, Vector3f b, Vector3f c) {
   return (a.subtract(b).cross(c.subtract(b))).lengthSquared() == 0;
 }