/*
* Copyright (c) 2005–2012 Goethe Center for Scientific Computing - Simulation and Modelling (G-CSC Frankfurt)
* Copyright (c) 2012-2015 Goethe Center for Scientific Computing - Computational Neuroscience (G-CSC Frankfurt)
*
* This file is part of NeuGen.
*
* NeuGen is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 3
* as published by the Free Software Foundation.
*
* see: http://opensource.org/licenses/LGPL-3.0
* file://path/to/NeuGen/LICENSE
*
* NeuGen is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* This version of NeuGen includes copyright notice and attribution requirements.
* According to the LGPL this information must be displayed even if you modify
* the source code of NeuGen. The copyright statement/attribution may not be removed.
*
* Attribution Requirements:
*
* If you create derived work you must do the following regarding copyright
* notice and author attribution.
*
* Add an additional notice, stating that you modified NeuGen. In addition
* you must cite the publications listed below. A suitable notice might read
* "NeuGen source code modified by YourName 2012".
*
* Note, that these requirements are in full accordance with the LGPL v3
* (see 7. Additional Terms, b).
*
* Publications:
*
* S. Wolf, S. Grein, G. Queisser. NeuGen 2.0 -
* Employing NeuGen 2.0 to automatically generate realistic
* morphologies of hippocapal neurons and neural networks in 3D.
* Neuroinformatics, 2013, 11(2), pp. 137-148, doi: 10.1007/s12021-012-9170-1
*
*
* J. P. Eberhard, A. Wanner, G. Wittum. NeuGen -
* A tool for the generation of realistic morphology
* of cortical neurons and neural networks in 3D.
* Neurocomputing, 70(1-3), pp. 327-343, doi: 10.1016/j.neucom.2006.01.028
*
*/
/*
* File: Vrand.java
* Created on 06.10.2009, 13:56:13
*
*/
package org.neugen.utils;
import java.io.Serializable;
import javax.vecmath.Vector3f;
/**
* Class for random space vectors on the \a NEUGEN_DIM -dimensional unit sphere.
* @author Jens Eberhard
*/
public class Vrand extends Frand implements Serializable {
static final long serialVersionUID = -8689448816398030143L;
public static final int d = 3;
/** The deviation for the random rotation vector in a plane orthogonal to a given direction.*/
public Vector3f rotationDeviation;
/** The normal vector for the plane. */
public Vector3f normalVector;
/**
* Constructor.
* Initialize with a seed and sets the deviation vector to (1,1,...,1).
* @param s the seed.
*/
public Vrand(long s) {
super(s);
rotationDeviation = new Vector3f(1.0f, 1.0f, 1.0f);
normalVector = new Vector3f();
}
/**
* Function for a valarray of floating point numbers.
* It returns its euclidean length.
*/
public static float length(float[] v) {
float sumVal = 0.0f;
for (int i = 0; i < v.length; i++) {
//v[i] = v[i] * v[i];
sumVal = sumVal + v[i] * v[i];
}
return (float) Math.sqrt(sumVal);
//return Math.sqrt((v * v).sum());
}
/**
* Function for two arrays of floating point numbers.
* It returns their devision array.
*/
public static float[] div(float[] v1, float[] v2) {
float[] result = new float[v1.length];
for (int i = 0; i < v1.length; i++) {
if (v2[i] != 0) {
result[i] = v1[i] / v2[i];
}
}
return result;
}
public static float[] div(float[] v1, float v2) {
float[] result = new float[v1.length];
for (int i = 0; i < v1.length; i++) {
if (v2 != 0) {
result[i] = v1[i] / v2;
}
}
return result;
}
/**
* Function for a random space vector. It computes a vector which is equally
* distributed on the d-dimensional unit sphere.
*/
public Vector3f getRandomRotVector() {
float phi = 2.0f * (float) Math.PI * fdraw();
float theta = (float) Math.PI * fdraw();
if (d == 2) {
Vector3f v = new Vector3f();
v.x = (float) Math.cos(phi);
v.y = (float) Math.sin(phi);
return v;
}
if (d == 3) {
Vector3f v = new Vector3f();
v.x = (float) Math.cos(phi) * (float) Math.sin(theta);
v.y = (float) Math.sin(phi) * (float) Math.sin(theta);
v.z = (float) Math.cos(theta);
return v;
}
return null;
}
/**
* Function for a random space vector. It computes and returns a vector which is equally
* distributed on the d-dimensional unit sphere with angle @a theta. The angle @a theta
* measures from the abscissa.
* @param theta the spherical angle.
*/
public Vector3f getRandomRotVector(float theta) {
float phi = 2.0f * (float) Math.PI * fdraw();
if (d == 3) {
Vector3f v = new Vector3f();
v.x = (float) Math.cos(theta);
v.y = (float) Math.sin(phi) * (float) Math.sin(theta);
v.z = (float) -Math.cos(phi) * (float) Math.sin(theta);
return v;
}
return null;
}
public static Vector3f rotVectorY(float theta, Vector3f v) {
v.x = v.x * (float) Math.cos(theta) + v.z * (float) Math.sin(theta);
v.z = v.x * (float) -Math.sin(theta) + v.z * (float) Math.cos(theta);
return v;
}
/**
* Function for a random space vector. It computes and returns a vector which is equally
* distributed on the d-dimensional unit sphere with angle @a theta. The angle @a theta
* measures from the abscissa.
* @param theta the spherical angle.
*/
public Vector3f getRandomRotVector(float theta, float range) {
float rand = (fdraw() + range);
float phi = 2.0f * (float) Math.PI * rand;
if (d == 3) {
Vector3f v = new Vector3f();
v.x = (float) Math.cos(theta);
v.y = (float) Math.sin(phi) * (float) Math.sin(theta);
v.z = (float) -Math.cos(phi) * (float) Math.sin(theta);
return v;
}
return null;
}
/**
* Function for a random space vector. It computes and returns a vector which is equally
* distributed on the d-dimensional unit sphere with angle @a theta. The angle @a theta
* measures from the abscissa.
* @param theta the spherical angle.
*/
/*
public float[] getRandomRotVector(float theta) {
float phi = 2.0f * (float) Math.PI * fdraw();
if (d == 2) {
float[] v = new float[2];
v[0] = (float) Math.cos(theta);
v[1] = (float) Math.sin(theta);
return v;
}
if (d == 3) {
float[] v = new float[3];
v[0] = (float) Math.cos(theta);
v[1] = (float) Math.sin(phi) * (float) Math.sin(theta);
v[2] = (float) -Math.cos(phi) * (float) Math.sin(theta);
return v;
}
return null;
}
*
*/
/**
* Function for a random space vector. It computes and returns a vector which is equally
* distributed on the d-dimensional unit sphere with angle @a theta around the given direction
* vector @a vd. It works only for three dimensions.
* @param theta the spherical angle.
* @param vd the vector of direction.
*/
public Vector3f getRandomRotVector(float theta, Vector3f vd) {
Vector3f direction = new Vector3f();
direction.add(vd);
direction.normalize();
float vd_phi = (float) Math.atan2(direction.y, direction.x);
// angles of the vector of direction
float vd_theta = (float) Math.acos(direction.z);
float sin_phi = (float) Math.sin(vd_phi);
float cos_phi = (float) Math.cos(vd_phi);
float sin_theta = (float) Math.sin(vd_theta);
float cos_theta = (float) Math.cos(vd_theta);
// generate a vector around the z-axis
Vector3f v = new Vector3f();
float phi = 2.0f * (float) Math.PI * fdraw();
v.x = (float) Math.cos(phi) * (float) Math.sin(theta);
v.y = (float) Math.sin(phi) * (float) Math.sin(theta);
v.z = (float) Math.cos(theta);
// rotate the vector around the y-axis
Vector3f v1 = new Vector3f();
v1.x = cos_theta * v.x - sin_theta * v.z;
v1.y = v.y;
v1.z = sin_theta * v.x + cos_theta * v.z;
// rotate the vector around the z-axis
Vector3f v2 = new Vector3f();
v2.x = cos_phi * v1.x + sin_phi * v1.y;
v2.y = -sin_phi * v1.x + cos_phi * v1.y;
v2.z = v1.z;
v2.x *= -1.0f;
if (v2.length() == 0.0) {
return v2;
}
v2.normalize();
return v2;
}
/**
* Function for a random space vector. It computes and returns a vector which is equally
* distributed on the d-dimensional unit sphere with angle @a theta around the given direction
* vector @a vd. It works only for three dimensions.
* @param theta the spherical angle.
* @param vd the vector of direction.
*/
public Vector3f getRandomRotVector(float theta, Vector3f vd, float range) {
//theta = (float) Math.toRadians(theta);
//range = (float) Math.toRadians(range);
Vector3f direction = new Vector3f();
direction.add(vd);
direction.normalize();
float vd_phi = (float) Math.atan2(direction.y, direction.x);
// angles of the vector of direction
float vd_theta = (float) Math.acos(direction.z);
float sin_phi = (float) Math.sin(vd_phi);
float cos_phi = (float) Math.cos(vd_phi);
float sin_theta = (float) Math.sin(vd_theta);
float cos_theta = (float) Math.cos(vd_theta);
// generate a vector around the z-axis
Vector3f v = new Vector3f();
float rand = fdraw() + range;
float phi = 2.0f * (float) Math.PI * rand;
v.x = (float) Math.cos(phi) * (float) Math.sin(theta);
v.y = (float) Math.sin(phi) * (float) Math.sin(theta);
v.z = (float) Math.cos(theta);
// rotate the vector around the y-axis
Vector3f v1 = new Vector3f();
v1.x = cos_theta * v.x - sin_theta * v.z;
v1.y = v.y;
v1.z = sin_theta * v.x + cos_theta * v.z;
// rotate the vector around the z-axis
Vector3f v2 = new Vector3f();
v2.x = cos_phi * v1.x + sin_phi * v1.y;
v2.y = -sin_phi * v1.x + cos_phi * v1.y;
v2.z = v1.z;
v2.x *= -1.0f;
if (v2.length() == 0.0) {
return v2;
}
v2.normalize();
return v2;
}
public Vector3f getRotVector(float theta, Vector3f vd, float phi) {
Vector3f direction = new Vector3f();
direction.add(vd);
direction.normalize();
float vd_phi = (float) Math.atan2(direction.y, direction.x);
// angles of the vector of direction
float vd_theta = (float) Math.acos(direction.z);
float sin_phi = (float) Math.sin(vd_phi);
float cos_phi = (float) Math.cos(vd_phi);
float sin_theta = (float) Math.sin(vd_theta);
float cos_theta = (float) Math.cos(vd_theta);
// generate a vector around the z-axis
Vector3f v = new Vector3f();
//float phi = 2.0f * (float) Math.PI * rand;
v.x = (float) Math.cos(phi) * (float) Math.sin(theta);
v.y = (float) Math.sin(phi) * (float) Math.sin(theta);
v.z = (float) Math.cos(theta);
// rotate the vector around the y-axis
Vector3f v1 = new Vector3f();
v1.x = cos_theta * v.x - sin_theta * v.z;
v1.y = v.y;
v1.z = sin_theta * v.x + cos_theta * v.z;
// rotate the vector around the z-axis
Vector3f v2 = new Vector3f();
v2.x = cos_phi * v1.x + sin_phi * v1.y;
v2.y = -sin_phi * v1.x + cos_phi * v1.y;
v2.z = v1.z;
v2.x *= -1.0f;
if (v2.length() == 0.0) {
return v2;
}
v2.normalize();
return v2;
}
/**
* Function for a random space vector. It computes and returns a vector which is equally
* distributed on the two-dimensional plane which is orthogonal to the given direction
* vector \a n_vector. The returned vector has unit length and is shrinked to an ellipse due to
* the given deviation vector \a rotation_dev. For the default case \a rotation_dev=1, the
* random vector lies on the circle line. The function works only for three dimensions.
*/
public float[] getRandomRotOrthogonal() {
if (d == 3) {
//n_vector /= length(n_vector);
normalVector.normalize();
float vd_phi = (float) Math.atan2(normalVector.y, normalVector.x);
// angles of the vector of direction
float vd_theta = (float) Math.acos(normalVector.z);
float sin_phi = (float) Math.sin(vd_phi);
float cos_phi = (float) Math.cos(vd_phi);
float sin_theta = (float) Math.sin(vd_theta);
float cos_theta = (float) Math.cos(vd_theta);
//valarray<float> v1(3), v2(3);
float[] v1 = new float[3];
float[] v2 = new float[3];
float phi = 2.0f * (float) Math.PI * fdraw();
v1[0] = cos_theta * (float) Math.cos(phi) * rotationDeviation.x;
v1[1] = (float) Math.sin(phi) * rotationDeviation.y;
v1[2] = sin_theta * (float) Math.cos(phi) * rotationDeviation.x;
// rotate the vector around the z-axis
v2[0] = cos_phi * v1[0] + sin_phi * v1[1];
v2[1] = -sin_phi * v1[0] + cos_phi * v1[1];
v2[2] = v1[2];
v2[0] *= -1.0f;
if (length(v2) == 0.0) {
return v2;
} else {
return div(v2, length(v2));
}
}
return null;
}
/**
* Function for a random space vector. It computes and returns a vector which is equally
* distributed on the two-dimensional plane which is orthogonal to the given direction
* vector \a vd. The returned vector has unit length and is shrinked to an ellipse due to
* the given deviation vector \a rotation_dev. For the default case \a rotation_dev=(1,1,1), the
* random vector lies on the circle line. The function works only for three dimensions.
* \param vd the vector of direction.
*/
public Vector3f getRandomRotOrthogonal(Vector3f vd) {
if (d == 3) {
//vd /= length(vd);
Vector3f direction = new Vector3f(vd);
direction.normalize();
float vd_phi = (float) Math.atan2(direction.y, direction.x);
// angles of the vector of direction
float vd_theta = (float) Math.acos(direction.z);
float sin_phi = (float) Math.sin(vd_phi);
float cos_phi = (float) Math.cos(vd_phi);
float sin_theta = (float) Math.sin(vd_theta);
float cos_theta = (float) Math.cos(vd_theta);
float[] v1 = new float[3];
float[] v2 = new float[3];
//valarray<float> v1(3), v2(3);
float phi = 2.0f * (float) Math.PI * fdraw();
v1[0] = cos_theta * (float) Math.cos(phi) * rotationDeviation.x;
v1[1] = (float) Math.sin(phi) * rotationDeviation.y;
v1[2] = sin_theta * (float) Math.cos(phi) * rotationDeviation.x;
// rotate the vector around the z-axis
v2[0] = cos_phi * v1[0] + sin_phi * v1[1];
v2[1] = -sin_phi * v1[0] + cos_phi * v1[1];
v2[2] = v1[2];
v2[0] *= -1.0f;
if (length(v2) == 0.0) {
return new Vector3f(v2);
} else {
Vector3f dir = new Vector3f(v2);
dir.normalize();
return dir;
}
}
return null;
}
/** Set the deviation for the random rotation vector orthogonal to a given direction. */
public void setRotDeviation(Vector3f rd) {
rotationDeviation = rd;
}
/** Set the normal vector for the plane for generating random vectors within the plane. */
public void setRotNormal(Vector3f n) {
normalVector = n;
}
}