All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.commons.rng.sampling.shape.TetrahedronSampler Maven / Gradle / Ivy

Go to download

The Apache Commons RNG Sampling module provides samplers for various distributions.

The newest version!
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.commons.rng.sampling.shape;

import org.apache.commons.rng.UniformRandomProvider;
import org.apache.commons.rng.sampling.SharedStateObjectSampler;

/**
 * Generate points uniformly distributed within a
 * tetrahedron.
 *
 * 
    *
  • * Uses the algorithm described in: *
    * Rocchini, C. and Cignoni, P. (2001)
    * Generating Random Points in a Tetrahedron.
    * Journal of Graphics Tools 5(4), pp. 9-12. *
    *
  • *
* *

Sampling uses:

* *
    *
  • {@link UniformRandomProvider#nextDouble()} *
* * @see * Rocchini, C. & Cignoni, P. (2001) Journal of Graphics Tools 5, pp. 9-12 * @since 1.4 */ public class TetrahedronSampler implements SharedStateObjectSampler { /** The dimension for 3D sampling. */ private static final int THREE_D = 3; /** The name of vertex a. */ private static final String VERTEX_A = "Vertex a"; /** The name of vertex b. */ private static final String VERTEX_B = "Vertex b"; /** The name of vertex c. */ private static final String VERTEX_C = "Vertex c"; /** The name of vertex d. */ private static final String VERTEX_D = "Vertex d"; /** The first vertex. */ private final double[] a; /** The second vertex. */ private final double[] b; /** The third vertex. */ private final double[] c; /** The fourth vertex. */ private final double[] d; /** The source of randomness. */ private final UniformRandomProvider rng; /** * @param rng Source of randomness. * @param a The first vertex. * @param b The second vertex. * @param c The third vertex. * @param d The fourth vertex. */ TetrahedronSampler(UniformRandomProvider rng, double[] a, double[] b, double[] c, double[] d) { // Defensive copy this.a = a.clone(); this.b = b.clone(); this.c = c.clone(); this.d = d.clone(); this.rng = rng; } /** * @param rng Generator of uniformly distributed random numbers * @param source Source to copy. */ TetrahedronSampler(UniformRandomProvider rng, TetrahedronSampler source) { // Shared state is immutable a = source.a; b = source.b; c = source.c; d = source.d; this.rng = rng; } /** * @return a random Cartesian point within the tetrahedron. */ @Override public double[] sample() { double s = rng.nextDouble(); double t = rng.nextDouble(); final double u = rng.nextDouble(); // Care is taken to ensure the 3 deviates remain in the 2^53 dyadic rationals in [0, 1). // The following are exact for all the 2^53 dyadic rationals: // 1 - u; u in [0, 1] // u - 1; u in [0, 1] // u + 1; u in [-1, 0] // u + v; u in [-1, 0], v in [0, 1] // u + v; u, v in [0, 1], u + v <= 1 // Cut and fold with the plane s + t = 1 if (s + t > 1) { // (s, t, u) = (1 - s, 1 - t, u) if s + t > 1 s = 1 - s; t = 1 - t; } // Now s + t <= 1. // Cut and fold with the planes t + u = 1 and s + t + u = 1. final double tpu = t + u; final double sptpu = s + tpu; if (sptpu > 1) { if (tpu > 1) { // (s, t, u) = (s, 1 - u, 1 - s - t) if t + u > 1 // 1 - s - (1-u) - (1-s-t) == u - 1 + t return createSample(u - 1 + t, s, 1 - u, 1 - s - t); } // (s, t, u) = (1 - t - u, t, s + t + u - 1) if t + u <= 1 // 1 - (1-t-u) - t - (s+t+u-1) == 1 - s - t return createSample(1 - s - t, 1 - tpu, t, s - 1 + tpu); } return createSample(1 - sptpu, s, t, u); } /** * Creates the sample given the random variates {@code s}, {@code t} and {@code u} in the * interval {@code [0, 1]} and {@code s + t + u <= 1}. The sum {@code 1 - s - t - u} is * provided. The sample can be obtained from the tetrahedron {@code abcd} using: * *
     * p = (1 - s - t - u)a + sb + tc + ud
     * 
* * @param p1msmtmu plus 1 minus s minus t minus u ({@code 1 - s - t - u}) * @param s the first variate s * @param t the second variate t * @param u the third variate u * @return the sample */ private double[] createSample(double p1msmtmu, double s, double t, double u) { // From the barycentric coordinates s,t,u create the point by moving along // vectors ab, ac and ad. // Here we do not compute the vectors and use the original vertices: // p = a + s(b-a) + t(c-a) + u(d-a) // = (1-s-t-u)a + sb + tc + ud return new double[] {p1msmtmu * a[0] + s * b[0] + t * c[0] + u * d[0], p1msmtmu * a[1] + s * b[1] + t * c[1] + u * d[1], p1msmtmu * a[2] + s * b[2] + t * c[2] + u * d[2]}; } /** {@inheritDoc} */ @Override public TetrahedronSampler withUniformRandomProvider(UniformRandomProvider rng) { return new TetrahedronSampler(rng, this); } /** * Create a tetrahedron sampler with vertices {@code a}, {@code b}, {@code c} and {@code d}. * Sampled points are uniformly distributed within the tetrahedron. * *

No test for a volume is performed. If the vertices are coplanar the sampling * distribution is undefined. * * @param rng Source of randomness. * @param a The first vertex. * @param b The second vertex. * @param c The third vertex. * @param d The fourth vertex. * @return the sampler * @throws IllegalArgumentException If the vertices do not have length 3; * or vertices have non-finite coordinates */ public static TetrahedronSampler of(UniformRandomProvider rng, double[] a, double[] b, double[] c, double[] d) { // Must be 3D Coordinates.requireLength(a, THREE_D, VERTEX_A); Coordinates.requireLength(b, THREE_D, VERTEX_B); Coordinates.requireLength(c, THREE_D, VERTEX_C); Coordinates.requireLength(d, THREE_D, VERTEX_D); // Detect non-finite vertices Coordinates.requireFinite(a, VERTEX_A); Coordinates.requireFinite(b, VERTEX_B); Coordinates.requireFinite(c, VERTEX_C); Coordinates.requireFinite(d, VERTEX_D); return new TetrahedronSampler(rng, a, b, c, d); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy