ROOT logo
// $Id: PSTorus.cxx 2182 2009-04-12 23:11:16Z matevz $

// Copyright (C) 1999-2008, Matevz Tadel. All rights reserved.
// This file is part of GLED, released under GNU General Public License version 2.
// For the licensing terms see $GLEDSYS/LICENSE or http://www.gnu.org/.

//__________________________________________________________________________
// PSTorus
//
// Parametric toroidal surface.
// bInside ~ false: 'world' on outer surface
// bInside ~ true:  'world' on inner surface
//
//   | Outside             | Inside
//-----------------------------------------------
// f | phi   [-pi, pi ] | phi   [inverted]
// g | theta [-pi, pi ] | theta [same    ]
// h | dr    [-mR, inf] | dr    [mR, -inf]
//
// f,g,h vectors form a right-handed ortho-normal base.
// 'outside' -> 'inside' : { f -> -f, h -> -h. }


#include "PSTorus.h"
#include "PSTorus.c7"

#include "PSSphere.h"
#include <Stones/GravData.h>

#include <Opcode/Opcode.h>

#include <TMath.h>
#include <TRandom.h>

ClassImp(PSTorus);

/**************************************************************************/

void PSTorus::_init()
{
  bInside = false;
  mRM = 1;
  mRm = 0.5;
}

/**************************************************************************/

void PSTorus::FindMinMaxFGH(TriMesh* mesh)
{
  PARENT_GLASS::FindMinMaxH(mesh);

  mMinF = -sPi; mMaxF = sPi;
  mMinG = -sPi; mMaxG = sPi;
}

/**************************************************************************/

namespace {
inline float norm3(float x, float y, float z)
{ return sqrtf(x*x + y*y + z*z); }
}

/**************************************************************************/

Float_t PSTorus::Surface()
{
  return 4.0f*sPi*sPi*mRM*mRm;
}

/******************************************************************************/

void PSTorus::pos2fgh(const Float_t* x, Float_t* f)
{
  f[0] = atan2f(x[1], x[0]);
  f[1] = atan2f(x[2], sqrtf(x[0]*x[0] + x[1]*x[1]) - mRM);
  f[2] = norm3(x[0] - mRM*cosf(f[0]), x[1] - mRM*sinf(f[0]), x[2]) - mRm;
  if (bInside) { f[0] = -f[0]; f[2] = -f[2]; }
}

void PSTorus::fgh2pos(const Float_t* f, Float_t* x)
{
  const Float_t rphi = bInside ? mRm - f[2] : mRm + f[2];
  const Float_t rxy  = mRM + rphi*cosf(f[1]);

  x[0] = rxy  * cosf(f[0]); // cos is even
  x[1] = rxy  * sinf(f[0]); if (bInside) x[1] = -x[1];
  x[2] = rphi * sinf(f[1]);
}

void PSTorus::fgh2fdir(const Float_t* f, Float_t* d)
{
  d[0] = -sinf(f[0]);
  d[1] =  cosf(f[0]);
  d[2] =  0;
  if (bInside) {
    // d[0] = -d[0]; already negated by phi inversion and oddness of sin
    d[1] = -d[1];
    // d[2] = -d[2]; zero
  }
}

void PSTorus::fgh2gdir(const Float_t* f, Float_t* d)
{
  const Float_t st = -sinf(f[1]);

  d[0] = st * cosf(f[0]);
  d[1] = st * sinf(f[0]); if (bInside) d[1] = -d[1];
  d[2] = cosf(f[1]);
}

void PSTorus::fgh2hdir(const Float_t* f, Float_t* d)
{
  const Float_t ct = cosf(f[1]);

  d[0] = ct * cosf(f[0]);
  d[1] = ct * sinf(f[0]);
  d[2] = sinf(f[1]);
  if (bInside) {
    d[0] = -d[0];
    // d[1] = -d[1]; already negated by phi inversion and oddness of sin
    d[2] = -d[2];
  }
}

/**************************************************************************/

void PSTorus::pos2hdir(const Float_t* x, Float_t* d)
{
  // Return 'up' direction.

  const Float_t p  = atan2f(x[1], x[0]);
  const Float_t t  = atan2f(x[2], sqrtf(x[0]*x[0] + x[1]*x[1]) - mRM);
  const Float_t ct = cosf(t);

  d[0] = ct*cosf(p);
  d[1] = ct*sinf(p);
  d[2] = sinf(t);
  if (bInside) {
    d[0] = -d[0]; d[1] = -d[1]; d[2] = -d[2];
  }
}

Float_t PSTorus::pos2hray(const Float_t* x, Opcode::Ray& r)
{
  // Setup ray r for given postition x so that the ray origin is above
  // the surface and its direction/lenght ascertain the surface will
  // be intersected.
  // Returns distance the ray-origin was shifted from initial pos.

  const Float_t p  = atan2f(x[1], x[0]);
  const Float_t t  = atan2f(x[2], sqrtf(x[0]*x[0] + x[1]*x[1]) - mRM);
  const Float_t ct = cosf(t);
  const Float_t sp = sinf(p), cp = cosf(p);

  Float_t dr = norm3(x[0] - mRM*cp, x[1] - mRM*sp, x[2]) - mRm;
  r.mDir.Set(ct*cp, ct*sp, sinf(t));
  if (bInside) {
    r.mDir.Neg();
    dr = -dr;
  }
  Float_t dist = mMaxH - dr + mEpsilon;

  r.mOrig.Set(x);
  r.mOrig.TMac(r.mDir, dist);
  r.mDir.Neg();
  /*
  printf("pos=%.2f,%.2f,%.2f; orig=%.2f,%.2f,%.2f; dir=%.2f,%.2f,%.2f; dist=%.2f\n",
         x[0],      x[1],      x[2],
         r.mOrig.x, r.mOrig.y, r.mOrig.z,
         r.mDir.x,  r.mDir.y,  r.mDir.z,
         dist);
  */
  return dist;
}

/**************************************************************************/

void PSTorus::pos2grav(const Float_t* x, GravData& gd)
{
  // The gravity is always composed from two spherical contributions
  // of two "gravity centers" on the ring - the first one on the
  // closest point and the second on the opposite side.
  //
  // This is not trully toroidal field - but is easy to calculate and
  // I guess it does not deviate significantly from the true one.
  //
  // If somebody feels adventurous enough to try implementing the true
  // gravitational field of the torus - be my guest.

  gd.fPos[0] = x[0]; gd.fPos[1] = x[1]; gd.fPos[2] = x[2];

  const Float_t q  = sqrtf(x[0]*x[0] + x[1]*x[1]);

  // This trick below, the subtraction of phi-R-shift is neat. Could
  // also reuse it in pos2hdir and pos2hray?

  // Shift from origin to the closest point at the center-line of the torus.
  Opcode::Point phi_R_shift(x[0], x[1], 0);
  phi_R_shift *= mRM / q;

  Opcode::Point near(x); near -= phi_R_shift;
  Opcode::Point far (x); far  += phi_R_shift;

  GravData gd1, gd2;
  GravData::lGravFraction_t gf_list;

  PSSphere::fill_spherical_grav(mGravAtSurface, mRm, bInside, near, gd1);
  gf_list.push_back(make_pair(1.0f, &gd1));

  PSSphere::fill_spherical_grav(mGravAtSurface, mRm, bInside, far,  gd2);
  gf_list.push_back(make_pair(1.0f, &gd2));

  gd.Combine(gf_list);

  // Fix height to the closest point on the ring.
  gd.fH     = gd1.fH;
  gd.Down() = gd1.Down();
}

/**************************************************************************/

void PSTorus::sub_fgh(Float_t* a, Float_t* b, Float_t* delta)
{
  // Subtract fgh values, taking care of U(1) variables (like angles).
  // Here this is done for phi and theta.

  delta[0] = U1Sub(a[0], b[0]);
  delta[1] = U1Sub(a[1], b[1]);
  delta[2] = a[2] - b[2];
}

void PSTorus::regularize_fg(Float_t* f)
{
  // Put fg values into regular intervals.

  if (f[0] > sPi)       f[0] -= sTwoPi;
  else if (f[0] < -sPi) f[0] += sTwoPi;

  if (f[1] > sPi)       f[1] -= sTwoPi;
  else if (f[1] < -sPi) f[1] += sTwoPi;
}

void PSTorus::random_fgh(TRandom& rnd, Float_t* f)
{
  const Float_t k  = mRm/mRM;
  const Float_t P  = rnd.Uniform(-TMath::Pi(), TMath::Pi());
  Float_t t = P, d = 0;
  do {
    d  = (P - t - k*sinf(t)) / (1 + k*cosf(t));
    t += d;
  } while (fabsf(d) > 1e-6);

  f[0] = rnd.Uniform(-TMath::Pi(), TMath::Pi());
  f[1] = t;
  f[2] = 0;
}

/**************************************************************************/
 PSTorus.cxx:1
 PSTorus.cxx:2
 PSTorus.cxx:3
 PSTorus.cxx:4
 PSTorus.cxx:5
 PSTorus.cxx:6
 PSTorus.cxx:7
 PSTorus.cxx:8
 PSTorus.cxx:9
 PSTorus.cxx:10
 PSTorus.cxx:11
 PSTorus.cxx:12
 PSTorus.cxx:13
 PSTorus.cxx:14
 PSTorus.cxx:15
 PSTorus.cxx:16
 PSTorus.cxx:17
 PSTorus.cxx:18
 PSTorus.cxx:19
 PSTorus.cxx:20
 PSTorus.cxx:21
 PSTorus.cxx:22
 PSTorus.cxx:23
 PSTorus.cxx:24
 PSTorus.cxx:25
 PSTorus.cxx:26
 PSTorus.cxx:27
 PSTorus.cxx:28
 PSTorus.cxx:29
 PSTorus.cxx:30
 PSTorus.cxx:31
 PSTorus.cxx:32
 PSTorus.cxx:33
 PSTorus.cxx:34
 PSTorus.cxx:35
 PSTorus.cxx:36
 PSTorus.cxx:37
 PSTorus.cxx:38
 PSTorus.cxx:39
 PSTorus.cxx:40
 PSTorus.cxx:41
 PSTorus.cxx:42
 PSTorus.cxx:43
 PSTorus.cxx:44
 PSTorus.cxx:45
 PSTorus.cxx:46
 PSTorus.cxx:47
 PSTorus.cxx:48
 PSTorus.cxx:49
 PSTorus.cxx:50
 PSTorus.cxx:51
 PSTorus.cxx:52
 PSTorus.cxx:53
 PSTorus.cxx:54
 PSTorus.cxx:55
 PSTorus.cxx:56
 PSTorus.cxx:57
 PSTorus.cxx:58
 PSTorus.cxx:59
 PSTorus.cxx:60
 PSTorus.cxx:61
 PSTorus.cxx:62
 PSTorus.cxx:63
 PSTorus.cxx:64
 PSTorus.cxx:65
 PSTorus.cxx:66
 PSTorus.cxx:67
 PSTorus.cxx:68
 PSTorus.cxx:69
 PSTorus.cxx:70
 PSTorus.cxx:71
 PSTorus.cxx:72
 PSTorus.cxx:73
 PSTorus.cxx:74
 PSTorus.cxx:75
 PSTorus.cxx:76
 PSTorus.cxx:77
 PSTorus.cxx:78
 PSTorus.cxx:79
 PSTorus.cxx:80
 PSTorus.cxx:81
 PSTorus.cxx:82
 PSTorus.cxx:83
 PSTorus.cxx:84
 PSTorus.cxx:85
 PSTorus.cxx:86
 PSTorus.cxx:87
 PSTorus.cxx:88
 PSTorus.cxx:89
 PSTorus.cxx:90
 PSTorus.cxx:91
 PSTorus.cxx:92
 PSTorus.cxx:93
 PSTorus.cxx:94
 PSTorus.cxx:95
 PSTorus.cxx:96
 PSTorus.cxx:97
 PSTorus.cxx:98
 PSTorus.cxx:99
 PSTorus.cxx:100
 PSTorus.cxx:101
 PSTorus.cxx:102
 PSTorus.cxx:103
 PSTorus.cxx:104
 PSTorus.cxx:105
 PSTorus.cxx:106
 PSTorus.cxx:107
 PSTorus.cxx:108
 PSTorus.cxx:109
 PSTorus.cxx:110
 PSTorus.cxx:111
 PSTorus.cxx:112
 PSTorus.cxx:113
 PSTorus.cxx:114
 PSTorus.cxx:115
 PSTorus.cxx:116
 PSTorus.cxx:117
 PSTorus.cxx:118
 PSTorus.cxx:119
 PSTorus.cxx:120
 PSTorus.cxx:121
 PSTorus.cxx:122
 PSTorus.cxx:123
 PSTorus.cxx:124
 PSTorus.cxx:125
 PSTorus.cxx:126
 PSTorus.cxx:127
 PSTorus.cxx:128
 PSTorus.cxx:129
 PSTorus.cxx:130
 PSTorus.cxx:131
 PSTorus.cxx:132
 PSTorus.cxx:133
 PSTorus.cxx:134
 PSTorus.cxx:135
 PSTorus.cxx:136
 PSTorus.cxx:137
 PSTorus.cxx:138
 PSTorus.cxx:139
 PSTorus.cxx:140
 PSTorus.cxx:141
 PSTorus.cxx:142
 PSTorus.cxx:143
 PSTorus.cxx:144
 PSTorus.cxx:145
 PSTorus.cxx:146
 PSTorus.cxx:147
 PSTorus.cxx:148
 PSTorus.cxx:149
 PSTorus.cxx:150
 PSTorus.cxx:151
 PSTorus.cxx:152
 PSTorus.cxx:153
 PSTorus.cxx:154
 PSTorus.cxx:155
 PSTorus.cxx:156
 PSTorus.cxx:157
 PSTorus.cxx:158
 PSTorus.cxx:159
 PSTorus.cxx:160
 PSTorus.cxx:161
 PSTorus.cxx:162
 PSTorus.cxx:163
 PSTorus.cxx:164
 PSTorus.cxx:165
 PSTorus.cxx:166
 PSTorus.cxx:167
 PSTorus.cxx:168
 PSTorus.cxx:169
 PSTorus.cxx:170
 PSTorus.cxx:171
 PSTorus.cxx:172
 PSTorus.cxx:173
 PSTorus.cxx:174
 PSTorus.cxx:175
 PSTorus.cxx:176
 PSTorus.cxx:177
 PSTorus.cxx:178
 PSTorus.cxx:179
 PSTorus.cxx:180
 PSTorus.cxx:181
 PSTorus.cxx:182
 PSTorus.cxx:183
 PSTorus.cxx:184
 PSTorus.cxx:185
 PSTorus.cxx:186
 PSTorus.cxx:187
 PSTorus.cxx:188
 PSTorus.cxx:189
 PSTorus.cxx:190
 PSTorus.cxx:191
 PSTorus.cxx:192
 PSTorus.cxx:193
 PSTorus.cxx:194
 PSTorus.cxx:195
 PSTorus.cxx:196
 PSTorus.cxx:197
 PSTorus.cxx:198
 PSTorus.cxx:199
 PSTorus.cxx:200
 PSTorus.cxx:201
 PSTorus.cxx:202
 PSTorus.cxx:203
 PSTorus.cxx:204
 PSTorus.cxx:205
 PSTorus.cxx:206
 PSTorus.cxx:207
 PSTorus.cxx:208
 PSTorus.cxx:209
 PSTorus.cxx:210
 PSTorus.cxx:211
 PSTorus.cxx:212
 PSTorus.cxx:213
 PSTorus.cxx:214
 PSTorus.cxx:215
 PSTorus.cxx:216
 PSTorus.cxx:217
 PSTorus.cxx:218
 PSTorus.cxx:219
 PSTorus.cxx:220
 PSTorus.cxx:221
 PSTorus.cxx:222
 PSTorus.cxx:223
 PSTorus.cxx:224
 PSTorus.cxx:225
 PSTorus.cxx:226
 PSTorus.cxx:227
 PSTorus.cxx:228
 PSTorus.cxx:229
 PSTorus.cxx:230
 PSTorus.cxx:231
 PSTorus.cxx:232
 PSTorus.cxx:233
 PSTorus.cxx:234
 PSTorus.cxx:235
 PSTorus.cxx:236
 PSTorus.cxx:237
 PSTorus.cxx:238
 PSTorus.cxx:239
 PSTorus.cxx:240
 PSTorus.cxx:241
 PSTorus.cxx:242
 PSTorus.cxx:243
 PSTorus.cxx:244
 PSTorus.cxx:245
 PSTorus.cxx:246
 PSTorus.cxx:247
 PSTorus.cxx:248
 PSTorus.cxx:249
 PSTorus.cxx:250
 PSTorus.cxx:251
 PSTorus.cxx:252
 PSTorus.cxx:253
 PSTorus.cxx:254
 PSTorus.cxx:255
 PSTorus.cxx:256
 PSTorus.cxx:257
 PSTorus.cxx:258