Import Geant4 10.0.0 source tree

This commit is contained in:
Gabriele Cosmo
2016-06-10 11:51:14 +02:00
parent e2d2f9810a
commit 286caacf06
12421 changed files with 730077 additions and 502383 deletions
@@ -0,0 +1,18 @@
#------------------------------------------------------------------------------
# CMakeLists.txt
# Module : G4geomUsolids
# Package: Geant4.src.G4geometry.G4geomUSolids
#
# CMakeLists.txt for building a single granular library.
#
# Generated on : 24/9/2010
#
# $Id: CMakeLists.txt 66356 2012-12-18 09:02:32Z gcosmo $
#
#------------------------------------------------------------------------------
if(GEANT4_BUILD_GRANULAR_LIBS)
include(Geant4MacroLibraryTargets)
GEANT4_GRANULAR_LIBRARY_TARGET(COMPONENT sources.cmake)
endif()
@@ -0,0 +1,25 @@
# $Id: GNUmakefile 66356 2012-12-18 09:02:32Z gcosmo $
# --------------------------------------------------------------------
# GNUmakefile for geometry/usolids library. Gabriele Cosmo, 16/11/96.
# --------------------------------------------------------------------
name := G4geomUSolids
ifndef G4INSTALL
G4INSTALL = ../../../..
endif
include $(G4INSTALL)/config/architecture.gmk
CPPFLAGS += -DG4GEOM_ALLOC_EXPORT
CPPFLAGS += -I$(G4BASE)/intercoms/include \
-I$(G4BASE)/graphics_reps/include \
-I$(G4BASE)/global/management/include \
-I$(G4BASE)/global/HEPGeometry/include \
-I$(G4BASE)/geometry/management/include \
ifdef G4USOLDEBUG
CPPFLAGS += -DG4USOLDEBUG
endif
include $(G4INSTALL)/config/common.gmk
+67
View File
@@ -0,0 +1,67 @@
$Id: History 74238 2013-10-02 08:51:17Z gcosmo $
-------------------------------------------------------------------
=========================================================
Geant4 - an Object-Oriented Toolkit for Simulation in HEP
=========================================================
Sub-Category History file
-------------------------
This file should be used by G4 developers and category coordinators
to briefly summarize all major modifications introduced in the code
and keep track of all directory-tags.
It DOES NOT substitute the CVS log-message one should put at every
committal in the CVS repository !
----------------------------------------------------------
* Reverse chronological order (last date on top), please *
----------------------------------------------------------
November 29, 2013 G.Cosmo geom-usolids-V09-06-11
- Corrected library name in GNUmakefile and fixed comment in sources.cmake.
November 21, 2013 G.Cosmo geom-usolids-V09-06-10
- Fixed compilation warning for type conversion in UVCSGfaceted
constructor.
November 20, 2013 T.Mikitina geom-usolids-V09-06-09
- Fixed Coverity defects.
November 14, 2013 T.Mikitina geom-usolids-V09-06-08
- Corrected visualization methods in bridge G4USolid.
- Corrected returned type string from USolids and added Reset()
method to UPolycone.
November 13, 2013 G.Cosmo geom-usolids-V09-06-07
- Removed useless dependency on UMultiUnion in UPolycone.
November 13, 2013 G.Cosmo geom-usolids-V09-06-06
- Leave out UMultiUnion, as not yet ready for release.
November 12, 2013 T.Nikitina geom-usolids-V09-06-05
- Corrected passing of parameters for normal in G4USolid::DistanceToOut(p,v).
November 7, 2013 G.Cosmo geom-usolids-V09-06-04
- Moved wrappers to associated modules.
- Added missing accessor method to UTrd.
November 5, 2013 G.Cosmo geom-usolids-V09-06-03
- Code cleanup and added banners to USolids files.
November 1, 2013 G.Cosmo geom-usolids-V09-06-02
- Fixed compilation error and warnings on SLC6.
November 1, 2013 G.Cosmo geom-usolids-V09-06-01
- Added wrappers for Ubox, Ucons, UGenericPolycone, UMultiUnion, UOrb,
UPolycone, UPolyhedra, USphere, UTet, UTrd, UTubs.
Removed all other shapes not covered by the wrappers (will be included
in a later stage).
- Updated CMake script accordingly.
October 29, 2013 G.Cosmo geom-usolids-V09-06-00
- Imported classes from the AIDA Unified Solids Library
(see https://aidasoft.web.cern.ch/USolids).
Shapes provided: Ubox, Ucons, UGenericPolycone, UMultiUnion, UOrb,
UPolycone, UPolyhedra, USphere, UTet, UTrd, UTubs (including also
shapes not foreseen to be wrapped as first stage).
- Includes bridge class G4USolid and first wrapper class G4UBox.
@@ -0,0 +1,183 @@
//
// ********************************************************************
// * License and Disclaimer *
// * *
// * The Geant4 software is copyright of the Copyright Holders of *
// * the Geant4 Collaboration. It is provided under the terms and *
// * conditions of the Geant4 Software License, included in the file *
// * LICENSE and available at http://cern.ch/geant4/license . These *
// * include a list of copyright holders. *
// * *
// * Neither the authors of this software system, nor their employing *
// * institutes,nor the agencies providing financial support for this *
// * work make any representation or warranty, express or implied, *
// * regarding this software system or assume any liability for its *
// * use. Please see the license in the file LICENSE and URL above *
// * for the full disclaimer and the limitation of liability. *
// * *
// * This code implementation is the result of the scientific and *
// * technical work of the GEANT4 collaboration. *
// * By using, copying, modifying or distributing the software (or *
// * any work based on the software) you agree to acknowledge its *
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
//
// $Id:$
// GEANT4 tag $Name:$
//
//
// class G4USolid
//
// Class description:
//
// Bridge base class for solids defined in the Unified Solids Library.
// --------------------------------------------------------------------
#ifndef G4USolid_HH
#define G4USolid_HH
#include "G4VSolid.hh"
#include "VUSolid.hh"
class G4USolid : public G4VSolid
{
public: // with description
G4USolid(const G4String& pName, VUSolid* shape);
// Creates a new shape, with the supplied name. No provision is made
// for sharing a common name amongst multiple classes.
virtual ~G4USolid();
// Default destructor.
G4bool operator==(const G4USolid& s) const;
// Return true only if addresses are the same.
virtual G4bool CalculateExtent(const EAxis pAxis,
const G4VoxelLimits& pVoxelLimit,
const G4AffineTransform& pTransform,
G4double& pMin, G4double& pMax) const;
// Calculate the minimum and maximum extent of the solid, when under the
// specified transform, and within the specified limits. If the solid
// is not intersected by the region, return false, else return true.
virtual EInside Inside(const G4ThreeVector& p) const;
// Returns kOutside if the point at offset p is outside the shapes
// boundaries plus Tolerance/2, kSurface if the point is <= Tolerance/2
// from a surface, otherwise kInside.
virtual G4ThreeVector SurfaceNormal(const G4ThreeVector& p) const;
// Returns the outwards pointing unit normal of the shape for the
// surface closest to the point at offset p.
virtual G4double DistanceToIn(const G4ThreeVector& p,
const G4ThreeVector& v) const;
// Return the distance along the normalised vector v to the shape,
// from the point at offset p. If there is no intersection, return
// kInfinity. The first intersection resulting from `leaving' a
// surface/volume is discarded. Hence, it is tolerant of points on
// the surface of the shape.
virtual G4double DistanceToIn(const G4ThreeVector& p) const;
// Calculate the distance to the nearest surface of a shape from an
// outside point. The distance can be an underestimate.
virtual G4double DistanceToOut(const G4ThreeVector& p,
const G4ThreeVector& v,
const G4bool calcNorm = false,
G4bool* validNorm = 0,
G4ThreeVector* n = 0) const;
// Return the distance along the normalised vector v to the shape,
// from a point at an offset p inside or on the surface of the shape.
// Intersections with surfaces, when the point is < Tolerance/2 from a
// surface must be ignored.
// If calcNorm==true:
// validNorm set true if the solid lies entirely behind or on the
// exiting surface.
// n set to exiting outwards normal vector (undefined Magnitude).
// validNorm set to false if the solid does not lie entirely behind
// or on the exiting surface
// If calcNorm==false:
// validNorm and n are unused.
//
// Must be called as solid.DistanceToOut(p,v) or by specifying all
// the parameters.
virtual G4double DistanceToOut(const G4ThreeVector& p) const;
// Calculate the distance to the nearest surface of a shape from an
// inside point. The distance can be an underestimate.
virtual G4double GetCubicVolume();
// Returns an estimation of the solid volume in internal units.
// This method may be overloaded by derived classes to compute the
// exact geometrical quantity for solids where this is possible,
// or anyway to cache the computed value.
// Note: the computed value is NOT cached.
virtual G4double GetSurfaceArea();
// Return an estimation of the solid surface area in internal units.
// This method may be overloaded by derived classes to compute the
// exact geometrical quantity for solids where this is possible,
// or anyway to cache the computed value.
// Note: the computed value is NOT cached.
virtual G4GeometryType GetEntityType() const;
// Provide identification of the class of an object.
// (required for persistency and STEP interface)
virtual G4ThreeVector GetPointOnSurface() const;
// Returns a random point located on the surface of the solid.
virtual G4VSolid* Clone() const;
// Returns a pointer of a dynamically allocated copy of the solid.
// Returns NULL pointer with warning in case the concrete solid does not
// implement this method. The caller has responsibility for ownership.
virtual std::ostream& StreamInfo(std::ostream& os) const;
// Dumps contents of the solid to a stream.
virtual void DescribeYourselfTo(G4VGraphicsScene& scene) const;
// A "double dispatch" function which identifies the solid
// to the graphics scene for visualization.
virtual G4VisExtent GetExtent() const;
// Provide extent (bounding box) as possible hint to the graphics view.
G4Polyhedron* CreatePolyhedron() const;
// Create Polyhedron used for Visualisation
virtual G4Polyhedron* GetPolyhedron() const;
// Smart access function - creates on request and stores for future
// access. A null pointer means "not available".
virtual void ResetPolyhedron() const;
//Reset Polyhedron used by Parametrisation
public: // without description
G4USolid(__void__&);
// Fake default constructor for usage restricted to direct object
// persistency for clients requiring preallocation of memory for
// persistifiable objects.
G4USolid(const G4USolid& rhs);
G4USolid& operator=(const G4USolid& rhs);
// Copy constructor and assignment operator.
VUSolid* GetSolid() const
{
return fShape;
}
protected:
G4ThreeVectorList* CreateRotatedVertices(const G4AffineTransform& pT) const;
protected: // data
VUSolid* fShape;
private:
mutable G4Polyhedron* fPolyhedron;
};
#endif
@@ -0,0 +1,222 @@
//
// ********************************************************************
// * This Software is part of the AIDA Unified Solids Library package *
// * See: https://aidasoft.web.cern.ch/USolids *
// ********************************************************************
//
// $Id:$
//
// --------------------------------------------------------------------
//
// UBits
//
// Class description:
//
// Container of bits
//
// This class provides a simple container of bits.
// Each bit can be set and tested via the functions SetBitNumber and
// TestBitNumber.
// The default value of all bits is false.
// The size of the container is automatically extended when a bit
// number is either set or tested. To reduce the memory size of the
// container use the Compact function, this will discard the memory
// occupied by the upper bits that are 0.
//
// Created for UTessellatedSolid
//
// 19.10.12 Marek Gayer
// Created from original implementation in ROOT (TBits)
// --------------------------------------------------------------------
#ifndef UBits_HH
#define UBits_HH
#include <cstring>
#include <ostream>
class UBits
{
public:
unsigned char* fAllBits; //[fNBytes] array of UChars
protected:
unsigned int fNBits; // Highest bit set + 1
unsigned int fNBytes; // Number of UChars in fAllBits
void ReserveBytes(unsigned int nbytes);
/*
void DoAndEqual(const UBits& rhs);
void DoOrEqual (const UBits& rhs);
void DoXorEqual(const UBits& rhs);
void DoLeftShift(unsigned int shift);
void DoRightShift(unsigned int shift);
void DoFlip();
*/
public:
UBits(unsigned int nbits = 0);
UBits(const UBits&);
UBits& operator=(const UBits& rhs);
virtual ~UBits();
//----- bit manipulation
//----- (note the difference with TObject's bit manipulations)
void ResetAllBits(bool value = false); // if value=1 set all bits to 1
void ResetBitNumber(unsigned int bitnumber);
void SetBitNumber(unsigned int bitnumber, bool value = true);
bool TestBitNumber(unsigned int bitnumber) const;
//----- Accessors and operator
bool operator[](unsigned int bitnumber) const;
/*
UBits& operator&=(const UBits& rhs) { DoAndEqual(rhs); return *this; }
UBits& operator|=(const UBits& rhs) { DoOrEqual(rhs); return *this; }
UBits& operator^=(const UBits& rhs) { DoXorEqual(rhs); return *this; }
UBits& operator<<=(unsigned int rhs) { DoLeftShift(rhs); return *this; }
UBits& operator>>=(unsigned int rhs) { DoRightShift(rhs); return *this; }
UBits operator<<(unsigned int rhs) { return UBits(*this)<<= rhs; }
UBits operator>>(unsigned int rhs) { return UBits(*this)>>= rhs; }
UBits operator~() { UBits res(*this); res.DoFlip(); return res; }
*/
//----- Optimized setters
// Each of these will replace the contents of the receiver with the bitvector
// in the parameter array. The number of bits is changed to nbits. If nbits
// is smaller than fNBits, the receiver will NOT be compacted.
void Set(unsigned int nbits, const char* array);
// void Set(unsigned int nbits, const unsigned char *array) { Set(nbits, (const char*)array); }
// void Set(unsigned int nbits, const short *array);
//void Set(unsigned int nbits, const unsigned short *array) { Set(nbits, (const short*)array); }
void Set(unsigned int nbits, const int* array);
// void Set(unsigned int nbits, const unsigned int *array) { Set(nbits, (const int*)array); }
//----- Optimized getters
// Each of these will replace the contents of the parameter array with the
// bits in the receiver. The parameter array must be large enough to hold
// all of the bits in the receiver.
// Note on semantics: any bits in the parameter array that go beyond the
// number of the bits in the receiver will have an unspecified value. For
// example, if you call Get(Int*) with an array of one integer and the UBits
// object has less than 32 bits, then the remaining bits in the integer will
// have an unspecified value.
void Get(char* array) const;
// void Get(unsigned char *array) const { Get((char*)array); }
// void Get(short *array) const;
// void Get(unsigned short *array) const { Get((short*)array); }
void Get(int* array) const;
// void Get(unsigned int *array) const { Get((int*)array); }
//----- Utilities
void Clear();
void Compact(); // Reduce the space used.
unsigned int GetNbits() const
{
return fNBits;
}
unsigned int GetNbytes() const
{
return fNBytes;
}
/*
unsigned int CounUBits(unsigned int startBit=0) const ; // return number of bits set to 1
unsigned int FirstNullBit(unsigned int startBit=0) const;
unsigned int FirstSetBit(unsigned int startBit=0) const;
*/
// bool operator==(const UBits &other) const;
// bool operator!=(const UBits &other) const { return !(*this==other); }
void Print() const; // to show the list of active bits
void Output(std::ostream&) const;
};
/*
inline UBits operator&(const UBits& lhs, const UBits& rhs)
{
UBits result(lhs);
result &= rhs;
return result;
}
inline UBits operator|(const UBits& lhs, const UBits& rhs)
{
UBits result(lhs);
result |= rhs;
return result;
}
inline UBits operator^(const UBits& lhs, const UBits& rhs)
{
UBits result(lhs);
result ^= rhs;
return result;
}
inline std::ostream &operator<<(std::ostream& os, const UBits& rhs)
{
rhs.Output(os); return os;
}
*/
// inline functions...
inline void UBits::SetBitNumber(unsigned int bitnumber, bool value)
{
// Set bit number 'bitnumber' to be value
if (bitnumber >= fNBits)
{
unsigned int new_size = (bitnumber / 8) + 1;
if (new_size > fNBytes)
{
if (new_size < 100 * 1024 * 1024)
new_size *= 2;
unsigned char* old_location = fAllBits;
fAllBits = new unsigned char[new_size];
std::memcpy(fAllBits, old_location, fNBytes);
std::memset(fAllBits + fNBytes , 0, new_size - fNBytes);
fNBytes = new_size;
delete [] old_location;
}
fNBits = bitnumber + 1;
}
unsigned int loc = bitnumber / 8;
unsigned char bit = bitnumber % 8;
if (value)
fAllBits[loc] |= (1 << bit);
else
fAllBits[loc] &= (0xFF ^ (1 << bit));
}
inline bool UBits::TestBitNumber(unsigned int bitnumber) const
{
// Return the current value of the bit
if (bitnumber >= fNBits) return false;
unsigned int loc = bitnumber / 8;
unsigned char value = fAllBits[loc];
unsigned char bit = bitnumber % 8;
bool result = (value & (1 << bit)) != 0;
return result;
// short: return 0 != (fAllBits[bitnumber/8] & (1<< (bitnumber%8)));
}
inline void UBits::ResetBitNumber(unsigned int bitnumber)
{
SetBitNumber(bitnumber, false);
}
inline bool UBits::operator[](unsigned int bitnumber) const
{
return TestBitNumber(bitnumber);
}
#endif
@@ -0,0 +1,156 @@
//
// ********************************************************************
// * This Software is part of the AIDA Unified Solids Library package *
// * See: https://aidasoft.web.cern.ch/USolids *
// ********************************************************************
//
// $Id:$
//
// --------------------------------------------------------------------
//
// UBox
//
// Class description:
//
// A simple box defined by half-lengths on the three axis.
// The center of the box matches the origin of the local reference frame.
//
// 10.06.11 J.Apostolakis, G.Cosmo, A.Gheata
// Created from original implementation in Geant4 and ROOT
// --------------------------------------------------------------------
#ifndef USOLIDS_UBox
#define USOLIDS_UBox
#ifndef USOLIDS_VUSolid
#include "VUSolid.hh"
#endif
#ifndef USOLIDS_UUtils
#include "UUtils.hh"
#endif
class UBox : public VUSolid
{
public:
UBox() : VUSolid(), fDx(0), fDy(0), fDz(0),fCubicVolume(0.), fSurfaceArea(0.) {}
UBox(const std::string& name, double dx, double dy, double dz);
virtual ~UBox();
UBox(const UBox& rhs);
UBox& operator=(const UBox& rhs);
// Copy constructor and assignment operator
void Set(double dx, double dy, double dz);
void Set(const UVector3& vec);
// Accessors and modifiers
inline double GetXHalfLength() const;
inline double GetYHalfLength() const;
inline double GetZHalfLength() const;
void SetXHalfLength(double dx);
void SetYHalfLength(double dy);
void SetZHalfLength(double dz);
// Navigation methods
EnumInside Inside(const UVector3& aPoint) const;
double SafetyFromInside(const UVector3& aPoint,
bool aAccurate = false) const;
double SafetyFromOutside(const UVector3& aPoint,
bool aAccurate = false) const;
double DistanceToIn(const UVector3& aPoint,
const UVector3& aDirection,
// UVector3 &aNormalVector,
double aPstep = UUtils::kInfinity) const;
double DistanceToOut(const UVector3& aPoint,
const UVector3& aDirection,
UVector3& aNormalVector,
bool& aConvex,
double aPstep = UUtils::kInfinity) const;
bool Normal(const UVector3& aPoint, UVector3& aNormal) const;
// void Extent ( EAxisType aAxis, double &aMin, double &aMax ) const;
void Extent(UVector3& aMin, UVector3& aMax) const;
inline double Capacity();
inline double SurfaceArea();
VUSolid* Clone() const
{
return new UBox(GetName(), fDx, fDy, fDz);
}
UGeometryType GetEntityType() const;
void ComputeBBox(UBBox* /*aBox*/, bool /*aStore = false*/) {}
//G4Visualisation
void GetParametersList(int, double* aArray) const
{
aArray[0] = GetXHalfLength();
aArray[1] = GetYHalfLength();
aArray[2] = GetZHalfLength();
}
UVector3 GetPointOnSurface() const;
std::ostream& StreamInfo(std::ostream& os) const;
private:
double fDx; // Half-length on X
double fDy; // Half-length on Y
double fDz; // Half-length on Z
double fCubicVolume; // Cubic Volume
double fSurfaceArea; // Surface Area
};
inline double UBox::GetXHalfLength() const
{
return fDx;
}
inline double UBox::GetYHalfLength() const
{
return fDy;
}
inline double UBox::GetZHalfLength() const
{
return fDz;
}
inline double UBox::Capacity()
{
if (fCubicVolume != 0.)
{
;
}
else
{
fCubicVolume = 8 * fDx * fDy * fDz;
}
return fCubicVolume;
}
inline double UBox::SurfaceArea()
{
if (fSurfaceArea != 0.)
{
;
}
else
{
fSurfaceArea = 8 * (fDx * fDy + fDx * fDz + fDy * fDz);
}
return fSurfaceArea;
}
#endif
@@ -0,0 +1,302 @@
//
// ********************************************************************
// * This Software is part of the AIDA Unified Solids Library package *
// * See: https://aidasoft.web.cern.ch/USolids *
// ********************************************************************
//
// $Id:$
//
// --------------------------------------------------------------------
//
// UCons
//
// Class description:
//
// A UCons is, in the general case, a Phi segment of a cone, with
// half-length fDz, inner and outer radii specified at -fDz and +fDz.
// The Phi segment is described by a starting fSPhi angle, and the
// +fDPhi delta angle for the shape.
// If the delta angle is >=2*UUtils::kPi, the shape is treated as
// continuous in Phi
//
// Member Data:
//
// fRmin1 inside radius at -fDz
// fRmin2 inside radius at +fDz
// fRmax1 outside radius at -fDz
// fRmax2 outside radius at +fDz
// fDz half length in z
//
// fSPhi starting angle of the segment in radians
// fDPhi delta angle of the segment in radians
//
// fPhiFullCone Boolean variable used for indicate the Phi Section
//
// Note:
// Internally fSPhi & fDPhi are adjusted so that fDPhi<=2PI,
// and fDPhi+fSPhi<=2PI. This enables simpler comparisons to be
// made with (say) Phi of a point.
//
// 19.10.12 Marek Gayer
// Created from original implementation in Geant4
// --------------------------------------------------------------------
#ifndef UCons_HH
#define UCons_HH
#include "VUSolid.hh"
class UCons : public VUSolid
{
public: // with description
UCons(const std::string& pName,
double pRmin1, double pRmax1,
double pRmin2, double pRmax2,
double pDz,
double pSPhi, double pDPhi);
//
// Constructs a cone with the given name and dimensions
~UCons() ;
//
// Destructor
// Accessors
inline double GetInnerRadiusMinusZ() const;
inline double GetOuterRadiusMinusZ() const;
inline double GetInnerRadiusPlusZ() const;
inline double GetOuterRadiusPlusZ() const;
inline double GetZHalfLength() const;
inline double GetStartPhiAngle() const;
inline double GetDeltaPhiAngle() const;
// Modifiers
inline void SetInnerRadiusMinusZ(double Rmin1);
inline void SetOuterRadiusMinusZ(double Rmax1);
inline void SetInnerRadiusPlusZ(double Rmin2);
inline void SetOuterRadiusPlusZ(double Rmax2);
inline void SetZHalfLength(double newDz);
inline void SetStartPhiAngle(double newSPhi, bool trig = true);
inline void SetDeltaPhiAngle(double newDPhi);
// Other methods for solid
inline double GetCubicVolume();
inline double GetSurfaceArea();
// inline VUSolid::EnumInside Inside( const UVector3& p ) const;
bool Normal(const UVector3& p, UVector3& n) const;
double DistanceToIn(const UVector3& p, const UVector3& v, double aPstep = UUtils::kInfinity) const;
double SafetyFromOutside(const UVector3& p, bool precise) const;
double DistanceToOut(const UVector3& aPoint,
const UVector3& aDirection,
UVector3& aNormalVector,
bool& aConvex,
double aPstep = UUtils::kInfinity) const;
double SafetyFromInside(const UVector3& p, bool precise) const;
UGeometryType GetEntityType() const;
UVector3 GetPointOnSurface() const;
VUSolid* Clone() const;
std::ostream& StreamInfo(std::ostream& os) const;
// void Extent (EAxisType aAxis, double &aMin, double &aMax) const;
void Extent(UVector3& aMin, UVector3& aMax) const;
virtual void GetParametersList(int /*aNumber*/, double* /*aArray*/) const;
virtual void ComputeBBox(UBBox* /*aBox*/, bool /*aStore = false*/) {}
// Visualisation functions
inline VUSolid::EnumInside Inside(const UVector3& p) const
{
double r2, rl, rh, pPhi, tolRMin, tolRMax; // rh2, rl2;
VUSolid::EnumInside in;
static const double halfCarTolerance = VUSolid::Tolerance() * 0.5;
static const double halfRadTolerance = kRadTolerance * 0.5;
static const double halfAngTolerance = kAngTolerance * 0.5;
if (std::fabs(p.z) > fDz + halfCarTolerance)
{
return in = eOutside;
}
else if (std::fabs(p.z) >= fDz - halfCarTolerance)
{
in = eSurface;
}
else
{
in = eInside;
}
r2 = p.x * p.x + p.y * p.y;
rl = 0.5 * (fRmin2 * (p.z + fDz) + fRmin1 * (fDz - p.z)) / fDz;
rh = 0.5 * (fRmax2 * (p.z + fDz) + fRmax1 * (fDz - p.z)) / fDz;
// rh2 = rh*rh;
tolRMin = rl - halfRadTolerance;
if (tolRMin < 0)
{
tolRMin = 0;
}
tolRMax = rh + halfRadTolerance;
if ((r2 < tolRMin * tolRMin) || (r2 > tolRMax * tolRMax))
{
return in = eOutside;
}
if (rl)
{
tolRMin = rl + halfRadTolerance;
}
else
{
tolRMin = 0.0;
}
tolRMax = rh - halfRadTolerance;
if (in == eInside) // else it's eSurface already
{
if ((r2 < tolRMin * tolRMin) || (r2 >= tolRMax * tolRMax))
{
in = eSurface;
}
}
if (!fPhiFullCone && ((p.x != 0.0) || (p.y != 0.0)))
{
pPhi = std::atan2(p.y, p.x);
if (pPhi < fSPhi - halfAngTolerance)
{
pPhi += 2 * UUtils::kPi;
}
else if (pPhi > fSPhi + fDPhi + halfAngTolerance)
{
pPhi -= 2 * UUtils::kPi;
}
if ((pPhi < fSPhi - halfAngTolerance) ||
(pPhi > fSPhi + fDPhi + halfAngTolerance))
{
return in = eOutside;
}
else if (in == eInside) // else it's eSurface anyway already
{
if ((pPhi < fSPhi + halfAngTolerance) ||
(pPhi > fSPhi + fDPhi - halfAngTolerance))
{
in = eSurface;
}
}
}
else if (!fPhiFullCone)
{
in = eSurface;
}
return in;
}
public: // without description
UCons();
//
// Fake default constructor for usage restricted to direct object
// persistency for clients requiring preallocation of memory for
// persistifiable objects.
UCons(const UCons& rhs);
UCons& operator=(const UCons& rhs);
// Copy constructor and assignment operator.
// Old access functions
inline double GetRmin1() const;
inline double GetRmax1() const;
inline double GetRmin2() const;
inline double GetRmax2() const;
inline double GetDz() const;
inline double GetSPhi() const;
inline double GetDPhi() const;
private:
double fCubicVolume, fSurfaceArea;
inline double Capacity();
inline double SurfaceArea();
inline void Initialize();
//
// Reset relevant values to zero
inline void CheckSPhiAngle(double sPhi);
inline void CheckDPhiAngle(double dPhi);
inline void CheckPhiAngles(double sPhi, double dPhi);
//
// Reset relevant flags and angle values
inline void InitializeTrigonometry();
//
// Recompute relevant trigonometric values and cache them
UVector3 ApproxSurfaceNormal(const UVector3& p) const;
//
// Algorithm for SurfaceNormal() following the original
// specification for points not on the surface
private:
// Used by distanceToOut
//
enum ESide {kNull, kRMin, kRMax, kSPhi, kEPhi, kPZ, kMZ};
// used by normal
//
enum ENorm {kNRMin, kNRMax, kNSPhi, kNEPhi, kNZ};
double kRadTolerance, kAngTolerance;
//
// Radial and angular tolerances
double fRmin1, fRmin2, fRmax1, fRmax2, fDz, fSPhi, fDPhi;
//
// Radial and angular dimensions
double sinCPhi, cosCPhi, cosHDPhiOT, cosHDPhiIT,
sinSPhi, cosSPhi, sinEPhi, cosEPhi;
//
// Cached trigonometric values
bool fPhiFullCone;
double secRMin, tanRMin, tanRMax, secRMax;
// double fSinPhi;
//
// Flag for identification of section or full cone
};
#include "UCons.icc"
#endif
@@ -0,0 +1,294 @@
//
// ********************************************************************
// * This Software is part of the AIDA Unified Solids Library package *
// * See: https://aidasoft.web.cern.ch/USolids *
// ********************************************************************
//
// $Id:$
//
// --------------------------------------------------------------------
//
// UCons.icc
//
// Implementation of inline methods of UCons
//
// 19.10.12 Marek Gayer
// Created from original implementation in Geant4
// --------------------------------------------------------------------
inline
double UCons::GetInnerRadiusMinusZ() const
{
return fRmin1 ;
}
inline
double UCons::GetOuterRadiusMinusZ() const
{
return fRmax1 ;
}
inline
double UCons::GetInnerRadiusPlusZ() const
{
return fRmin2 ;
}
inline
double UCons::GetOuterRadiusPlusZ() const
{
return fRmax2 ;
}
inline
double UCons::GetZHalfLength() const
{
return fDz ;
}
inline
double UCons::GetStartPhiAngle() const
{
return fSPhi ;
}
inline
double UCons::GetDeltaPhiAngle() const
{
return fDPhi;
}
inline
void UCons::Initialize()
{
fCubicVolume = 0.;
fSurfaceArea = 0.;
tanRMin = (fRmin2 - fRmin1) * 0.5 / fDz;
secRMin = std::sqrt(1.0 + tanRMin * tanRMin);
tanRMax = (fRmax2 - fRmax1) * 0.5 / fDz;
secRMax = std::sqrt(1.0 + tanRMax * tanRMax);
}
inline
void UCons::InitializeTrigonometry()
{
double hDPhi = 0.5 * fDPhi; // half delta phi
double cPhi = fSPhi + hDPhi;
double ePhi = fSPhi + fDPhi;
sinCPhi = std::sin(cPhi);
cosCPhi = std::cos(cPhi);
cosHDPhiIT = std::cos(hDPhi - 0.5 * kAngTolerance); // inner/outer tol half dphi
cosHDPhiOT = std::cos(hDPhi + 0.5 * kAngTolerance);
sinSPhi = std::sin(fSPhi);
cosSPhi = std::cos(fSPhi);
sinEPhi = std::sin(ePhi);
cosEPhi = std::cos(ePhi);
}
inline void UCons::CheckSPhiAngle(double sPhi)
{
// Ensure fSphi in 0-2PI or -2PI-0 range if shape crosses 0
if (sPhi < 0)
{
fSPhi = 2 * UUtils::kPi - std::fmod(std::fabs(sPhi), 2 * UUtils::kPi);
}
else
{
fSPhi = std::fmod(sPhi, 2 * UUtils::kPi) ;
}
if (fSPhi + fDPhi > 2 * UUtils::kPi)
{
fSPhi -= 2 * UUtils::kPi ;
}
}
inline void UCons::CheckDPhiAngle(double dPhi)
{
fPhiFullCone = true;
if (dPhi >= 2 * UUtils::kPi - kAngTolerance * 0.5)
{
fDPhi = 2 * UUtils::kPi;
fSPhi = 0;
}
else
{
fPhiFullCone = false;
if (dPhi > 0)
{
fDPhi = dPhi;
}
else
{
std::ostringstream message;
message << "Invalid dphi." << std::endl
<< "Negative or zero delta-Phi (" << dPhi << ") in solid: "
<< GetName();
UUtils::Exception("UCons::CheckDPhiAngle()", "GeomSolids0002",
FatalErrorInArguments, 1, message.str().c_str());
}
}
}
inline void UCons::CheckPhiAngles(double sPhi, double dPhi)
{
CheckDPhiAngle(dPhi);
if ((fDPhi < 2 * UUtils::kPi) && (sPhi))
{
CheckSPhiAngle(sPhi);
}
InitializeTrigonometry();
}
inline
void UCons::SetInnerRadiusMinusZ(double Rmin1)
{
fRmin1 = Rmin1 ;
Initialize();
}
inline
void UCons::SetOuterRadiusMinusZ(double Rmax1)
{
fRmax1 = Rmax1 ;
Initialize();
}
inline
void UCons::SetInnerRadiusPlusZ(double Rmin2)
{
fRmin2 = Rmin2 ;
Initialize();
}
inline
void UCons::SetOuterRadiusPlusZ(double Rmax2)
{
fRmax2 = Rmax2 ;
Initialize();
}
inline
void UCons::SetZHalfLength(double newDz)
{
fDz = newDz ;
Initialize();
}
inline
void UCons::SetStartPhiAngle(double newSPhi, bool compute)
{
// Flag 'compute' can be used to explicitely avoid recomputation of
// trigonometry in case SetDeltaPhiAngle() is invoked afterwards
CheckSPhiAngle(newSPhi);
fPhiFullCone = false;
if (compute)
{
InitializeTrigonometry();
}
Initialize();
}
void UCons::SetDeltaPhiAngle(double newDPhi)
{
CheckPhiAngles(fSPhi, newDPhi);
Initialize();
}
// Old access methods ...
inline
double UCons::GetRmin1() const
{
return GetInnerRadiusMinusZ();
}
inline
double UCons::GetRmax1() const
{
return GetOuterRadiusMinusZ();
}
inline
double UCons::GetRmin2() const
{
return GetInnerRadiusPlusZ();
}
inline
double UCons::GetRmax2() const
{
return GetOuterRadiusPlusZ();
}
inline
double UCons::GetDz() const
{
return GetZHalfLength();
}
inline
double UCons::GetSPhi() const
{
return GetStartPhiAngle();
}
inline
double UCons::GetDPhi() const
{
return GetDeltaPhiAngle();
}
inline
double UCons::Capacity()
{
if (fCubicVolume != 0.)
{
;
}
else
{
double Rmean, rMean, deltaR, deltar;
Rmean = 0.5 * (fRmax1 + fRmax2);
deltaR = fRmax1 - fRmax2;
rMean = 0.5 * (fRmin1 + fRmin2);
deltar = fRmin1 - fRmin2;
fCubicVolume = fDPhi * fDz * (Rmean * Rmean - rMean * rMean
+ (deltaR * deltaR - deltar * deltar) / 12);
}
return fCubicVolume;
}
inline
double UCons::SurfaceArea()
{
if (fSurfaceArea != 0.)
{
;
}
else
{
double mmin, mmax, dmin, dmax;
mmin = (fRmin1 + fRmin2) * 0.5;
mmax = (fRmax1 + fRmax2) * 0.5;
dmin = (fRmin2 - fRmin1);
dmax = (fRmax2 - fRmax1);
fSurfaceArea = fDPhi * (mmin * std::sqrt(dmin * dmin + 4 * fDz * fDz)
+ mmax * std::sqrt(dmax * dmax + 4 * fDz * fDz)
+ 0.5 * (fRmax1 * fRmax1 - fRmin1 * fRmin1
+ fRmax2 * fRmax2 - fRmin2 * fRmin2));
if (!fPhiFullCone)
{
fSurfaceArea = fSurfaceArea + 4 * fDz * (mmax - mmin);
}
}
return fSurfaceArea;
}
@@ -0,0 +1,76 @@
//
// ********************************************************************
// * This Software is part of the AIDA Unified Solids Library package *
// * See: https://aidasoft.web.cern.ch/USolids *
// ********************************************************************
//
// $Id:$
//
// --------------------------------------------------------------------
//
// UEnclosingCylinder
//
// Class description:
//
// Definition of a utility class for quickly deciding if a point
// is clearly outside a polyhedra or polycone or deciding if
// a trajectory is clearly going to miss those shapes.
//
// 19.10.12 Marek Gayer
// Created from original implementation in Geant4
// --------------------------------------------------------------------
#ifndef UEnclosingCylinder_hh
#define UEnclosingCylinder_hh
#include "UTypes.hh"
#include "UTubs.hh"
class UReduciblePolygon;
class UEnclosingCylinder
{
public: // with description
UEnclosingCylinder(/*const UReduciblePolygon *rz*/ double r, double lo, double hi,
bool phiIsOpen,
double startPhi, double totalPhi);
~UEnclosingCylinder();
bool MustBeOutside(const UVector3& p) const;
// Decide very rapidly if the point is outside the cylinder.
// If one is not certain, return false.
bool ShouldMiss(const UVector3& p, const UVector3& v) const;
// Decide very rapidly if the trajectory is going to miss the cylinder.
// If one is not sure, return false.
double DistanceTo(const UVector3& p, const UVector3& v) const;
double SafetyFromOutside(const UVector3& p) const;
public: // without description
void Extent(UVector3& aMin, UVector3& aMax) const;
double radius; // radius of our cylinder
protected:
double zLo, zHi; // z extent
bool phiIsOpen; // true if there is a phi segment
double startPhi, // for isPhiOpen==true, starting of phi segment
totalPhi; // for isPhiOpen==true, size of phi segment
double rx1, ry1,
dx1, dy1;
double rx2, ry2,
dx2, dy2;
bool concave; // true, if x/y Cross section is concave
UTubs* tube;
};
#endif
@@ -0,0 +1,147 @@
//
// ********************************************************************
// * This Software is part of the AIDA Unified Solids Library package *
// * See: https://aidasoft.web.cern.ch/USolids *
// ********************************************************************
//
// $Id:$
//
// --------------------------------------------------------------------
//
// UGenericPolycone
//
// Class description:
//
// Implementing a CSG-like type "PCON" volume with possibility of
// specifying also 'decreasing' Z sections:
//
// UGenericPolycone( const std::string& name,
// double phiStart, // initial phi starting angle
// double phiTotal, // total phi angle
// int numRZ, // number corners in r,z space
// const double r[], // r coordinate of these corners
// const double z[]) // z coordinate of these corners
//
// 19.10.13 Tatiana Nikitina
// Created from original implementation in Geant4
// --------------------------------------------------------------------
#ifndef UGenericPolycone_hh
#define UGenericPolycone_hh
#include "UVCSGfaceted.hh"
#include "UPolyconeSide.hh"
class UEnclosingCylinder;
class UReduciblePolygon;
class UVCSGface;
class UGenericPolycone: public UVCSGfaceted
{
public: // with description
UGenericPolycone(const std::string& name,
double phiStart, // initial phi starting angle
double phiTotal, // total phi angle
int numZPlanes, // number of z planes
const double zPlane[], // position of z planes
const double rInner[], // tangent distance to inner surface
const double rOuter[]); // tangent distance to outer surface
UGenericPolycone(const std::string& name,
double phiStart, // initial phi starting angle
double phiTotal, // total phi angle
int numRZ, // number corners in r,z space
const double r[], // r coordinate of these corners
const double z[]); // z coordinate of these corners
virtual ~UGenericPolycone();
// Methods for solid
VUSolid::EnumInside Inside(const UVector3& p) const;
double DistanceToIn(const UVector3& p, const UVector3& v, double aPstep = UUtils::kInfinity) const;
// double SafetyFromOutside( const UVector3 &p, bool aAccurate=false) const;
UVector3 GetPointOnSurface() const;
/*
void ComputeDimensions( UVPVParameterisation* p,
const int n,
const UVPhysicalVolume* pRep );
*/
UGeometryType GetEntityType() const;
VUSolid* Clone() const;
std::ostream& StreamInfo(std::ostream& os) const;
bool Reset();
// Accessors
inline double GetStartPhi() const;
inline double GetEndPhi() const;
inline bool IsOpen() const;
inline int GetNumRZCorner() const;
inline UPolyconeSideRZ GetCorner(int index) const;
public: // without description
//UPolycone(__void__&);
// Fake default constructor for usage restricted to direct object
// persistency for clients requiring preallocation of memory for
// persistifiable objects.
UGenericPolycone(const UGenericPolycone& source);
UGenericPolycone& operator=(const UGenericPolycone& source);
// Copy constructor and assignment operator.
protected: // without description
// Generic initializer, called by all constructors
void Create(double phiStart, // initial phi starting angle
double phiTotal, // total phi angle
UReduciblePolygon* rz); // r/z coordinate of these corners
void CopyStuff(const UGenericPolycone& source);
// Methods for random point generation
void GetParametersList(int /*aNumber*/, double* /*aArray*/) const {}
void ComputeBBox(UBBox* /*aBox*/, bool /*aStore*/)
{
// Computes bounding box.
std::cout << "ComputeBBox - Not implemented" << std::endl;
}
void Extent(UVector3& aMin, UVector3& aMax) const;
protected: // without description
// Here are our parameters
double startPhi; // Starting phi value (0 < phiStart < 2pi)
double endPhi; // end phi value (0 < endPhi-phiStart < 2pi)
bool phiIsOpen; // true if there is a phi segment
int numCorner; // number RZ points
UPolyconeSideRZ* corners; // corner r,z points
// Our quick test
UEnclosingCylinder* enclosingCylinder;
};
#include "UGenericPolycone.icc"
#endif
@@ -0,0 +1,49 @@
//
// ********************************************************************
// * This Software is part of the AIDA Unified Solids Library package *
// * See: https://aidasoft.web.cern.ch/USolids *
// ********************************************************************
//
// $Id:$
//
// --------------------------------------------------------------------
//
// UGenericPolycone.icc
//
// Implementation of inline methods of UGenericPolycone
//
// 19.10.13 Tatiana Nikitina
// Created from original implementation in Geant4
// --------------------------------------------------------------------
inline
double UGenericPolycone::GetStartPhi() const
{
return startPhi;
}
inline
double UGenericPolycone::GetEndPhi() const
{
return endPhi;
}
inline
bool UGenericPolycone::IsOpen() const
{
return phiIsOpen;
}
inline
int UGenericPolycone::GetNumRZCorner() const
{
return numCorner;
}
inline
UPolyconeSideRZ UGenericPolycone::GetCorner(int index) const
{
return corners[index];
}
@@ -0,0 +1,91 @@
//
// ********************************************************************
// * This Software is part of the AIDA Unified Solids Library package *
// * See: https://aidasoft.web.cern.ch/USolids *
// ********************************************************************
//
// $Id:$
//
// --------------------------------------------------------------------
//
// UIntersectingCone
//
// Class description:
//
// Utility class which calculates the intersection
// of an arbitrary line with a fixed cone
//
// 19.02.13 Marek Gayer
// Created from original implementation in Geant4
// --------------------------------------------------------------------
#ifndef UIntersectingCone_hh
#define UIntersectingCone_hh
#include "UTypes.hh"
class UIntersectingCone
{
public:
UIntersectingCone(const double r[2], const double z[2]);
virtual ~UIntersectingCone();
int LineHitsCone(const UVector3& p, const UVector3& v, double& s1, double& s2);
bool HitOn(const double r, const double z);
inline double RLo() const
{
return rLo;
}
inline double RHi() const
{
return rHi;
}
inline double ZLo() const
{
return zLo;
}
inline double ZHi() const
{
return zHi;
}
public: // without description
/*
UIntersectingCone(__void__&);
// Fake default constructor for usage restricted to direct object
// persistency for clients requiring preallocation of memory for
// persistifiable objects.
*/
protected:
double zLo, zHi, // Z bounds of side
rLo, rHi; // R bounds of side
bool type1; // True if cone is type 1
// (std::fabs(z1-z2)>std::fabs(r1-r2))
double A, B; // Cone radius parameter:
// type 1: r = A + B*z
// type 2: z = A + B*r
// int Solution (const UVector3 &p, const UVector3 &v, double a, double b, double c, double &s1, double &s2);
int LineHitsCone1(const UVector3& p, const UVector3& v,
double& s1, double& s2);
int LineHitsCone1Optimized(const UVector3& p, const UVector3& v,
double& s1, double& s2);
int LineHitsCone2(const UVector3& p, const UVector3& v,
double& s1, double& s2);
// const double kInfinity;
const static double EpsilonQuad;
};
#endif
@@ -0,0 +1,128 @@
//
// ********************************************************************
// * This Software is part of the AIDA Unified Solids Library package *
// * See: https://aidasoft.web.cern.ch/USolids *
// ********************************************************************
//
// $Id:$
//
// --------------------------------------------------------------------
//
// UOrb
//
// Class description:
//
// A simple Orb defined by half-lengths on the three axis.
// The center of the Orb matches the origin of the local reference frame.
//
// 19.10.12 Marek Gayer
// Created from original implementation in Geant4
// --------------------------------------------------------------------
#ifndef USOLIDS_UOrb
#define USOLIDS_UOrb
#include "VUSolid.hh"
#include "UUtils.hh"
class UOrb : public VUSolid
{
public:
UOrb() : VUSolid(), fR(0), fRTolerance(0) {}
UOrb(const std::string& name, double pRmax);
~UOrb() {}
UOrb(const UOrb& rhs);
UOrb& operator=(const UOrb& rhs);
// Accessors
inline double GetRadius() const;
// Modifiers
inline void SetRadius(double newRmax);
// Navigation methods
EnumInside Inside(const UVector3& aPo6int) const;
double SafetyFromInside(const UVector3& aPoint,
bool aAccurate = false) const;
double SafetyFromOutside(const UVector3& aPoint,
bool aAccurate = false) const;
double DistanceToIn(const UVector3& aPoint,
const UVector3& aDirection,
double aPstep = UUtils::kInfinity) const;
double DistanceToOut(const UVector3& aPoint,
const UVector3& aDirection,
UVector3& aNormalVector,
bool& aConvex,
double aPstep = UUtils::kInfinity) const;
bool Normal(const UVector3& aPoint, UVector3& aNormal) const;
void Extent(UVector3& aMin, UVector3& aMax) const;
inline double Capacity();
inline double SurfaceArea();
UGeometryType GetEntityType() const;
void ComputeBBox(UBBox* /*aBox*/, bool /*aStore = false*/) {}
//G4Visualisation
void GetParametersList(int /*aNumber*/, double* /*aArray*/) const;
VUSolid* Clone() const;
double GetRadialTolerance()
{
return fRTolerance;
}
UVector3 GetPointOnSurface() const;
std::ostream& StreamInfo(std::ostream& os) const;
private:
double fR;
double fRTolerance;
double fCubicVolume; // Cubic Volume
double fSurfaceArea; // Surface Area
double DistanceToOutForOutsidePoints(const UVector3& p, const UVector3& v, UVector3& n) const;
};
inline double UOrb::GetRadius() const
{
return fR;
}
inline void UOrb::SetRadius(double newRmax)
{
fR = newRmax;
}
inline double UOrb::Capacity()
{
if (fCubicVolume != 0.)
{
;
}
else
{
fCubicVolume = (4 * UUtils::kPi / 3) * fR * fR * fR;
}
return fCubicVolume;
}
inline double UOrb::SurfaceArea()
{
if (fSurfaceArea != 0.)
{
;
}
else
{
fSurfaceArea = (4 * UUtils::kPi) * fR * fR;
}
return fSurfaceArea;
}
#endif
@@ -0,0 +1,221 @@
//
// ********************************************************************
// * This Software is part of the AIDA Unified Solids Library package *
// * See: https://aidasoft.web.cern.ch/USolids *
// ********************************************************************
//
// $Id:$
//
// --------------------------------------------------------------------
//
// UPolyPhiFace
//
// Class description:
//
// Definition of a face that bounds a polycone or polyhedra when
// it has a phi opening:
//
// UPolyPhiFace( const UReduciblePolygon *rz,
// double phi,
// double deltaPhi,
// double phiOther )
//
// Specifically: a face that lies on a plane that passes through
// the z axis. It has boundaries that are straight lines of arbitrary
// length and direction, but with corners aways on the same side of
// the z axis.
//
// 19.10.12 Marek Gayer
// Created from original implementation in Geant4
// --------------------------------------------------------------------
#ifndef UPolyPhiFace_hh
#define UPolyPhiFace_hh
#include "UVCSGface.hh"
#include "UVector2.hh"
class UReduciblePolygon;
struct UPolyPhiFaceVertex
{
double x, y, r, z; // position
double rNorm,
zNorm; // r/z normal
UVector3 norm3D; // 3D normal
// Needed for Triangulation Algorithm
//
bool ear;
UPolyPhiFaceVertex* next, *prev;
};
struct UPolyPhiFaceEdge
{
UPolyPhiFaceEdge(): v0(0), v1(0), tr(.0), tz(0.), length(0.) {}
UPolyPhiFaceVertex* v0, *v1; // Corners
double tr, tz, // Unit vector along edge
length; // Length of edge
UVector3 norm3D; // 3D edge normal vector
};
class UPolyPhiFace : public UVCSGface
{
public: // with description
UPolyPhiFace(const UReduciblePolygon* rz,
double phi, double deltaPhi, double phiOther);
// Constructor.
// Points r,z should be supplied in clockwise order in r,z.
// For example:
// [1]---------[2] ^ R
// | | |
// | | +--> z
// [0]---------[3]
virtual ~UPolyPhiFace();
// Destructor. Removes edges and corners.
UPolyPhiFace(const UPolyPhiFace& source);
UPolyPhiFace& operator=(const UPolyPhiFace& source);
// Copy constructor and assgnment operator.
bool Distance(const UVector3& p, const UVector3& v,
bool outgoing, double surfTolerance,
double& distance, double& distFromSurface,
UVector3& normal, bool& allBehind);
double Safety(const UVector3& p, bool outgoing);
VUSolid::EnumInside Inside(const UVector3& p, double tolerance,
double* bestDistance);
UVector3 Normal(const UVector3& p, double* bestDistance);
double Extent(const UVector3 axis);
/*
void CalculateExtent( const EAxisType axis,
const UVoxelLimits &voxelLimit,
const UAffineTransform &tranform,
USolidExtentList &extentList );
*/
inline UVCSGface* Clone();
// Allocates on the heap a clone of this face.
double SurfaceArea();
double SurfaceTriangle(UVector3 p1, UVector3 p2,
UVector3 p3, UVector3* p4);
UVector3 GetPointOnFace();
// Auxiliary methods for determination of points on surface.
public: // without description
UPolyPhiFace(__void__&);
// Fake default constructor for usage restricted to direct object
// persistency for clients requiring preallocation of memory for
// persistifiable objects.
void Diagnose(VUSolid* solid);
// Throw an exception if something is found inconsistent with
// the solid. For debugging purposes only
protected:
bool InsideEdgesExact(double r, double z, double normSign,
const UVector3& p, const UVector3& v);
// Decide if the point in r,z is inside the edges of our face,
// **but** do so consistently with other faces.
bool InsideEdges(double r, double z);
bool InsideEdges(double r, double z, double* distRZ2,
UPolyPhiFaceVertex** base3Dnorm = 0,
UVector3** head3Dnorm = 0);
// Decide if the point in r,z is inside the edges of our face.
inline double ExactZOrder(double z,
double qx, double qy, double qz,
const UVector3& v,
double normSign,
const UPolyPhiFaceVertex* vert) const;
// Decide precisely whether a trajectory passes to the left, right,
// or exactly passes through the z position of a vertex point in face.
void CopyStuff(const UPolyPhiFace& source);
protected:
// Functions used for Triangulation in Case of generic Polygone.
// The triangulation is used for GetPointOnFace()
double Area2(UVector2 a, UVector2 b, UVector2 c);
// Calculation of 2*Area of Triangle with Sign
bool Left(UVector2 a, UVector2 b, UVector2 c);
bool LeftOn(UVector2 a, UVector2 b, UVector2 c);
bool Collinear(UVector2 a, UVector2 b, UVector2 c);
// Boolean functions for sign of Surface
bool IntersectProp(UVector2 a, UVector2 b,
UVector2 c, UVector2 d);
// Boolean function for finding proper intersection of two
// line segments (a,b) and (c,d).
bool Between(UVector2 a, UVector2 b, UVector2 c);
// Boolean function for determining if point c is between a and b
// where the three points (a,b,c) are on the same line.
bool Intersect(UVector2 a, UVector2 b,
UVector2 c, UVector2 d);
// Boolean function for finding proper intersection or not
// of two line segments (a,b) and (c,d).
bool Diagonalie(UPolyPhiFaceVertex* a, UPolyPhiFaceVertex* b);
// Boolean Diagonalie help to determine if diagonal s
// of segment (a,b) is convex or reflex.
bool InCone(UPolyPhiFaceVertex* a, UPolyPhiFaceVertex* b);
// Boolean function for determining if b is inside the cone (a0,a,a1)
// where a is the center of the cone.
bool Diagonal(UPolyPhiFaceVertex* a, UPolyPhiFaceVertex* b);
// Boolean function for determining if Diagonal is possible
// inside Polycone or PolyHedra.
void EarInit();
// Initialisation for Triangulisation by ear tips.
// For details see "Computational Geometry in C" by Joseph O'Rourke.
void Triangulate();
// Triangularisation by ear tips for Polycone or Polyhedra.
// For details see "Computational Geometry in C" by Joseph O'Rourke.
// NOTE: a copy of the shape is made and this copy is reordered in
// order to have a list of triangles. This list is used by the
// method GetPointOnFace().
protected:
int numEdges; // Number of edges
UPolyPhiFaceEdge* edges; // The edges of the face
UPolyPhiFaceVertex* corners; // And the corners
UVector3 normal; // Normal Unit vector
UVector3 radial; // Unit vector along radial direction
UVector3 surface; // Point on surface
UVector3 surface_point; // Auxiliary point on surface used for
// method GetPointOnFace()
double rMin, rMax, // Extent in r
zMin, zMax; // Extent in z
bool allBehind; // True if the polycone/polyhedra
// is behind the place of this face
double fTolerance;// Surface thickness
double fSurfaceArea; // Surface Area of PolyPhiFace
UPolyPhiFaceVertex* triangles; // Auxiliary pointer to 'corners' used for
// triangulation. Copy structure, changing
// the structure of 'corners' (ear removal)
};
#include "UPolyPhiFace.icc"
#endif
@@ -0,0 +1,54 @@
//
// ********************************************************************
// * This Software is part of the AIDA Unified Solids Library package *
// * See: https://aidasoft.web.cern.ch/USolids *
// ********************************************************************
//
// $Id:$
//
// --------------------------------------------------------------------
//
// UPolyPhiFace.icc
//
// 19.10.12 Marek Gayer
// Created from original implementation in Geant4
// --------------------------------------------------------------------
inline
UVCSGface* UPolyPhiFace::Clone()
{
return new UPolyPhiFace(*this);
}
// ExactZOrder
//
// Decide precisely whether a trajectory passes to the left, right, or exactly
// passes through the z position of a vertex point in our face.
//
// Result is only determined within an arbitrary (positive) factor.
// > 0 to the right
// < 0 to the left
// = 0 exactly on top of
// In 99.9999% of the cases, a trivial calculation is used. In difficult
// cases, a precise, compliant calculation is relied on.
//
inline
double UPolyPhiFace::ExactZOrder(double z,
double qx, double qy, double qz,
const UVector3& v,
double normSign,
const UPolyPhiFaceVertex* vert) const
{
double answer = vert->z - z;
if (std::fabs(answer) < VUSolid::Tolerance())
{
UVector3 qa(qx - vert->x + radial.x,
qy - vert->y + radial.y, qz - vert->z),
qb(qx - vert->x, qy - vert->y, qz - vert->z);
UVector3 qacb = qa.Cross(qb);
answer = normSign * qacb.Dot(v) * (normal.y * radial.x - normal.x * radial.y);
}
return answer;
}
@@ -0,0 +1,296 @@
//
// ********************************************************************
// * This Software is part of the AIDA Unified Solids Library package *
// * See: https://aidasoft.web.cern.ch/USolids *
// ********************************************************************
//
// $Id:$
//
// --------------------------------------------------------------------
//
// UPolycone
//
// Class description:
//
// Class implementing a CSG-like type "PCON".
//
// UPolycone( const G4String& name,
// G4double phiStart, // initial phi starting angle
// G4double phiTotal, // total phi angle
// G4int numZPlanes, // number of z planes
// const G4double zPlane[], // position of z planes
// const G4double rInner[], // tangent distance to inner surface
// const G4double rOuter[]) // tangent distance to outer surface
//
// Alternative constructor, but limited to increasing-only Z sections:
//
// UPolycone( const G4String& name,
// G4double phiStart, // initial phi starting angle
// G4double phiTotal, // total phi angle
// G4int numRZ, // number corners in r,z space
// const G4double r[], // r coordinate of these corners
// const G4double z[]) // z coordinate of these corners
//
// 19.04.13 Marek Gayer
// Created from original implementation in Geant4
// --------------------------------------------------------------------
#ifndef UPolycone_hh
#define UPolycone_hh
#include "VUSolid.hh"
#include "UPolyconeSide.hh"
#include "UVCSGfaceted.hh"
#include "UVoxelizer.hh"
#include "UCons.hh"
#include "UTubs.hh"
class UEnclosingCylinder;
class UReduciblePolygon;
class UPolyconeHistorical
{
public:
UPolyconeHistorical();
~UPolyconeHistorical();
UPolyconeHistorical(const UPolyconeHistorical& source);
UPolyconeHistorical& operator=(const UPolyconeHistorical& right);
double fStartAngle;
double fOpeningAngle;
int fNumZPlanes;
std::vector<double> fZValues;
std::vector<double> Rmin;
std::vector<double> Rmax;
};
class UPolycone : public VUSolid
{
public: // with description
void Init(
double phiStart, // initial phi starting angle
double phiTotal, // total phi angle
int numZPlanes, // number of z planes
const double zPlane[], // position of z planes
const double rInner[], // tangent distance to inner surface
const double rOuter[]);
UPolycone(const std::string& name) : VUSolid(name)
{
}
UPolycone(const std::string& name,
double phiStart, // initial phi starting angle
double phiTotal, // total phi angle
int numZPlanes, // number of z planes
const double zPlane[], // position of z planes
const double rInner[], // tangent distance to inner surface
const double rOuter[]); // tangent distance to outer surface
UPolycone(const std::string& name,
double phiStart, // initial phi starting angle
double phiTotal, // total phi angle
int numRZ, // number corners in r,z space
const double r[], // r coordinate of these corners
const double z[]); // z coordinate of these corners
virtual ~UPolycone();
void Reset();
// inline void SetOriginalParameters(UPolyconeHistorical* pars);
// inline void SetOriginalParameters();
std::ostream& StreamInfo(std::ostream& os) const;
VUSolid::EnumInside Inside(const UVector3& p) const;
double DistanceToIn(const UVector3& p, const UVector3& v, double aPstep = UUtils::kInfinity) const;
double SafetyFromInside(const UVector3& aPoint,
bool aAccurate = false) const;
double SafetyFromOutside(const UVector3& aPoint,
bool aAccurate = false) const;
double DistanceToOut(const UVector3& aPoint,
const UVector3& aDirection,
UVector3& aNormalVector,
bool& aConvex,
double aPstep = UUtils::kInfinity) const;
bool Normal(const UVector3& aPoint, UVector3& aNormal) const;
// virtual void Extent ( EAxisType aAxis, double &aMin, double &aMax ) const;
void Extent(UVector3& aMin, UVector3& aMax) const;
double Capacity();
double SurfaceArea();
UGeometryType GetEntityType() const;
void ComputeBBox(UBBox* /*aBox*/, bool /*aStore = false*/) {}
//G4Visualisation
void GetParametersList(int /*aNumber*/, double* /*aArray*/) const {}
VUSolid* Clone() const;
UPolycone(const UPolycone& source);
UPolycone& operator=(const UPolycone& source);
// Copy constructor and assignment operator.
void CopyStuff(const UPolycone& source);
UVector3 GetPointOnSurface() const;
// Methods for random point generation
UVector3 GetPointOnCone(double fRmin1, double fRmax1,
double fRmin2, double fRmax2,
double zOne, double zTwo,
double& totArea) const;
UVector3 GetPointOnTubs(double fRMin, double fRMax,
double zOne, double zTwo,
double& totArea) const;
UVector3 GetPointOnCut(double fRMin1, double fRMax1,
double fRMin2, double fRMax2,
double zOne, double zTwo,
double& totArea) const;
UVector3 GetPointOnRing(double fRMin, double fRMax,
double fRMin2, double fRMax2,
double zOne) const;
inline double GetStartPhi() const
{
return startPhi;
}
inline double GetEndPhi() const
{
return endPhi;
}
inline bool IsOpen() const
{
return phiIsOpen;
}
inline bool IsGeneric() const
{
return false;
}
inline int GetNumRZCorner() const
{
return numCorner;
}
inline UPolyconeSideRZ GetCorner(int index) const
{
return corners[index];
}
inline UPolyconeHistorical* GetOriginalParameters() const
{
return fOriginalParameters;
}
inline void SetOriginalParameters(UPolyconeHistorical* pars)
{
if (!pars)
// UException("UPolycone3::SetOriginalParameters()", "GeomSolids0002",
// FatalException, "NULL pointer to parameters!");
*fOriginalParameters = *pars;
}
protected: // without description
// int fNumSides;
bool SetOriginalParameters(UReduciblePolygon* rz);
// Here are our parameters
double startPhi; // Starting phi value (0 < phiStart < 2pi)
double endPhi; // end phi value (0 < endPhi-phiStart < 2pi)
bool phiIsOpen; // true if there is a phi segment
int numCorner; // number RZ points
UPolyconeSideRZ* corners; // corner r,z points
UPolyconeHistorical* fOriginalParameters; // original input parameters
double fCubicVolume; // Cubic Volume
double fSurfaceArea; // Surface Area
inline void SetOriginalParameters()
{
int numPlanes = (int)numCorner / 2;
fOriginalParameters = new UPolyconeHistorical;
fOriginalParameters->fZValues.resize(numPlanes);
fOriginalParameters->Rmin.resize(numPlanes);
fOriginalParameters->Rmax.resize(numPlanes);
for (int j = 0; j < numPlanes; j++)
{
fOriginalParameters->fZValues[j] = corners[numPlanes + j].z;
fOriginalParameters->Rmax[j] = corners[numPlanes + j].r;
fOriginalParameters->Rmin[j] = corners[numPlanes - 1 - j].r;
}
fOriginalParameters->fStartAngle = startPhi;
fOriginalParameters->fOpeningAngle = endPhi - startPhi;
fOriginalParameters->fNumZPlanes = numPlanes;
}
UEnclosingCylinder* enclosingCylinder;
struct UPolyconeSection
{
VUSolid* solid;// true if all points in section are concave in regards to whole polycone, will be determined
double shift;
bool tubular;
// double left, right;
bool convex; // TURE if all points in section are concave in regards to whole polycone, will be determined, currently not implemented
};
std::vector<double> fZs; // z coordinates of given sections
std::vector<UPolyconeSection> fSections;
int fMaxSection;
inline VUSolid::EnumInside InsideSection(int index, const UVector3& p) const;
inline double SafetyFromInsideSection(int index, const UVector3& p) const
{
const UPolyconeSection& section = fSections[index];
UVector3 ps(p.x, p.y, p.z - section.shift);
double res = section.solid->SafetyFromInside(ps, true);
return res;
}
inline double SafetyFromOutsideSection(int index, const UVector3& p) const
{
const UPolyconeSection& section = fSections[index];
UVector3 ps(p.x, p.y, p.z - section.shift);
double res = section.solid->SafetyFromOutside(ps, true);
return res;
}
bool NormalSection(int index, const UVector3& p, UVector3& n) const
{
const UPolyconeSection& section = fSections[index];
UVector3 ps(p.x, p.y, p.z - section.shift);
bool res = section.solid->Normal(ps, n);
return res;
}
inline int GetSection(double z) const
{
int section = UVoxelizer::BinarySearch(fZs, z);
if (section < 0) section = 0;
else if (section > fMaxSection) section = fMaxSection;
return section;
}
};
#endif
@@ -0,0 +1,93 @@
//
// ********************************************************************
// * This Software is part of the AIDA Unified Solids Library package *
// * See: https://aidasoft.web.cern.ch/USolids *
// ********************************************************************
//
// $Id:$
//
// --------------------------------------------------------------------
//
// UPolycone.icc
//
// Implementation of inline methods of UPolycone
//
// 19.04.13 Marek Gayer
// Created from original implementation in Geant4
// --------------------------------------------------------------------
inline
double UPolycone::GetStartPhi() const
{
return startPhi;
}
inline
double UPolycone::GetEndPhi() const
{
return endPhi;
}
inline
bool UPolycone::IsOpen() const
{
return phiIsOpen;
}
inline
bool UPolycone::IsGeneric() const
{
return false;
}
inline
int UPolycone::GetNumRZCorner() const
{
return numCorner;
}
inline
UPolyconeSideRZ UPolycone::GetCorner(int index) const
{
return corners[index];
}
inline
UPolyconeHistorical* UPolycone::GetOriginalParameters() const
{
return fOriginalParameters;
}
inline
void UPolycone::SetOriginalParameters(UPolyconeHistorical* pars)
{
if (!pars)
// UException("UPolycone::SetOriginalParameters()", "GeomSolids0002",
// FatalException, "NULL pointer to parameters!");
*fOriginalParameters = *pars;
fCubicVolume = 0.;
fpPolyhedron = 0;
}
inline
void UPolycone::SetOriginalParameters()
{
int numPlanes = (int)numCorner / 2;
fOriginalParameters = new UPolyconeHistorical;
fOriginalParameters->fZValues.resize(numPlanes);
fOriginalParameters->Rmin.resize(numPlanes);
fOriginalParameters->Rmax.resize(numPlanes);
for (int j = 0; j < numPlanes; j++)
{
fOriginalParameters->fZValues[j] = corners[numPlanes + j].z;
fOriginalParameters->Rmax[j] = corners[numPlanes + j].r;
fOriginalParameters->Rmin[j] = corners[numPlanes - 1 - j].r;
}
fOriginalParameters->fStartAngle = startPhi;
fOriginalParameters->fOpeningAngle = endPhi - startPhi;
fOriginalParameters->fNumZPlanes = numPlanes;
}
@@ -0,0 +1,155 @@
//
// ********************************************************************
// * This Software is part of the AIDA Unified Solids Library package *
// * See: https://aidasoft.web.cern.ch/USolids *
// ********************************************************************
//
// $Id:$
//
// --------------------------------------------------------------------
//
// UPolyconeSide
//
// Class description:
//
// Class implmenting a face that represents one conical side
// of a polycone:
//
// UPolyconeSide( const UPolyconeSideRZ *prevRZ,
// const UPolyconeSideRZ *tail,
// const UPolyconeSideRZ *head,
// const UPolyconeSideRZ *nextRZ,
// double phiStart, double deltaPhi,
// bool phiIsOpen, bool isAllBehind=false )
//
// Values for r1,z1 and r2,z2 should be specified in clockwise
// order in (r,z).
//
// 19.04.13 Marek Gayer
// Created from original implementation in Geant4
// --------------------------------------------------------------------
#ifndef UPolyconeSide_hh
#define UPolyconeSide_hh
#include "UVCSGface.hh"
class UIntersectingCone;
struct UPolyconeSideRZ
{
double r, z; // start of vector
};
class UPolyconeSidePrivateSubclass
{
public:
std::pair<UVector3, double> fPhi; // Cached value for phi
void initialize()
{
fPhi.first = UVector3(0, 0, 0);
fPhi.second = 0.0;
};
};
class UPolyconeSide : public UVCSGface
{
public:
UPolyconeSide(const UPolyconeSideRZ* prevRZ,
const UPolyconeSideRZ* tail,
const UPolyconeSideRZ* head,
const UPolyconeSideRZ* nextRZ,
double phiStart, double deltaPhi,
bool phiIsOpen, bool isAllBehind = false);
virtual ~UPolyconeSide();
UPolyconeSide(const UPolyconeSide& source);
UPolyconeSide& operator=(const UPolyconeSide& source);
bool Distance(const UVector3& p, const UVector3& v,
bool outgoing, double surfTolerance,
double& distance, double& distFromSurface,
UVector3& normal, bool& isAllBehind);
double Safety(const UVector3& p, bool outgoing);
VUSolid::EnumInside Inside(const UVector3& p, double tolerance,
double* bestDistance);
UVector3 Normal(const UVector3& p, double* bestDistance);
double Extent(const UVector3 axis);
/*
void CalculateExtent( const EAxisType axis,
const UVoxelLimits &voxelLimit,
const UAffineTransform &tranform,
USolidExtentList &extentList );
*/
UVCSGface* Clone()
{
return new UPolyconeSide(*this);
}
double SurfaceArea();
UVector3 GetPointOnFace();
public: // without description
UPolyconeSide(__void__&);
// Fake default constructor for usage restricted to direct object
// persistency for clients requiring preallocation of memory for
// persistifiable objects.
protected:
double DistanceAway(const UVector3& p, bool opposite,
double& distOutside2, double* rzNorm = 0);
bool PointOnCone(const UVector3& hit, double normSign,
const UVector3& p,
const UVector3& v, UVector3& normal);
void CopyStuff(const UPolyconeSide& source);
static void FindLineIntersect(double x1, double y1,
double tx1, double ty1,
double x2, double y2,
double tx2, double ty2,
double& x, double& y);
double GetPhi(const UVector3& p);
protected:
double r[2], z[2]; // r, z parameters, in specified order
double startPhi, // Start phi (0 to 2pi), if phiIsOpen
deltaPhi; // Delta phi (0 to 2pi), if phiIsOpen
bool phiIsOpen; // True if there is a phi slice
bool allBehind; // True if the entire solid is "behind" this face
UIntersectingCone* cone; // Our intersecting utility class
double rNorm, zNorm; // Normal to surface in r,z space
double rS, zS; // Unit vector along surface in r,z space
double length; // Length of face in r,z space
double prevRS,
prevZS; // Unit vector along previous polyconeSide
double nextRS,
nextZS; // Unit vector along next polyconeSide
double rNormEdge[2],
zNormEdge[2]; // Normal to edges
int ncorners;
UVector3* corners; // The coordinates of the corners (if phiIsOpen)
private:
double tolerance; // Geometrical surface thickness
double fSurfaceArea; // Used for surface calculation
};
#endif
@@ -0,0 +1,194 @@
//
// ********************************************************************
// * This Software is part of the AIDA Unified Solids Library package *
// * See: https://aidasoft.web.cern.ch/USolids *
// ********************************************************************
//
// $Id:$
//
// --------------------------------------------------------------------
//
// UPolyhedra
//
// Class description:
//
// Class implementing a CSG-like type "PGON":
//
// UPolyhedra( const std::string& name,
// double phiStart, - initial phi starting angle
// double phiTotal, - total phi angle
// int numSide, - number sides
// int numZPlanes, - number of z planes
// const double zPlane[], - position of z planes
// const double rInner[], - tangent distance to inner surface
// const double rOuter[] ) - tangent distance to outer surface
//
// UPolyhedra( const std::string& name,
// double phiStart, - initial phi starting angle
// double phiTotal, - total phi angle
// int numSide, - number sides
// int numRZ, - number corners in r,z space
// const double r[], - r coordinate of these corners
// const double z[] ) - z coordinate of these corners
//
// 19.09.13 Marek Gayer
// Created from original implementation in Geant4
// --------------------------------------------------------------------
#ifndef UPolyhedra_hh
#define UPolyhedra_hh
#include "UVCSGfaceted.hh"
#include "UPolyhedraSide.hh"
class UEnclosingCylinder;
class UReduciblePolygon;
class UPolyhedraHistorical
{
public:
UPolyhedraHistorical();
~UPolyhedraHistorical();
UPolyhedraHistorical(const UPolyhedraHistorical& source);
UPolyhedraHistorical& operator=(const UPolyhedraHistorical& right);
double fStartAngle;
double fOpeningAngle;
int fNumSide;
int fNumZPlanes;
std::vector<double> fZValues;
std::vector<double> Rmin;
std::vector<double> Rmax;
};
class UPolyhedra : public UVCSGfaceted
{
protected:
inline UPolyhedra(const std::string& name) : UVCSGfaceted(name) {}
public: // with description
void Init(
double phiStart, // initial phi starting angle
double phiTotal, // total phi angle
int numSide, // number sides
int numZPlanes, // number of z planes
const double zPlane[], // position of z planes
const double rInner[], // tangent distance to inner surface
const double rOuter[]); // tangent distance to outer surface
UPolyhedra(const std::string& name,
double phiStart, // initial phi starting angle
double phiTotal, // total phi angle
int numSide, // number sides
int numZPlanes, // number of z planes
const double zPlane[], // position of z planes
const double rInner[], // tangent distance to inner surface
const double rOuter[]); // tangent distance to outer surface
UPolyhedra(const std::string& name,
double phiStart, // initial phi starting angle
double phiTotal, // total phi angle
int numSide, // number sides
int numRZ, // number corners in r,z space
const double r[], // r coordinate of these corners
const double z[]); // z coordinate of these corners
virtual ~UPolyhedra();
// Methods for solid
void GetParametersList(int /*aNumber*/, double* /*aArray*/) const {}
void ComputeBBox(UBBox* /*aBox*/, bool /*aStore*/)
{
// Computes bounding box.
std::cout << "ComputeBBox - Not implemented" << std::endl;
}
VUSolid::EnumInside Inside(const UVector3& p) const;
// double DistanceToInDelete( const UVector3 &p,
// const UVector3 &v ) const;
double SafetyFromOutside(const UVector3& aPoint, bool aAccurate = false) const;
UGeometryType GetEntityType() const;
VUSolid* Clone() const;
UVector3 GetPointOnSurface() const;
std::ostream& StreamInfo(std::ostream& os) const;
bool Reset();
// Accessors
inline int GetNumSide() const;
inline double GetStartPhi() const;
inline double GetEndPhi() const;
inline bool IsOpen() const;
inline bool IsGeneric() const;
inline int GetNumRZCorner() const;
inline UPolyhedraSideRZ GetCorner(const int index) const;
inline UPolyhedraHistorical* GetOriginalParameters();
// Returns internal scaled parameters.
inline void SetOriginalParameters(UPolyhedraHistorical& pars);
// Sets internal parameters. Parameters 'Rmin' and 'Rmax' in input must
// be scaled first by a factor computed as 'cos(0.5*phiTotal/theNumSide)',
// if not already scaled.
public: // without description
double DistanceToIn(const UVector3& p,
const UVector3& v, double aPstep = UUtils::kInfinity) const;
UPolyhedra(const UPolyhedra& source);
UPolyhedra& operator=(const UPolyhedra& source);
// Copy constructor and assignment operator.
protected: // without description
inline void SetOriginalParameters();
// Sets internal parameters for the generic constructor.
void Create(double phiStart, // initial phi starting angle
double phiTotal, // total phi angle
int numSide, // number sides
UReduciblePolygon* rz); // rz coordinates
// Generates the shape and is called by each constructor, after the
// conversion of the arguments
void CopyStuff(const UPolyhedra& source);
void DeleteStuff();
// Methods for generation of random points on surface
UVector3 GetPointOnPlane(UVector3 p0, UVector3 p1,
UVector3 p2, UVector3 p3) const;
UVector3 GetPointOnTriangle(UVector3 p0, UVector3 p1,
UVector3 p2) const;
UVector3 GetPointOnSurfaceCorners() const;
void Extent(UVector3& aMin, UVector3& aMax) const;
protected: // without description
int fNumSides; // Number of sides
double fStartPhi; // Starting phi value (0 < phiStart < 2pi)
double fEndPhi; // end phi value (0 < endPhi-phiStart < 2pi)
bool fPhiIsOpen; // true if there is a phi segment
bool fGenericPgon; // true if created through the 2nd generic constructor
int fNumCorner; // number RZ points
UPolyhedraSideRZ* fCorners; // our corners
UPolyhedraHistorical fOriginalParameters; // original input parameters
UEnclosingCylinder* fEnclosingCylinder;
};
#include "UPolyhedra.icc"
#endif
@@ -0,0 +1,95 @@
//
// ********************************************************************
// * This Software is part of the AIDA Unified Solids Library package *
// * See: https://aidasoft.web.cern.ch/USolids *
// ********************************************************************
//
// $Id:$
//
// --------------------------------------------------------------------
//
// UPolyhedra.icc
//
// Implementation of inline methods of UPolyhedra
//
// 19.09.13 Marek Gayer
// Created from original implementation in Geant4
// --------------------------------------------------------------------
inline
int UPolyhedra::GetNumSide() const
{
return fNumSides;
}
inline
double UPolyhedra::GetStartPhi() const
{
return fStartPhi;
}
inline
double UPolyhedra::GetEndPhi() const
{
return fEndPhi;
}
inline
bool UPolyhedra::IsOpen() const
{
return fPhiIsOpen;
}
inline
bool UPolyhedra::IsGeneric() const
{
return fGenericPgon;
}
inline
int UPolyhedra::GetNumRZCorner() const
{
return fNumCorner;
}
inline
UPolyhedraSideRZ UPolyhedra::GetCorner(const int index) const
{
return fCorners[index];
}
inline
UPolyhedraHistorical* UPolyhedra::GetOriginalParameters()
{
return &fOriginalParameters;
}
inline
void UPolyhedra::SetOriginalParameters(UPolyhedraHistorical& pars)
{
fOriginalParameters = pars;
fCubicVolume = 0.;
}
inline
void UPolyhedra::SetOriginalParameters()
{
int fNumPlanes = (int) fNumCorner / 2;
fOriginalParameters.fZValues.resize(fNumPlanes);
fOriginalParameters.Rmin.resize(fNumPlanes);
fOriginalParameters.Rmax.resize(fNumPlanes);
for (int j = 0; j < fNumPlanes; j++)
{
fOriginalParameters.fZValues[j] = fCorners[fNumPlanes + j].z;
fOriginalParameters.Rmax[j] = fCorners[fNumPlanes + j].r;
fOriginalParameters.Rmin[j] = fCorners[fNumPlanes - 1 - j].r;
}
fOriginalParameters.fStartAngle = fStartPhi;
fOriginalParameters.fOpeningAngle = fEndPhi - fStartPhi;
fOriginalParameters.fNumZPlanes = fNumPlanes;
fOriginalParameters.fNumSide = fNumSides;
}
@@ -0,0 +1,180 @@
//
// ********************************************************************
// * This Software is part of the AIDA Unified Solids Library package *
// * See: https://aidasoft.web.cern.ch/USolids *
// ********************************************************************
//
// $Id:$
//
// --------------------------------------------------------------------
//
// UPolyhedraSide
//
// Class description:
//
// Class implementing a face that represents one segmented side
// of a polyhedra:
//
// UPolyhedraSide( const UPolyhedraSideRZ *prevRZ,
// const UPolyhedraSideRZ *tail,
// const UPolyhedraSideRZ *head,
// const UPolyhedraSideRZ *nextRZ,
// int numSide,
// double phiStart, double phiTotal,
// bool phiIsOpen, bool isAllBehind=false )
//
// Values for r1,z1 and r2,z2 should be specified in clockwise
// order in (r,z).
//
// 19.09.13 Marek Gayer
// Created from original implementation in Geant4
// --------------------------------------------------------------------
#ifndef UPolyhedraSide_hh
#define UPolyhedraSide_hh
#include "UVCSGface.hh"
class UIntersectingCone;
struct UPolyhedraSideRZ
{
double r, z; // start of vector
};
class UPolyhedraSide : public UVCSGface
{
public: // with description
UPolyhedraSide(const UPolyhedraSideRZ* prevRZ,
const UPolyhedraSideRZ* tail,
const UPolyhedraSideRZ* head,
const UPolyhedraSideRZ* nextRZ,
int numSide,
double phiStart, double phiTotal,
bool phiIsOpen, bool isAllBehind = false);
virtual ~UPolyhedraSide();
UPolyhedraSide(const UPolyhedraSide& source);
UPolyhedraSide& operator=(const UPolyhedraSide& source);
bool Distance(const UVector3& p, const UVector3& v,
bool outgoing, double surfTolerance,
double& distance, double& distFromSurface,
UVector3& normal, bool& allBehind);
double Safety(const UVector3& p, bool outgoing);
VUSolid::EnumInside Inside(const UVector3& p, double tolerance,
double* bestDistance);
UVector3 Normal(const UVector3& p, double* bestDistance);
double Extent(const UVector3 axis);
UVCSGface* Clone()
{
return new UPolyhedraSide(*this);
}
public: // without description
// Methods used for GetPointOnSurface()
double SurfaceTriangle(UVector3 p1,
UVector3 p2,
UVector3 p3,
UVector3* p4);
UVector3 GetPointOnPlane(UVector3 p0, UVector3 p1,
UVector3 p2, UVector3 p3,
double* Area);
double SurfaceArea();
UVector3 GetPointOnFace();
public: // without description
UPolyhedraSide(__void__&);
// Fake default constructor for usage restricted to direct object
// persistency for clients requiring preallocation of memory for
// persistifiable objects.
protected:
//
// A couple internal data structures
//
struct sUPolyhedraSideVec; // Secret recipe for allowing
friend struct sUPolyhedraSideVec; // protected nested structures
typedef struct sUPolyhedraSideEdge
{
UVector3 normal; // Unit normal to this edge
UVector3 corner[2]; // The two corners of this phi edge
UVector3 cornNorm[2]; // The normals of these corners
} UPolyhedraSideEdge;
typedef struct sUPolyhedraSideVec
{
UVector3 normal, // Normal (point out of the shape)
center, // Point in center of side
surfPhi, // Unit vector on surface pointing along phi
surfRZ; // Unit vector on surface pointing along R/Z
UPolyhedraSideEdge* edges[2]; // The phi boundary edges to this side
// [0]=low phi [1]=high phi
UVector3 edgeNorm[2]; // RZ edge normals [i] at {r[i],z[i]}
} UPolyhedraSideVec;
bool IntersectSidePlane(const UVector3& p, const UVector3& v,
const UPolyhedraSideVec& vec,
double normSign,
double surfTolerance,
double& distance,
double& distFromSurface);
int LineHitsSegments(const UVector3& p,
const UVector3& v,
int* i1, int* i2);
int ClosestPhiSegment(double phi);
int PhiSegment(double phi);
double GetPhi(const UVector3& p);
double DistanceToOneSide(const UVector3& p,
const UPolyhedraSideVec& vec,
double* normDist);
double DistanceAway(const UVector3& p,
const UPolyhedraSideVec& vec,
double* normDist);
void CopyStuff(const UPolyhedraSide& source);
protected:
int numSide; // Number sides
double r[2], z[2]; // r, z parameters, in specified order
double startPhi, // Start phi (0 to 2pi), if phiIsOpen
deltaPhi, // Delta phi (0 to 2pi), if phiIsOpen
endPhi; // End phi (>startPhi), if phiIsOpen
bool phiIsOpen; // True if there is a phi slice
bool allBehind; // True if the entire solid is "behind" this face
UIntersectingCone* cone; // Our intersecting cone
UPolyhedraSideVec* vecs; // Vector Set for each facet of our face
UPolyhedraSideEdge* edges; // The edges belong to vecs
double lenRZ, // RZ length of each side
lenPhi[2]; // Phi dimensions of each side
double edgeNorm; // Normal in RZ/Phi space to each side
private:
std::pair<UVector3, double> fPhi; // Cached value for phi
double kCarTolerance; // Geometrical surface thickness
double fSurfaceArea; // Surface Area
};
#endif
@@ -0,0 +1,190 @@
//
// ********************************************************************
// * This Software is part of the AIDA Unified Solids Library package *
// * See: https://aidasoft.web.cern.ch/USolids *
// ********************************************************************
//
// $Id:$
//
// --------------------------------------------------------------------
//
// UReduciblePolygon
//
// Class description:
//
// Utility class used to specify, test, reduce, and/or otherwise
// manipulate a 2D polygon.
//
// For this class, a polygon consists of n > 2 points in 2D
// space (a,b). The polygon is always closed by connecting the
// last point to the first. A UReduciblePolygon is guaranteed
// to fulfill this definition in all instances.
//
// Illegal manipulations (such that a valid polygon would be
// produced) result in an error return if possible and
// otherwise a // UException.
//
// The Set of manipulations is limited currently to what
// is needed for UPolycone and UPolyhedra.
//
// 19.09.13 Marek Gayer
// Created from original implementation in Geant4
// --------------------------------------------------------------------
#ifndef UReduciblePolygon_hh
#define UReduciblePolygon_hh
#include "UTypes.hh"
class UReduciblePolygon
{
friend class UReduciblePolygonIterator;
public:
//
// Creator: via simple a/b arrays
//
UReduciblePolygon(const double a[], const double b[], int n);
//
// Creator: a special version for UPolygon and UPolycone
// that takes two a points at planes of b
// (where a==r and b==z for the GEANT3 classic PCON and PGON)
//
UReduciblePolygon(const double rmin[], const double rmax[],
const double z[], int n);
virtual ~UReduciblePolygon();
//
// Queries
//
inline int NumVertices() const
{
return numVertices;
}
inline double Amin() const
{
return aMin;
}
inline double Amax() const
{
return aMax;
}
inline double Bmin() const
{
return bMin;
}
inline double Bmax() const
{
return bMax;
}
void CopyVertices(double a[], double b[]) const;
//
// Manipulations
//
void ScaleA(double scale);
void ScaleB(double scale);
bool RemoveDuplicateVertices(double tolerance);
bool RemoveRedundantVertices(double tolerance);
void ReverseOrder();
void StartWithZMin();
//
// Tests
//
double Area();
bool CrossesItself(double tolerance);
bool BisectedBy(double a1, double b1,
double a2, double b2, double tolerance);
void Print(); // Debugging only
public: // without description
protected:
void Create(const double a[], const double b[], int n);
void CalculateMaxMin();
//
// Below are member values that are *always* kept up to date (please!)
//
double aMin, aMax, bMin, bMax;
int numVertices;
//
// A subclass which holds the vertices in a single-linked list
//
// Yeah, call me an old-fashioned c hacker, but I cannot make
// myself use the rogue tools for this trivial list.
//
struct ABVertex; // Secret recipe for allowing
friend struct ABVertex; // protected nested structures
struct ABVertex
{
ABVertex() : a(0.), b(0.), next(0) {}
double a, b;
ABVertex* next;
};
ABVertex* vertexHead;
private:
UReduciblePolygon(const UReduciblePolygon&);
UReduciblePolygon& operator=(const UReduciblePolygon&);
// Private copy constructor and assignment operator.
};
//
// A companion class for iterating over the vertices of our polygon.
// It is simple enough that all routines are declared inline here.
//
class UReduciblePolygonIterator
{
public:
UReduciblePolygonIterator(const UReduciblePolygon* theSubject)
{
subject = theSubject;
current = 0;
}
void Begin()
{
current = subject->vertexHead;
}
bool Next()
{
if (current) current = current->next;
return Valid();
}
bool Valid() const
{
return current != 0;
}
double GetA() const
{
return current->a;
}
double GetB() const
{
return current->b;
}
protected:
const UReduciblePolygon* subject; // Who are we iterating over
UReduciblePolygon::ABVertex* current; // Current vertex
};
#endif
@@ -0,0 +1,503 @@
//
// ********************************************************************
// * This Software is part of the AIDA Unified Solids Library package *
// * See: https://aidasoft.web.cern.ch/USolids *
// ********************************************************************
//
// $Id:$
//
// --------------------------------------------------------------------
//
// USphere
//
// Class description:
//
// A USphere is, in the general case, a section of a spherical shell,
// between specified phi and theta angles
//
// The phi and theta segments are described by a starting angle,
// and the +ve delta angle for the shape.
// If the delta angle is >=2*UUtils::kPi, or >=UUtils::kPi the shape is treated as
// continuous in phi or theta respectively.
//
// Theta must lie between 0-UUtils::kPi (incl).
//
// Member Data:
//
// fRmin inner radius
// fRmax outer radius
//
// fSPhi starting angle of the segment in radians
// fDPhi delta angle of the segment in radians
//
// fSTheta starting angle of the segment in radians
// fDTheta delta angle of the segment in radians
//
//
// Note:
// Internally fSPhi & fDPhi are adjusted so that fDPhi<=2PI,
// and fDPhi+fSPhi<=2PI. This enables simpler comparisons to be
// made with (say) Phi of a point.
//
// 19.10.12 Marek Gayer
// Created from original implementation in Geant4
// --------------------------------------------------------------------
#ifndef USphere_HH
#define USphere_HH
#include <sstream>
#include "VUSolid.hh"
class UVisExtent;
class USphere : public VUSolid
{
public: // with description
USphere(const std::string& pName,
double pRmin, double pRmax,
double pSPhi, double pDPhi,
double pSTheta, double pDTheta);
//
// Constructs a sphere or sphere shell section
// with the given name and dimensions
~USphere();
//
// Destructor
// Accessors
inline double GetInnerRadius() const;
inline double GetOuterRadius() const;
inline double GetStartPhiAngle() const;
inline double GetDeltaPhiAngle() const;
inline double GetStartThetaAngle() const;
inline double GetDeltaThetaAngle() const;
// Modifiers
inline void SetInnerRadius(double newRMin);
inline void SetOuterRadius(double newRmax);
inline void SetStartPhiAngle(double newSphi, bool trig = true);
inline void SetDeltaPhiAngle(double newDphi);
inline void SetStartThetaAngle(double newSTheta);
inline void SetDeltaThetaAngle(double newDTheta);
// Methods for solid
inline double Capacity();
double SurfaceArea();
VUSolid::EnumInside Inside(const UVector3& p) const;
bool Normal(const UVector3& p, UVector3& n) const;
double DistanceToIn(const UVector3& p, const UVector3& v, double aPstep = UUtils::kInfinity) const;
double SafetyFromOutside(const UVector3& p, bool aAccurate = false) const;
double DistanceToOut(const UVector3& p, const UVector3& v, UVector3& n, bool& validNorm, double aPstep = UUtils::kInfinity) const;
double SafetyFromInside(const UVector3& p, bool aAccurate = false) const;
UGeometryType GetEntityType() const;
UVector3 GetPointOnSurface() const;
VUSolid* Clone() const;
std::ostream& StreamInfo(std::ostream& os) const;
// Visualisation functions
UVisExtent GetExtent() const;
public: // without description
void Extent(UVector3& aMin, UVector3& aMax) const;
void GetParametersList(int /*aNumber*/, double* /*aArray*/) const;
virtual void ComputeBBox(UBBox* /*aBox*/, bool /*aStore = false*/) {}
USphere(const USphere& rhs);
USphere& operator=(const USphere& rhs);
// Copy constructor and assignment operator.
// Old access functions
inline double GetRmin() const;
inline double GetRmax() const;
inline double GetSPhi() const;
inline double GetDPhi() const;
inline double GetSTheta() const;
inline double GetDTheta() const;
inline double GetInsideRadius() const;
inline void SetInsideRadius(double newRmin);
private:
double fCubicVolume;
double fSurfaceArea;
inline void Initialize();
//
// Reset relevant values to zero
inline void CheckThetaAngles(double sTheta, double dTheta);
inline void CheckSPhiAngle(double sPhi);
inline void CheckDPhiAngle(double dPhi);
inline void CheckPhiAngles(double sPhi, double dPhi);
//
// Reset relevant flags and angle values
inline void InitializePhiTrigonometry();
inline void InitializeThetaTrigonometry();
//
// Recompute relevant trigonometric values and cache them
UVector3 ApproxSurfaceNormal(const UVector3& p) const;
//
// Algorithm for SurfaceNormal() following the original
// specification for points not on the surface
private:
// Used by distanceToOut
//
enum ESide {kNull, kRMin, kRMax, kSPhi, kEPhi, kSTheta, kETheta};
// used by normal
//
enum ENorm {kNRMin, kNRMax, kNSPhi, kNEPhi, kNSTheta, kNETheta};
double fRminTolerance, kTolerance, kAngTolerance,
kRadTolerance, fEpsilon;
//
// Radial and angular tolerances
double fRmin, fRmax, fSPhi, fDPhi, fSTheta, fDTheta;
//
// Radial and angular dimensions
double sinCPhi, cosCPhi, cosHDPhiOT, cosHDPhiIT,
sinSPhi, cosSPhi, sinEPhi, cosEPhi, hDPhi, cPhi, ePhi;
//
// Cached trigonometric values for Phi angle
double sinSTheta, cosSTheta, sinETheta, cosETheta,
tanSTheta, tanSTheta2, tanETheta, tanETheta2, eTheta;
//
// Cached trigonometric values for Theta angle
bool fFullPhiSphere, fFullThetaSphere, fFullSphere;
//
// Flags for identification of section, shell or full sphere
};
inline
double USphere::GetInsideRadius() const
{
return fRmin;
}
inline
double USphere::GetInnerRadius() const
{
return fRmin;
}
inline
double USphere::GetOuterRadius() const
{
return fRmax;
}
inline
double USphere::GetStartPhiAngle() const
{
return fSPhi;
}
inline
double USphere::GetDeltaPhiAngle() const
{
return fDPhi;
}
inline
double USphere::GetStartThetaAngle() const
{
return fSTheta;
}
double USphere::GetDeltaThetaAngle() const
{
return fDTheta;
}
inline
void USphere::Initialize()
{
fCubicVolume = 0.;
fSurfaceArea = 0.;
}
inline
void USphere::InitializePhiTrigonometry()
{
hDPhi = 0.5 * fDPhi; // half delta phi
cPhi = fSPhi + hDPhi;
ePhi = fSPhi + fDPhi;
sinCPhi = std::sin(cPhi);
cosCPhi = std::cos(cPhi);
cosHDPhiIT = std::cos(hDPhi - 0.5 * kAngTolerance); // inner/outer tol half dphi
cosHDPhiOT = std::cos(hDPhi + 0.5 * kAngTolerance);
sinSPhi = std::sin(fSPhi);
cosSPhi = std::cos(fSPhi);
sinEPhi = std::sin(ePhi);
cosEPhi = std::cos(ePhi);
}
inline
void USphere::InitializeThetaTrigonometry()
{
eTheta = fSTheta + fDTheta;
sinSTheta = std::sin(fSTheta);
cosSTheta = std::cos(fSTheta);
sinETheta = std::sin(eTheta);
cosETheta = std::cos(eTheta);
tanSTheta = std::tan(fSTheta);
tanSTheta2 = tanSTheta * tanSTheta;
tanETheta = std::tan(eTheta);
tanETheta2 = tanETheta * tanETheta;
}
inline
void USphere::CheckThetaAngles(double sTheta, double dTheta)
{
if ((sTheta < 0) || (sTheta > UUtils::kPi))
{
std::ostringstream message;
message << "sTheta outside 0-PI range." << std::endl
<< "Invalid starting Theta angle for solid: " << GetName();
UUtils::Exception("USphere::CheckThetaAngles()", "GeomSolids0002",
FatalError, 1, message.str().c_str());
}
else
{
fSTheta = sTheta;
}
if (dTheta + sTheta >= UUtils::kPi)
{
fDTheta = UUtils::kPi - sTheta;
}
else if (dTheta > 0)
{
fDTheta = dTheta;
}
else
{
std::ostringstream message;
message << "Invalid dTheta." << std::endl
<< "Negative delta-Theta (" << dTheta << "), for solid: "
<< GetName();
UUtils::Exception("USphere::CheckThetaAngles()", "GeomSolids0002",
FatalError, 1, message.str().c_str());
}
if (fDTheta - fSTheta < UUtils::kPi)
{
fFullThetaSphere = false;
}
else
{
fFullThetaSphere = true ;
}
fFullSphere = fFullPhiSphere && fFullThetaSphere;
InitializeThetaTrigonometry();
}
inline
void USphere::CheckSPhiAngle(double sPhi)
{
// Ensure fSphi in 0-2PI or -2PI-0 range if shape crosses 0
if (sPhi < 0)
{
fSPhi = 2 * UUtils::kPi - std::fmod(std::fabs(sPhi), 2 * UUtils::kPi);
}
else
{
fSPhi = std::fmod(sPhi, 2 * UUtils::kPi) ;
}
if (fSPhi + fDPhi > 2 * UUtils::kPi)
{
fSPhi -= 2 * UUtils::kPi ;
}
}
inline
void USphere::CheckDPhiAngle(double dPhi)
{
fFullPhiSphere = true;
if (dPhi >= 2 * UUtils::kPi - kAngTolerance * 0.5)
{
fDPhi = 2 * UUtils::kPi;
fSPhi = 0;
}
else
{
fFullPhiSphere = false;
if (dPhi > 0)
{
fDPhi = dPhi;
}
else
{
std::ostringstream message;
message << "Invalid dphi." << std::endl
<< "Negative delta-Phi (" << dPhi << "), for solid: "
<< GetName();
UUtils::Exception("USphere::CheckDPhiAngle()", "GeomSolids0002",
FatalError, 1, message.str().c_str());
}
}
}
inline
void USphere::CheckPhiAngles(double sPhi, double dPhi)
{
CheckDPhiAngle(dPhi);
//if (!fFullPhiSphere && sPhi) { CheckSPhiAngle(sPhi); }
if (!fFullPhiSphere)
{
CheckSPhiAngle(sPhi);
}
fFullSphere = fFullPhiSphere && fFullThetaSphere;
InitializePhiTrigonometry();
}
inline
void USphere::SetInsideRadius(double newRmin)
{
fRmin = newRmin;
fRminTolerance = (fRmin) ? std::max(kRadTolerance, fEpsilon * fRmin) : 0;
Initialize();
}
inline
void USphere::SetInnerRadius(double newRmin)
{
SetInsideRadius(newRmin);
}
inline
void USphere::SetOuterRadius(double newRmax)
{
fRmax = newRmax;
kTolerance = std::max(kRadTolerance, fEpsilon * fRmax);
Initialize();
}
inline
void USphere::SetStartPhiAngle(double newSPhi, bool compute)
{
// Flag 'compute' can be used to explicitely avoid recomputation of
// trigonometry in case SetDeltaPhiAngle() is invoked afterwards
CheckSPhiAngle(newSPhi);
fFullPhiSphere = false;
if (compute)
{
InitializePhiTrigonometry();
}
Initialize();
}
inline
void USphere::SetDeltaPhiAngle(double newDPhi)
{
CheckPhiAngles(fSPhi, newDPhi);
Initialize();
}
inline
void USphere::SetStartThetaAngle(double newSTheta)
{
CheckThetaAngles(newSTheta, fDTheta);
Initialize();
}
inline
void USphere::SetDeltaThetaAngle(double newDTheta)
{
CheckThetaAngles(fSTheta, newDTheta);
Initialize();
}
// Old access functions
inline
double USphere::GetRmin() const
{
return GetInsideRadius();
}
inline
double USphere::GetRmax() const
{
return GetOuterRadius();
}
inline
double USphere::GetSPhi() const
{
return GetStartPhiAngle();
}
inline
double USphere::GetDPhi() const
{
return GetDeltaPhiAngle();
}
inline
double USphere::GetSTheta() const
{
return GetStartThetaAngle();
}
inline
double USphere::GetDTheta() const
{
return GetDeltaThetaAngle();
}
inline
double USphere::Capacity()
{
if (fCubicVolume != 0.)
{
;
}
else
{
fCubicVolume = fDPhi * (std::cos(fSTheta) - std::cos(fSTheta + fDTheta)) *
(fRmax * fRmax * fRmax - fRmin * fRmin * fRmin) / 3.;
}
return fCubicVolume;
}
#endif
@@ -0,0 +1,143 @@
//
// ********************************************************************
// * This Software is part of the AIDA Unified Solids Library package *
// * See: https://aidasoft.web.cern.ch/USolids *
// ********************************************************************
//
// $Id:$
//
// --------------------------------------------------------------------
//
// UTet
//
// Class description:
//
// A UTet is a tetrahedrasolid.
//
// 19.07.13 Tatiana Nikitina
// Created from original implementation in Geant4
// --------------------------------------------------------------------
#ifndef UTet_hh
#define UTet_hh
#include "VUSolid.hh"
#include "UUtils.hh"
class UTet : public VUSolid
{
public: // with description
UTet(const std::string& name,
UVector3 anchor,
UVector3 p2,
UVector3 p3,
UVector3 p4,
bool* degeneracyFlag = 0);
virtual ~UTet();
// Methods for solid
EnumInside Inside(const UVector3& p) const;
bool Normal(const UVector3& aPoint, UVector3& aNormal) const;
double SafetyFromInside(const UVector3& aPoint,
bool aAccurate = false) const;
double SafetyFromOutside(const UVector3& aPoint,
bool aAccurate = false) const;
double DistanceToIn(const UVector3& aPoint,
const UVector3& aDirection,
// UVector3 &aNormalVector,
double aPstep = UUtils::kInfinity) const;
double DistanceToOut(const UVector3& aPoint,
const UVector3& aDirection,
UVector3& aNormalVector,
bool& aConvex,
double aPstep = UUtils::kInfinity) const;
void Extent(UVector3& aMin, UVector3& aMax) const;
double Capacity();
double SurfaceArea();
UGeometryType GetEntityType() const;
void ComputeBBox(UBBox* /*aBox*/, bool /*aStore = false*/) {}
//G4Visualisation
void GetParametersList(int aNumber, double* aArray) const;
VUSolid* Clone() const
{
std::vector<UVector3> v = GetVertices();
return new UTet(GetName(), v[0], v[1], v[2], v[3]);
}
UVector3 GetPointOnSurface() const;
std::ostream& StreamInfo(std::ostream& os) const;
public: // without description
//UTet(__void__&);
// Fake default constructor for usage restricted to direct object
// persistency for clients requiring preallocation of memory for
// persistifiable objects.
UTet(const UTet& rhs);
UTet& operator=(const UTet& rhs);
// Copy constructor and assignment operator.
const char* CVSHeaderVers()
{
return "$Id: G4Tet.hh 66356 2012-12-18 09:02:32Z gcosmo $";
}
const char* CVSFileVers()
{
return CVSVers;
}
void PrintWarnings(bool flag)
{
warningFlag = flag;
}
static bool CheckDegeneracy(UVector3& anchor,
UVector3& p2,
UVector3& p3,
UVector3& p4);
std::vector<UVector3> GetVertices() const;
// Return the four vertices of the shape.
protected: // with description
/* UVectorList*
CreateRotatedVertices(const G4AffineTransform& pTransform) const;
// Create the List of transformed vertices in the format required
// for G4VSolid:: ClipCrossSection and ClipBetweenSections.
*/
private:
double fCubicVolume, fSurfaceArea;
UVector3 GetPointOnFace(UVector3 p1, UVector3 p2,
UVector3 p3, double& area) const;
static const char CVSVers[];
private:
UVector3 fAnchor, fP2, fP3, fP4, fMiddle;
UVector3 fNormal123, fNormal142, fNormal134, fNormal234;
bool warningFlag;
double fCdotN123, fCdotN142, fCdotN134, fCdotN234;
double fXMin, fXMax, fYMin, fYMax, fZMin, fZMax;
double fDx, fDy, fDz, fTol, fMaxSize;
};
#endif
@@ -0,0 +1,59 @@
//
// ********************************************************************
// * This Software is part of the AIDA Unified Solids Library package *
// * See: https://aidasoft.web.cern.ch/USolids *
// ********************************************************************
//
// $Id:$
//
// --------------------------------------------------------------------
//
// UTransform3D
//
// Class description:
//
// UTransform3D: General transformation made by rotation + translation
//
// 19.10.12 Marek Gayer
// Created from original implementation in CLHEP
// --------------------------------------------------------------------
#ifndef USOLIDS_UTransform3D
#define USOLIDS_UTransform3D
#include "UVector3.hh"
class UTransform3D
{
public:
UVector3 fTr; // Translation
double fRot[9]; // Rotation
UTransform3D(); // Initialize to identity
UTransform3D(double tx, double ty, double tz,
double phi = 0., double theta = 0., double psi = 0.);
UTransform3D(const UTransform3D& other);
~UTransform3D() {}
virtual void RotateX(double angle);
virtual void RotateY(double angle);
virtual void RotateZ(double angle);
void SetAngles(double phi, double theta, double psi);
// Local<->global coordinate and vector conversions
UVector3 GlobalPoint(const UVector3& local) const;
UVector3 GlobalVector(const UVector3& local) const;
UVector3 LocalPoint(const UVector3& global) const;
UVector3 LocalVector(const UVector3& global) const;
// Operators
UTransform3D& operator = (const UTransform3D& other);
UTransform3D& operator *= (const UTransform3D& other);
UTransform3D& operator *= (const UVector3& vect);
};
// Vector-matrix multiplication
UVector3 operator * (const UVector3& p, const UTransform3D& trans);
#endif
@@ -0,0 +1,118 @@
//
// ********************************************************************
// * This Software is part of the AIDA Unified Solids Library package *
// * See: https://aidasoft.web.cern.ch/USolids *
// ********************************************************************
//
// $Id:$
//
// --------------------------------------------------------------------
//
// UTrd
//
// Class description:
//
// A UTrd is a trapezoid with the x and y dimensions varying along z
// functions.
//
// 19.10.12 Marek Gayer
// Created from original implementation in Geant4
// --------------------------------------------------------------------
#ifndef USOLIDS_UTrd
#define USOLIDS_UTrd
#include "VUSolid.hh"
#include "UUtils.hh"
class UTrd : public VUSolid
{
enum ESide {kUndefined, kPX, kMX, kPY, kMY, kPZ, kMZ};
public:
UTrd() : VUSolid(), fDx1(0), fDx2(0), fDy1(0), fDy2(0), fDz(0) {}
UTrd(const std::string& pName, double pdx1, double pdx2, double pdy1, double pdy2, double pdz);
virtual ~UTrd() {}
UTrd(const UTrd& rhs);
UTrd& operator=(const UTrd& rhs);
// Copy constructor and assignment operator
// Accessors
inline double GetXHalfLength1() const;
inline double GetXHalfLength2() const;
inline double GetYHalfLength1() const;
inline double GetYHalfLength2() const;
inline double GetZHalfLength() const;
// Modifiers
inline void SetXHalfLength1(double val);
inline void SetXHalfLength2(double val);
inline void SetYHalfLength1(double val);
inline void SetYHalfLength2(double val);
inline void SetZHalfLength(double val);
// Navigation methods
EnumInside Inside(const UVector3& aPoint) const;
virtual double SafetyFromInside(const UVector3& aPoint, bool aAccurate = false) const;
inline double SafetyFromInsideAccurate(const UVector3& aPoint) const;
virtual double SafetyFromOutside(const UVector3& aPoint, bool aAccurate = false) const;
inline double SafetyFromOutsideAccurate(const UVector3& aPoint) const;
virtual double DistanceToIn(const UVector3& aPoint,
const UVector3& aDirection,
// UVector3 &aNormalVector,
double aPstep = UUtils::kInfinity) const;
virtual double DistanceToOut(const UVector3& aPoint,
const UVector3& aDirection,
UVector3& aNormalVector,
bool& aConvex,
double aPstep = UUtils::kInfinity) const;
virtual bool Normal(const UVector3& aPoint, UVector3& aNormal) const;
void CheckAndSetAllParameters ( double pdx1, double pdx2,
double pdy1, double pdy2,
double pdz );
void SetAllParameters ( double pdx1, double pdx2,
double pdy1, double pdy2,
double pdz );
// virtual void Extent ( EAxisType aAxis, double &aMin, double &aMax ) const;
void Extent(UVector3& aMin, UVector3& aMax) const;
inline double Capacity();
inline double SurfaceArea();
inline VUSolid* Clone() const
{
return new UTrd(GetName(), fDx1, fDx2, fDy1, fDy2, fDz);
}
UGeometryType GetEntityType() const;
virtual void ComputeBBox(UBBox* /*aBox*/, bool /*aStore = false*/) {}
//G4Visualisation
virtual void GetParametersList(int /*aNumber*/, double* /*aArray*/) const;
std::ostream& StreamInfo(std::ostream& os) const;
UVector3 GetPointOnSurface() const;
private:
inline UVector3 ApproxSurfaceNormal(const UVector3& p) const;
inline double amin(int n, const double* a) const;
inline double amax(int n, const double* a)const;
double fDx1, fDx2, fDy1, fDy2, fDz;
double fCubicVolume; // Cubic Volume
double fSurfaceArea; // Surface Area
};
#include "UTrd.icc"
#endif
@@ -0,0 +1,142 @@
//
// ********************************************************************
// * This Software is part of the AIDA Unified Solids Library package *
// * See: https://aidasoft.web.cern.ch/USolids *
// ********************************************************************
//
// $Id:$
//
// --------------------------------------------------------------------
//
// UTrd.icc
//
// Implementation of inline methods of UTrd
//
// 19.10.12 Marek Gayer
// Created from original implementation in Geant4
// --------------------------------------------------------------------
inline
double UTrd::GetXHalfLength1() const
{
return fDx1;
}
inline
double UTrd::GetXHalfLength2() const
{
return fDx2;
}
inline
double UTrd::GetYHalfLength1() const
{
return fDy1;
}
inline
double UTrd::GetYHalfLength2() const
{
return fDy2;
}
inline
double UTrd::GetZHalfLength() const
{
return fDz;
}
inline
void UTrd::SetXHalfLength1(double val)
{
fDx1 = val;
fCubicVolume = 0.;
fSurfaceArea = 0;
}
inline
void UTrd::SetXHalfLength2(double val)
{
fDx2 = val;
fCubicVolume = 0.;
fSurfaceArea = 0;
}
inline
void UTrd::SetYHalfLength1(double val)
{
fDy1 = val;
fCubicVolume = 0.;
fSurfaceArea = 0;
}
inline
void UTrd::SetYHalfLength2(double val)
{
fDy2 = val;
fCubicVolume = 0.;
fSurfaceArea = 0;
}
inline
void UTrd::SetZHalfLength(double val)
{
fDz = val;
fCubicVolume = 0.;
fSurfaceArea = 0;
}
inline
double UTrd::Capacity()
{
if (fCubicVolume != 0.)
{
;
}
else
{
fCubicVolume = 2 * fDz * ((fDx1 + fDx2) * (fDy1 + fDy2)
+ (fDx2 - fDx1) * (fDy2 - fDy1) / 3);
}
return fCubicVolume;
}
inline
double UTrd::SurfaceArea()
{
if (fSurfaceArea != 0.)
{
;
}
else
{
fSurfaceArea = 4 * (fDx1 * fDy1 + fDx2 * fDy2)
+ 2 * ((fDy1 + fDy2) * std::sqrt(4 * fDz * fDz + (fDx2 - fDx1) * (fDx2 - fDx1))
+ (fDx1 + fDx2) * std::sqrt(4 * fDz * fDz + (fDy2 - fDy1) * (fDy2 - fDy1)));
}
return fSurfaceArea;
}
inline double UTrd::amin(int n, const double* a) const
{
// Return value from array with the minimum element.
double xmin = a[0];
for (int i = 1; i < n; i++)
{
if (xmin > a[i]) xmin = a[i];
}
return xmin;
}
inline double UTrd::amax(int n, const double* a)const
{
// Return value from array with the maximum element.
double xmax = a[0];
for (int i = 1; i < n; i++)
{
if (xmax < a[i]) xmax = a[i];
}
return xmax;
}
@@ -0,0 +1,186 @@
//
// ********************************************************************
// * This Software is part of the AIDA Unified Solids Library package *
// * See: https://aidasoft.web.cern.ch/USolids *
// ********************************************************************
//
// $Id:$
//
// --------------------------------------------------------------------
//
// UTubs
//
// Class description:
//
// A tube or tube segment with curved sides parallel to
// the z-axis. The tube has a specified half-length along
// the z-axis, about which it is centered, and a given
// minimum and maximum radius. A minimum radius of 0
// corresponds to filled tube /cylinder. The tube segment is
// specified by starting and delta angles for phi, with 0
// being the +x axis, PI/2 the +y axis.
// A delta angle of 2PI signifies a complete, unsegmented
// tube/cylinder.
//
// Member Data:
//
// fRMin Inner radius
// fRMax Outer radius
// fDz half length in z
//
// fSPhi The starting phi angle in radians,
// adjusted such that fSPhi+fDPhi<=2PI, fSPhi>-2PI
//
// fDPhi Delta angle of the segment.
//
// fPhiFullTube Boolean variable used for indicate the Phi Section
//
// 19.10.12 Marek Gayer
// Created from original implementation in Geant4
// --------------------------------------------------------------------
#ifndef UTUBS_HH
#define UTUBS_HH
#include "VUSolid.hh"
class UTubs : public VUSolid
{
public: // with description
UTubs(const std::string& pName,
double pRMin,
double pRMax,
double pDz,
double pSPhi,
double pDPhi);
//
// Constructs a tubs with the given name and dimensions
virtual ~UTubs();
//
// Destructor
// Accessors
inline double GetInnerRadius() const;
inline double GetOuterRadius() const;
inline double GetZHalfLength() const;
inline double GetStartPhiAngle() const;
inline double GetDeltaPhiAngle() const;
// Modifiers
inline void SetInnerRadius(double newRMin);
inline void SetOuterRadius(double newRMax);
inline void SetZHalfLength(double newDz);
inline void SetStartPhiAngle(double newSPhi, bool trig = true);
inline void SetDeltaPhiAngle(double newDPhi);
// Methods for solid
inline double Capacity();
inline double SurfaceArea();
inline VUSolid::EnumInside Inside(const UVector3& p) const;
bool Normal(const UVector3& p, UVector3& normal) const;
double DistanceToIn(const UVector3& p, const UVector3& v, double aPstep = UUtils::kInfinity) const;
double SafetyFromInside(const UVector3& p, bool precise = false) const;
double DistanceToOut(const UVector3& p, const UVector3& v, UVector3& n, bool& validNorm, double aPstep = UUtils::kInfinity) const;
double SafetyFromOutside(const UVector3& p, bool precise = false) const;
UGeometryType GetEntityType() const;
UVector3 GetPointOnSurface() const;
VUSolid* Clone() const;
std::ostream& StreamInfo(std::ostream& os) const;
// void Extent (EAxisType aAxis, double &aMin, double &aMax) const;
void Extent(UVector3& aMin, UVector3& aMax) const;
virtual void GetParametersList(int /*aNumber*/, double* /*aArray*/) const;
virtual void ComputeBBox(UBBox* /*aBox*/, bool /*aStore = false*/) {}
public: // without description
UTubs();
//
// Fake default constructor for usage restricted to direct object
// persistency for clients requiring preallocation of memory for
// persistifiable objects.
UTubs(const UTubs& rhs);
UTubs& operator=(const UTubs& rhs);
// Copy constructor and assignment operator.
// Older names for access functions
inline double GetRMin() const;
inline double GetRMax() const;
inline double GetDz() const;
inline double GetSPhi() const;
inline double GetDPhi() const;
protected:
// UVector3List*
// CreateRotatedVertices( const UAffineTransform& pTransform ) const;
//
// Creates the List of transformed vertices in the format required
// for VUSolid:: ClipCrossSection and ClipBetweenSections
inline void Initialize();
//
// Reset relevant values to zero
inline void CheckSPhiAngle(double sPhi);
inline void CheckDPhiAngle(double dPhi);
inline void CheckPhiAngles(double sPhi, double dPhi);
//
// Reset relevant flags and angle values
inline void InitializeTrigonometry();
//
// Recompute relevant trigonometric values and cache them
virtual UVector3 ApproxSurfaceNormal(const UVector3& p) const;
//
// Algorithm for SurfaceNormal() following the original
// specification for points not on the surface
protected:
double fCubicVolume, fSurfaceArea;
// Used by distanceToOut
//
enum ESide {kNull, kRMin, kRMax, kSPhi, kEPhi, kPZ, kMZ};
// Used by normal
//
enum ENorm {kNRMin, kNRMax, kNSPhi, kNEPhi, kNZ};
double kRadTolerance, kAngTolerance;
//
// Radial and angular tolerances
double fRMin, fRMax, fDz, fSPhi, fDPhi;
//
// Radial and angular dimensions
double fSinCPhi, fCosCPhi, fCosHDPhiOT, fCosHDPhiIT,
fSinSPhi, fCosSPhi, fSinEPhi, fCosEPhi, fSinSPhiDPhi, fCosSPhiDPhi;
//
// Cached trigonometric values
bool fPhiFullTube;
//
// Flag for identification of section or full tube
};
#include "UTubs.icc"
#endif
@@ -0,0 +1,267 @@
//
// ********************************************************************
// * This Software is part of the AIDA Unified Solids Library package *
// * See: https://aidasoft.web.cern.ch/USolids *
// ********************************************************************
//
// $Id:$
//
// --------------------------------------------------------------------
//
// UTubs.icc
//
// Implementation of inline methods of UTubs
//
// 19.10.12 Marek Gayer
// Created from original implementation in Geant4
// --------------------------------------------------------------------
inline
double UTubs::GetInnerRadius() const
{
return fRMin;
}
inline
double UTubs::GetOuterRadius() const
{
return fRMax;
}
inline
double UTubs::GetZHalfLength() const
{
return fDz;
}
inline
double UTubs::GetStartPhiAngle() const
{
return fSPhi;
}
inline
double UTubs::GetDeltaPhiAngle() const
{
return fDPhi;
}
inline
void UTubs::Initialize()
{
fCubicVolume = 0.;
fSurfaceArea = 0.;
}
inline
void UTubs::InitializeTrigonometry()
{
double hDPhi = 0.5 * fDPhi; // half delta phi
double cPhi = fSPhi + hDPhi;
double ePhi = fSPhi + fDPhi;
fSinCPhi = std::sin(cPhi);
fCosCPhi = std::cos(cPhi);
fCosHDPhiIT = std::cos(hDPhi - 0.5 * kAngTolerance); // inner/outer tol half dphi
fCosHDPhiOT = std::cos(hDPhi + 0.5 * kAngTolerance);
fSinSPhi = std::sin(fSPhi);
fCosSPhi = std::cos(fSPhi);
fSinEPhi = std::sin(ePhi);
fCosEPhi = std::cos(ePhi);
fSinSPhiDPhi = std::sin(fSPhi + fDPhi);
fCosSPhiDPhi = std::cos(fSPhi + fDPhi);
}
inline void UTubs::CheckSPhiAngle(double sPhi)
{
// Ensure fSphi in 0-2PI or -2PI-0 range if shape crosses 0
if (sPhi < 0)
{
fSPhi = 2 * UUtils::kPi - std::fmod(std::fabs(sPhi), 2 * UUtils::kPi);
}
else
{
fSPhi = std::fmod(sPhi, 2 * UUtils::kPi) ;
}
if (fSPhi + fDPhi > 2 * UUtils::kPi)
{
fSPhi -= 2 * UUtils::kPi ;
}
}
inline void UTubs::CheckDPhiAngle(double dPhi)
{
fPhiFullTube = true;
if (dPhi >= 2 * UUtils::kPi - kAngTolerance * 0.5)
{
fDPhi = 2 * UUtils::kPi;
fSPhi = 0;
}
else
{
fPhiFullTube = false;
if (dPhi > 0)
{
fDPhi = dPhi;
}
else
{
std::ostringstream message;
message << "Invalid dphi." << std::endl
<< "Negative or zero delta-Phi (" << dPhi << "), for solid: "
<< GetName();
UUtils::Exception("UTubs::CheckDPhiAngle()", "GeomSolids0002",
FatalError, 1, message.str().c_str());
}
}
}
inline void UTubs::CheckPhiAngles(double sPhi, double dPhi)
{
CheckDPhiAngle(dPhi);
if ((fDPhi < 2 * UUtils::kPi) && (sPhi))
{
CheckSPhiAngle(sPhi);
}
InitializeTrigonometry();
}
inline
void UTubs::SetInnerRadius(double newRMin)
{
if (newRMin < 0) // Check radii
{
std::ostringstream message;
message << "Invalid radii." << std::endl
<< "Invalid values for radii in solid " << GetName() << std::endl
<< " newRMin = " << newRMin
<< ", fRMax = " << fRMax << std::endl
<< " Negative inner radius!";
UUtils::Exception("UTubs::SetInnerRadius()", "GeomSolids0002",
FatalError, 1, message.str().c_str());
}
fRMin = newRMin;
Initialize();
}
inline
void UTubs::SetOuterRadius(double newRMax)
{
if (newRMax <= 0) // Check radii
{
std::ostringstream message;
message << "Invalid radii." << std::endl
<< "Invalid values for radii in solid " << GetName() << std::endl
<< " fRMin = " << fRMin
<< ", newRMax = " << newRMax << std::endl
<< " Invalid outer radius!";
UUtils::Exception("UTubs::SetOuterRadius()", "GeomSolids0002",
FatalError, 1, message.str().c_str());
}
fRMax = newRMax;
Initialize();
}
inline
void UTubs::SetZHalfLength(double newDz)
{
if (newDz <= 0) // Check z-len
{
std::ostringstream message;
message << "Invalid Z half-length." << std::endl
<< "Negative Z half-length (" << newDz << "), for solid: "
<< GetName();
UUtils::Exception("UTubs::SetZHalfLength()", "GeomSolids0002",
FatalError, 1, message.str().c_str());
}
fDz = newDz;
Initialize();
}
inline
void UTubs::SetStartPhiAngle(double newSPhi, bool compute)
{
// Flag 'compute' can be used to explicitely avoid recomputation of
// trigonometry in case SetDeltaPhiAngle() is invoked afterwards
CheckSPhiAngle(newSPhi);
fPhiFullTube = false;
if (compute)
{
InitializeTrigonometry();
}
Initialize();
}
inline
void UTubs::SetDeltaPhiAngle(double newDPhi)
{
CheckPhiAngles(fSPhi, newDPhi);
Initialize();
}
// Older names for access functions
inline
double UTubs::GetRMin() const
{
return GetInnerRadius();
}
inline
double UTubs::GetRMax() const
{
return GetOuterRadius();
}
inline
double UTubs::GetDz() const
{
return GetZHalfLength() ;
}
inline
double UTubs::GetSPhi() const
{
return GetStartPhiAngle();
}
inline
double UTubs::GetDPhi() const
{
return GetDeltaPhiAngle();
}
inline
double UTubs::Capacity()
{
if (fCubicVolume != 0.)
{
;
}
else
{
fCubicVolume = fDPhi * fDz * (fRMax * fRMax - fRMin * fRMin);
}
return fCubicVolume;
}
inline
double UTubs::SurfaceArea()
{
if (fSurfaceArea != 0.)
{
;
}
else
{
fSurfaceArea = fDPhi * (fRMin + fRMax) * (2 * fDz + fRMax - fRMin);
if (!fPhiFullTube)
{
fSurfaceArea = fSurfaceArea + 4 * fDz * (fRMax - fRMin);
}
}
return fSurfaceArea;
}
@@ -0,0 +1,72 @@
//
// ********************************************************************
// * This Software is part of the AIDA Unified Solids Library package *
// * See: https://aidasoft.web.cern.ch/USolids *
// ********************************************************************
//
// $Id:$
//
// --------------------------------------------------------------------
//
// UTypes
//
// Description:
//
// Internal utility types defined for the unified solids library
//
// 19.10.12 Marek Gayer
// --------------------------------------------------------------------
#ifndef USOLIDS_Utypes
#define USOLIDS_Utypes
#include "UVector3.hh"
#include <iostream>
#include <string>
#include <vector>
class __void__;
typedef unsigned int UInt_t;
struct UBBoxStruct
{
double extent[3]; // half-lengths on the 3 axis (arrays for indexing)
double orig[3]; // center coordinates
};
/*struct UBuffer3DStruct {
const int fType; // Primitive type - predefined ones in TBuffer3DTypes.h
UInt_t fNbPnts; // Number of points describing the shape
UInt_t fNbSegs; // Number of segments describing the shape
UInt_t fNbPols; // Number of polygons describing the shape
UInt_t fPntsCapacity; // Current capacity of fPnts space
UInt_t fSegsCapacity; // Current capacity of fSegs space
UInt_t fPolsCapacity; // Current capacity of fSegs space
UInt_t fSections; // Section validity flags
double *fPnts; // x0, y0, z0, x1, y1, z1, ..... ..... ....
int *fSegs; // c0, p0, q0, c1, p1, q1, ..... ..... ....
int *fPols; // c0, n0, s0, s1, ... sn, c1, n1, s0, ... sn
};
*/
/*
struct UFacet2{
UInt_t f1;//number of vertices from verticesList forming a facet
UInt_t f2;
UInt_t f3;
UInt_t f4;
};
struct UPolyhedron2{
std::vector<UVector3> vertices;//List of Vertices for Polyhedron used in G4Vis
std::vector<UFacet2> facets;//List of Facets;
};
*/
typedef UBBoxStruct UBBox;
//typedef UBuffer3DStruct UBuffer3D;
typedef std::string UGeometryType;
#endif
@@ -0,0 +1,234 @@
//
// ********************************************************************
// * This Software is part of the AIDA Unified Solids Library package *
// * See: https://aidasoft.web.cern.ch/USolids *
// ********************************************************************
//
// $Id:$
//
// --------------------------------------------------------------------
//
// UUtils
//
// Description:
//
// Utility namespace providing common constants and mathematical utilities.
//
// 19.10.12 Marek Gayer
// --------------------------------------------------------------------
#ifndef USOLIDS_UUtils
#define USOLIDS_UUtils
#include <iostream>
#include <fstream>
#include <limits>
#include <cmath>
#include <cfloat>
#include <vector>
#include <algorithm>
#include "UVector3.hh"
class UTransform3D;
enum ExceptionSeverity
{ FatalError, FatalErrorInArguments, Error, Warning, Info };
namespace UUtils
{
// Sign
inline short Sign(short a, short b);
inline int Sign(int a, int b);
inline long Sign(long a, long b);
inline float Sign(float a, float b);
inline double Sign(double a, double b);
// Trigonometric
static const double kPi = 3.14159265358979323846;
static const double kTwoPi = 2.0 * kPi;
static const double kRadToDeg = 180.0 / kPi;
static const double kDegToRad = kPi / 180.0;
static const double kSqrt2 = 1.4142135623730950488016887242097;
static const double kInfinity = DBL_MAX;
static const double kMeshAngleDefault = (kPi / 4); // Angle for mesh `wedges' in rads
static const int kMinMeshSections = 3; // Min wedges+1 to make
static const int kMaxMeshSections = 37; // max wedges+1 to make
inline double Infinity();
inline double ASin(double);
inline double ACos(double);
inline double ATan(double);
inline double ATan2(double, double);
//Warnings and Errors Messages
void Exception(const char* originOfException,
const char* exceptionCode,
ExceptionSeverity severity,
int level,
const char* description);
// Comparing floating points
inline bool AreEqualAbs(double af, double bf, double epsilon)
{
//return true if absolute difference between af and bf is less than epsilon
return std::abs(af - bf) < epsilon;
}
inline bool AreEqualRel(double af, double bf, double relPrec)
{
//return true if relative difference between af and bf is less than relPrec
return std::abs(af - bf) <= 0.5 * relPrec * (std::abs(af) + std::abs(bf));
}
// Locate Min, Max element number in an array
long LocMin(long n, const double* a);
long LocMax(long n, const double* a);
// TransformLimits: Use the transformation to convert the local limits defined
// by min/max vectors to the master frame. Returns modified limits.
void TransformLimits(UVector3& min, UVector3& max, const UTransform3D& transformation);
double Random(double min = 0.0, double max = 1.0);
// Templates:
template<typename T>
struct CompareDesc
{
CompareDesc(T d) : fData(d) {}
template<typename Index>
bool operator()(Index i1, Index i2)
{
return *(fData + i1) > *(fData + i2);
}
T fData;
};
template<typename T>
struct CompareAsc
{
CompareAsc(T d) : fData(d) {}
template<typename Index>
bool operator()(Index i1, Index i2)
{
return *(fData + i1) < *(fData + i2);
}
T fData;
};
int SaveVectorToExternalFile(const std::vector<double>& vector, const std::string& filename);
int SaveVectorToExternalFile(const std::vector<UVector3>& vector, const std::string& filename);
int SaveVectorToExternalFile(const std::vector<int>& vector, const std::string& filename);
std::string ToString(int number);
std::string ToString(double number);
int FileSize(const std::string& filePath);
int StrPos(const std::string& haystack, const std::string& needle);
inline double GetRadiusInRing(double rmin, double rmax);
template <class T>
inline T sqr(const T& x)
{
return x * x;
}
inline bool StrEnds(std::string const& fullString, std::string const& ending)
{
if (fullString.length() >= ending.length())
{
return (0 == fullString.compare(fullString.length() - ending.length(), ending.length(), ending));
}
else
{
return false;
}
}
}
inline double UUtils::GetRadiusInRing(double rmin, double rmax)
{
// Generate radius in annular ring according to uniform area
//
if (rmin <= 0.)
{
return rmax * std::sqrt(Random());
}
if (rmin != rmax)
{
return std::sqrt(Random()
* (sqr(rmax) - sqr(rmin)) + sqr(rmin));
}
return rmin;
}
//____________________________________________________________________________
inline double UUtils::Infinity()
{
// returns an infinity as defined by the IEEE standard
return std::numeric_limits<double>::infinity();
}
//---- Sign --------------------------------------------------------------------
inline short UUtils::Sign(short a, short b)
{
return (b >= 0) ? std::abs(a) : -std::abs(a);
}
inline int UUtils::Sign(int a, int b)
{
return (b >= 0) ? std::abs(a) : -std::abs(a);
}
inline long UUtils::Sign(long a, long b)
{
return (b >= 0) ? std::abs(a) : -std::abs(a);
}
inline float UUtils::Sign(float a, float b)
{
return (b >= 0) ? std::abs(a) : -std::abs(a);
}
inline double UUtils::Sign(double a, double b)
{
return (b >= 0) ? std::abs(a) : -std::abs(a);
}
//---- Trigonometric------------------------------------------------------------
inline double UUtils::ASin(double x)
{
if (x < -1.) return -kPi / 2;
if (x > 1.) return kPi / 2;
return std::asin(x);
}
inline double UUtils::ACos(double x)
{
if (x < -1.) return kPi;
if (x > 1.) return 0;
return std::acos(x);
}
inline double UUtils::ATan2(double y, double x)
{
if (x != 0) return std::atan2(y, x);
if (y == 0) return 0;
if (y > 0) return kPi / 2;
else return -kPi / 2;
}
#endif
@@ -0,0 +1,68 @@
//
// ********************************************************************
// * This Software is part of the AIDA Unified Solids Library package *
// * See: https://aidasoft.web.cern.ch/USolids *
// ********************************************************************
//
// $Id:$
//
// --------------------------------------------------------------------
//
// UVCSGface
//
// Class description:
//
// Definition of the virtual base class UVCSGface, one side (or face)
// of a CSG-like solid. It should be possible to build a CSG entirely out of
// connecting CSG faces.
// Each face has an inside and outside surface, the former represents
// the inside of the volume, the latter, the outside.
//
// 19.09.13 Marek Gayer
// Created from original implementation in Geant4
// --------------------------------------------------------------------
#ifndef UVCSGface_hh
#define UVCSGface_hh
#include "UTypes.hh"
#include "VUSolid.hh"
class UVoxelLimits;
class UAffineTransform;
class USolidExtentList;
class UVCSGface
{
public: // with description
UVCSGface() {}
virtual ~UVCSGface() {}
virtual bool Distance(const UVector3& p, const UVector3& v,
bool outgoing, double surfTolerance,
double& distance, double& distFromSurface,
UVector3& normal, bool& allBehind) = 0;
virtual double Safety(const UVector3& p, bool outgoing) = 0;
virtual VUSolid::EnumInside Inside(const UVector3& p, double tolerance,
double* bestDistance) = 0;
virtual UVector3 Normal(const UVector3& p,
double* bestDistance) = 0;
virtual double Extent(const UVector3 axis) = 0;
/* virtual void CalculateExtent( const EAxisType axis,
const UVoxelLimits &voxelLimit,
const UAffineTransform &tranform,
USolidExtentList &extentList ) = 0;*/
virtual UVCSGface* Clone() = 0;
virtual double SurfaceArea() = 0;
virtual UVector3 GetPointOnFace() = 0;
};
#endif
@@ -0,0 +1,145 @@
//
// ********************************************************************
// * This Software is part of the AIDA Unified Solids Library package *
// * See: https://aidasoft.web.cern.ch/USolids *
// ********************************************************************
//
// $Id:$
//
// --------------------------------------------------------------------
//
// UVCSGfaceted
//
// Class description:
//
// Virtual class defining CSG-like type shape that is built entire
// of UCSGface faces.
//
// 19.09.13 Marek Gayer
// Created from original implementation in Geant4
// --------------------------------------------------------------------
#ifndef UVCSGfaceted_hh
#define UVCSGfaceted_hh
#include "VUSolid.hh"
#include "UVoxelizer.hh"
#include "UBox.hh"
#include "UReduciblePolygon.hh"
class UVCSGface;
class UVisExtent;
class UVCSGfaceted : public VUSolid
{
public: // with description
UVCSGfaceted(const std::string& name);
virtual ~UVCSGfaceted();
UVCSGfaceted(const UVCSGfaceted& source);
UVCSGfaceted& operator=(const UVCSGfaceted& source);
VUSolid::EnumInside InsideNoVoxels(const UVector3& p) const;
virtual VUSolid::EnumInside Inside(const UVector3& p) const;
virtual bool Normal(const UVector3& p, UVector3& n) const;
double DistanceToInNoVoxels(const UVector3& p,
const UVector3& v) const;
virtual double DistanceToIn(const UVector3& p,
const UVector3& v, double aPstep = UUtils::kInfinity) const;
virtual double SafetyFromOutside(const UVector3& aPoint, bool aAccurate = false) const;
double DistanceTo(const UVector3& p, const bool outgoing) const;
double DistanceToOutNoVoxels(const UVector3& p,
const UVector3& v,
UVector3& n,
bool& aConvex) const;
virtual double DistanceToOut(const UVector3& p,
const UVector3& v,
UVector3& n,
bool& aConvex,
double aPstep = UUtils::kInfinity) const;
virtual double SafetyFromInside(const UVector3& aPoint, bool aAccurate = false) const;
virtual double SafetyFromInsideNoVoxels(const UVector3& aPoint, bool aAccurate = false) const;
virtual UGeometryType GetEntityType() const;
virtual std::ostream& StreamInfo(std::ostream& os) const;
int GetCubVolStatistics() const;
double GetCubVolEpsilon() const;
void SetCubVolStatistics(int st);
void SetCubVolEpsilon(double ep);
int GetAreaStatistics() const;
double GetAreaAccuracy() const;
void SetAreaStatistics(int st);
void SetAreaAccuracy(double ep);
virtual double Capacity();
// Returns an estimation of the geometrical cubic volume of the
// solid. Caches the computed value once computed the first time.
virtual double SurfaceArea();
// Returns an estimation of the geometrical surface area of the
// solid. Caches the computed value once computed the first time.
public: // without description
protected: // without description
double SafetyFromInsideSection(int index, const UVector3& p, UBits& bits) const;
inline int GetSection(double z) const
{
int section = UVoxelizer::BinarySearch(fZs, z);
if (section < 0) section = 0;
else if (section > fMaxSection) section = fMaxSection;
return section;
}
int numFace;
UVCSGface** faces;
double fCubicVolume;
double fSurfaceArea;
std::vector<double> fZs; // z coordinates of given sections
std::vector<std::vector<int> > fCandidates; // precalculated candidates for each of the section
int fMaxSection; // maximum index number of sections of the solid (i.e. their number - 1). regular polyhedra with z = 1,2,3 section has 2 sections numbered 0 and 1, therefore the fMaxSection will be 1 (that is 2 - 1 = 1)
mutable UBox fBox; // bounding box of the polyhedra, used in some methods
double fBoxShift; // z-shift which is added during evaluation, because bounding box center does not have to be at (0,0,0)
bool fNoVoxels; // if set to true, no voxelized algorithms will be used
UVector3 GetPointOnSurfaceGeneric()const;
// Returns a random point located on the surface of the solid
// in case of generic Polycone or generic Polyhedra.
void CopyStuff(const UVCSGfaceted& source);
void DeleteStuff();
void FindCandidates(double z, std::vector <int>& candidates, bool sides = false);
void InitVoxels(UReduciblePolygon& z, double radius);
private:
int fStatistics;
double fCubVolEpsilon;
double fAreaAccuracy;
// Statistics, error accuracy for volume estimation.
};
#endif
@@ -0,0 +1,407 @@
//
// ********************************************************************
// * This Software is part of the AIDA Unified Solids Library package *
// * See: https://aidasoft.web.cern.ch/USolids *
// ********************************************************************
//
// $Id:$
//
// --------------------------------------------------------------------
//
// UVector2
//
// Class description:
//
// UVector2 is a general 2-vector class defining vectors in two
// dimension using double components.
//
// 19.09.12 Marek Gayer
// Created from original implementation in CLHEP
// --------------------------------------------------------------------
#ifndef UVECTOR2_H
#define UVECTOR2_H
#include <cmath>
#include <iostream>
#include "UVector3.hh"
// Declarations of classes and global methods
class UVector2;
std::ostream& operator << (std::ostream&, const UVector2&);
//std::istream & operator >> (std::istream &, UVector2 &);
inline double operator * (const UVector2& a, const UVector2& b);
inline UVector2 operator * (const UVector2& p, double a);
inline UVector2 operator * (double a, const UVector2& p);
UVector2 operator / (const UVector2& p, double a);
inline UVector2 operator + (const UVector2& a, const UVector2& b);
inline UVector2 operator - (const UVector2& a, const UVector2& b);
/**
* @author
* @ingroup vector
*/
class UVector2
{
public:
enum { X = 0, Y = 1, NUM_COORDINATES = 2, SIZE = NUM_COORDINATES };
// Safe indexing of the coordinates when using with matrices, arrays, etc.
inline UVector2(double x = 0.0, double y = 0.0);
// The constructor.
inline UVector2(const UVector2& p);
// The copy constructor.
explicit UVector2(const UVector3& s);
// "demotion" constructor"
// WARNING -- THIS IGNORES THE Z COMPONENT OF THE UVector3.
// SO IN GENERAL, UVector2(v)==v WILL NOT HOLD!
inline ~UVector2();
// The destructor.
// inline double x() const;
// inline double y() const;
// The components in cartesian coordinate system.
double operator()(int i) const;
inline double operator [](int i) const;
// Get components by index. 0-based.
double& operator()(int i);
inline double& operator [](int i);
// Set components by index. 0-based.
inline void setX(double x);
inline void setY(double y);
inline void set(double x, double y);
// Set the components in cartesian coordinate system.
inline double phi() const;
// The azimuth angle.
inline double mag2() const;
// The magnitude squared.
inline double mag() const;
// The magnitude.
inline double r() const;
// r in polar coordinates (r, phi): equal to mag().
inline void setPhi(double phi);
// Set phi keeping mag constant.
inline void setMag(double r);
// Set magnitude keeping phi constant.
inline void setR(double r);
// Set R keeping phi constant. Same as setMag.
inline void setPolar(double r, double phi);
// Set by polar coordinates.
inline UVector2& operator = (const UVector2& p);
// Assignment.
inline bool operator == (const UVector2& v) const;
inline bool operator != (const UVector2& v) const;
// Comparisons.
int compare(const UVector2& v) const;
bool operator > (const UVector2& v) const;
bool operator < (const UVector2& v) const;
bool operator>= (const UVector2& v) const;
bool operator<= (const UVector2& v) const;
// dictionary ordering according to y, then x component
static inline double getTolerance();
static double setTolerance(double tol);
double howNear(const UVector2& p) const;
bool isNear(const UVector2& p, double epsilon = tolerance) const;
double howParallel(const UVector2& p) const;
bool isParallel
(const UVector2& p, double epsilon = tolerance) const;
double howOrthogonal(const UVector2& p) const;
bool isOrthogonal
(const UVector2& p, double epsilon = tolerance) const;
inline UVector2& operator += (const UVector2& p);
// Addition.
inline UVector2& operator -= (const UVector2& p);
// Subtraction.
inline UVector2 operator - () const;
// Unary minus.
inline UVector2& operator *= (double a);
// Scaling with real numbers.
inline UVector2 unit() const;
// Unit vector parallel to this.
inline UVector2 orthogonal() const;
// Vector orthogonal to this.
inline double dot(const UVector2& p) const;
// Scalar product.
inline double angle(const UVector2&) const;
// The angle w.r.t. another 2-vector.
void rotate(double);
// Rotates the UVector2.
operator UVector3() const;
// Cast a UVector2 as a UVector3.
// The remaining methods are friends, thus defined at global scope:
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
friend std::ostream& operator<< (std::ostream&, const UVector2&);
// Output to a stream.
inline friend double operator * (const UVector2& a,
const UVector2& b);
// Scalar product.
inline friend UVector2 operator * (const UVector2& p, double a);
// v*c
inline friend UVector2 operator * (double a, const UVector2& p);
// c*v
friend UVector2 operator / (const UVector2& p, double a);
// v/c
inline friend UVector2 operator + (const UVector2& a,
const UVector2& b);
// v1+v2
inline friend UVector2 operator - (const UVector2& a,
const UVector2& b);
// v1-v2
enum { ZMpvToleranceTicks = 100 };
double x;
double y;
// The components.
private:
static double tolerance;
// default tolerance criterion for isNear() to return true.
}; // UVector2
static const UVector2 X_HAT2(1.0, 0.0);
static const UVector2 Y_HAT2(0.0, 1.0);
/*
inline double UVector2::x() const {
return x;
}
inline double UVector2::y() const {
return y;
}
*/
inline UVector2::UVector2(double x1, double y1)
: x(x1), y(y1) {}
inline UVector2::UVector2(const UVector3& s)
: x(s.x), y(s.y) {}
inline void UVector2::setX(double x1)
{
x = x1;
}
inline void UVector2::setY(double y1)
{
y = y1;
}
inline void UVector2::set(double x1, double y1)
{
x = x1;
y = y1;
}
double& UVector2::operator[](int i)
{
return operator()(i);
}
double UVector2::operator[](int i) const
{
return operator()(i);
}
inline UVector2::UVector2(const UVector2& p)
: x(p.x), y(p.y) {}
inline UVector2::~UVector2() {}
inline UVector2& UVector2::operator = (const UVector2& p)
{
if (this == &p) { return *this; }
x = p.x;
y = p.y;
return *this;
}
inline bool UVector2::operator == (const UVector2& v) const
{
return (v.x == x && v.y == y) ? true : false;
}
inline bool UVector2::operator != (const UVector2& v) const
{
return (v.x != x || v.y != y) ? true : false;
}
inline UVector2& UVector2::operator += (const UVector2& p)
{
x += p.x;
y += p.y;
return *this;
}
inline UVector2& UVector2::operator -= (const UVector2& p)
{
x -= p.x;
y -= p.y;
return *this;
}
inline UVector2 UVector2::operator - () const
{
return UVector2(-x, -y);
}
inline UVector2& UVector2::operator *= (double a)
{
x *= a;
y *= a;
return *this;
}
inline double UVector2::dot(const UVector2& p) const
{
return x * p.x + y * p.y;
}
inline double UVector2::mag2() const
{
return x * x + y * y;
}
inline double UVector2::mag() const
{
return std::sqrt(mag2());
}
inline double UVector2::r() const
{
return std::sqrt(mag2());
}
inline UVector2 UVector2::unit() const
{
double tot = mag2();
UVector2 p(*this);
return tot > 0.0 ? p *= (1.0 / std::sqrt(tot)) : UVector2(1, 0);
}
inline UVector2 UVector2::orthogonal() const
{
double x1 = std::fabs(x), y1 = std::fabs(y);
if (x1 < y1)
{
return UVector2(y, -x);
}
else
{
return UVector2(-y, x);
}
}
inline double UVector2::phi() const
{
return x == 0.0 && y == 0.0 ? 0.0 : std::atan2(y, x);
}
inline double UVector2::angle(const UVector2& q) const
{
double ptot2 = mag2() * q.mag2();
return ptot2 <= 0.0 ? 0.0 : std::acos(dot(q) / std::sqrt(ptot2));
}
inline void UVector2::setMag(double r1)
{
double ph = phi();
setX(r1 * std::cos(ph));
setY(r1 * std::sin(ph));
}
inline void UVector2::setR(double r1)
{
setMag(r1);
}
inline void UVector2::setPhi(double phi1)
{
double ma = mag();
setX(ma * std::cos(phi1));
setY(ma * std::sin(phi1));
}
inline void UVector2::setPolar(double r1, double phi1)
{
setX(r1 * std::cos(phi1));
setY(r1 * std::sin(phi1));
}
inline UVector2 operator + (const UVector2& a, const UVector2& b)
{
return UVector2(a.x + b.x, a.y + b.y);
}
inline UVector2 operator - (const UVector2& a, const UVector2& b)
{
return UVector2(a.x - b.x, a.y - b.y);
}
inline UVector2 operator * (const UVector2& p, double a)
{
return UVector2(a * p.x, a * p.y);
}
inline UVector2 operator * (double a, const UVector2& p)
{
return UVector2(a * p.x, a * p.y);
}
inline double operator * (const UVector2& a, const UVector2& b)
{
return a.dot(b);
}
inline double UVector2::getTolerance()
{
return tolerance;
}
#endif /* UVECTOR2_H */
@@ -0,0 +1,180 @@
//
// ********************************************************************
// * This Software is part of the AIDA Unified Solids Library package *
// * See: https://aidasoft.web.cern.ch/USolids *
// ********************************************************************
//
// $Id:$
//
// --------------------------------------------------------------------
//
// UVector2.icc
//
// Implementation of inline methods of UVector2
//
// 19.10.12 Marek Gayer
// Created from original implementation in CLHEP
// --------------------------------------------------------------------
#include <cmath>
namespace CLHEP {
inline double Hep2Vector::x() const {
return dx;
}
inline double Hep2Vector::y() const {
return dy;
}
inline Hep2Vector::Hep2Vector(double x1, double y1)
: dx(x1), dy(y1) {}
inline Hep2Vector::Hep2Vector( const Hep3Vector & s)
: dx(s.x()), dy(s.y()) {}
inline void Hep2Vector::setX(double x1) {
dx = x1;
}
inline void Hep2Vector::setY(double y1) {
dy = y1;
}
inline void Hep2Vector::set(double x1, double y1) {
dx = x1;
dy = y1;
}
double & Hep2Vector::operator[] (int i) { return operator()(i); }
double Hep2Vector::operator[] (int i) const { return operator()(i); }
inline Hep2Vector::Hep2Vector(const Hep2Vector & p)
: dx(p.x()), dy(p.y()) {}
inline Hep2Vector::~Hep2Vector() {}
inline Hep2Vector & Hep2Vector::operator = (const Hep2Vector & p) {
dx = p.x();
dy = p.y();
return *this;
}
inline bool Hep2Vector::operator == (const Hep2Vector& v) const {
return (v.x()==x() && v.y()==y()) ? true : false;
}
inline bool Hep2Vector::operator != (const Hep2Vector& v) const {
return (v.x()!=x() || v.y()!=y()) ? true : false;
}
inline Hep2Vector& Hep2Vector::operator += (const Hep2Vector & p) {
dx += p.x();
dy += p.y();
return *this;
}
inline Hep2Vector& Hep2Vector::operator -= (const Hep2Vector & p) {
dx -= p.x();
dy -= p.y();
return *this;
}
inline Hep2Vector Hep2Vector::operator - () const {
return Hep2Vector(-dx, -dy);
}
inline Hep2Vector& Hep2Vector::operator *= (double a) {
dx *= a;
dy *= a;
return *this;
}
inline double Hep2Vector::dot(const Hep2Vector & p) const {
return dx*p.x() + dy*p.y();
}
inline double Hep2Vector::mag2() const {
return dx*dx + dy*dy;
}
inline double Hep2Vector::mag() const {
return std::sqrt(mag2());
}
inline double Hep2Vector::r() const {
return std::sqrt(mag2());
}
inline Hep2Vector Hep2Vector::unit() const {
double tot = mag2();
Hep2Vector p(*this);
return tot > 0.0 ? p *= (1.0/std::sqrt(tot)) : Hep2Vector(1,0);
}
inline Hep2Vector Hep2Vector::orthogonal() const {
double x1 = std::fabs(dx), y1 = std::fabs(dy);
if (x1 < y1) {
return Hep2Vector(dy,-dx);
}else{
return Hep2Vector(-dy,dx);
}
}
inline double Hep2Vector::phi() const {
return dx == 0.0 && dy == 0.0 ? 0.0 : std::atan2(dy,dx);
}
inline double Hep2Vector::angle(const Hep2Vector & q) const {
double ptot2 = mag2()*q.mag2();
return ptot2 <= 0.0 ? 0.0 : std::acos(dot(q)/std::sqrt(ptot2));
}
inline void Hep2Vector::setMag(double r1){
double ph = phi();
setX( r1 * std::cos(ph) );
setY( r1 * std::sin(ph) );
}
inline void Hep2Vector::setR(double r1){
setMag(r1);
}
inline void Hep2Vector::setPhi(double phi1){
double ma = mag();
setX( ma * std::cos(phi1) );
setY( ma * std::sin(phi1) );
}
inline void Hep2Vector::setPolar(double r1, double phi1){
setX( r1 * std::cos(phi1) );
setY( r1 * std::sin(phi1) );
}
inline Hep2Vector operator + (const Hep2Vector & a, const Hep2Vector & b) {
return Hep2Vector(a.x() + b.x(), a.y() + b.y());
}
inline Hep2Vector operator - (const Hep2Vector & a, const Hep2Vector & b) {
return Hep2Vector(a.x() - b.x(), a.y() - b.y());
}
inline Hep2Vector operator * (const Hep2Vector & p, double a) {
return Hep2Vector(a*p.x(), a*p.y());
}
inline Hep2Vector operator * (double a, const Hep2Vector & p) {
return Hep2Vector(a*p.x(), a*p.y());
}
inline double operator * (const Hep2Vector & a, const Hep2Vector & b) {
return a.dot(b);
}
inline double Hep2Vector::getTolerance () {
return tolerance;
}
} // namespace CLHEP
@@ -0,0 +1,329 @@
//
// ********************************************************************
// * This Software is part of the AIDA Unified Solids Library package *
// * See: https://aidasoft.web.cern.ch/USolids *
// ********************************************************************
//
// $Id:$
//
// --------------------------------------------------------------------
//
// UVector3
//
// Class description:
//
// Bucket type for Vector type.
//
// 19.09.12 Marek Gayer
// Created from original implementation in CLHEP
// --------------------------------------------------------------------
#ifndef USOLIDS_UVector3
#define USOLIDS_UVector3
#include <cmath>
#include <iostream>
#include <fstream>
struct UVector3
{
public:
UVector3()
{
x = y = z = 0.0;
}
UVector3(double xval, double yval, double zval)
{
x = xval;
y = yval;
z = zval;
}
UVector3(double theta, double phi);
UVector3(const double coord[3])
{
x = coord[0];
y = coord[1];
z = coord[2];
}
inline UVector3& operator = (const UVector3& v);
inline UVector3& operator = (const double* vect);
// Assignments
inline bool operator == (const UVector3&) const;
inline bool operator != (const UVector3&) const;
// Comparisons.
inline UVector3 operator - () const;
// Unary minus.
inline UVector3& operator += (const UVector3&);
// Addition.
inline UVector3& operator -= (const UVector3&);
// Subtraction.
inline double& operator[](int index);
inline double operator[](int index) const;
inline UVector3& operator *= (double);
// Scaling with real numbers.
inline UVector3& operator /= (double);
// Dividing with real numbers.
inline double Dot(const UVector3&) const;
// Scalar product.
inline UVector3 Cross(const UVector3&) const;
// Cross product.
double Angle(const UVector3&) const;
// The angle w.r.t. another 3-vector.
UVector3 Unit() const;
// Unit vector parallel to this.
inline bool IsNull() const;
// Check if vector is null
inline void SetNull();
// Set all components to 0.
inline void Set(double xx, double yy, double zz);
// Assign values to components
inline void Set(double xx);
// Assign value to all components
double Normalize();
// Normalize to unit this vector
double Phi() const;
// The azimuth angle. returns phi from -pi to pi
double Theta() const;
// The polar angle.
inline double CosTheta() const;
// Cosine of the polar angle.
inline double Mag2() const;
// The magnitude squared (rho^2 in spherical coordinate system).
double Mag() const;
// The magnitude (rho in spherical coordinate system).
double Perp2() const;
// The transverse component (R^2 in cylindrical coordinate system).
double Perp() const;
// The transverse component (R in cylindrical coordinate system).
void RotateX(double);
// Rotates the vector around the x-axis.
void RotateY(double);
// Rotates the vector around the y-axis.
void RotateZ(double);
// Rotates the vector around the z-axis.
inline UVector3& MultiplyByComponents(const UVector3& p);
public:
double x;
double y;
double z;
};
UVector3 operator + (const UVector3&, const UVector3&);
// Addition of 3-vectors.
UVector3 operator - (const UVector3&, const UVector3&);
// Subtraction of 3-vectors.
double operator * (const UVector3&, const UVector3&);
// Scalar product of 3-vectors.
UVector3 operator * (const UVector3&, double a);
UVector3 operator / (const UVector3&, double a);
UVector3 operator * (double a, const UVector3&);
// Scaling of 3-vectors with a real number
//______________________________________________________________________________
inline UVector3& UVector3::MultiplyByComponents(const UVector3& p)
{
// Assignment of a UVector3
x *= p.x;
y *= p.y;
z *= p.z;
return *this;
}
//______________________________________________________________________________
inline UVector3& UVector3::operator = (const UVector3& p)
{
// Assignment of a UVector3
if (this == &p) { return *this; }
x = p.x;
y = p.y;
z = p.z;
return *this;
}
inline UVector3& UVector3::operator = (const double vect[3])
{
// Assignment of a C array
x = vect[0];
y = vect[1];
z = vect[2];
return *this;
}
inline bool UVector3::operator == (const UVector3& v) const
{
return (v.x == x && v.y == y && v.z == z) ? true : false;
}
inline bool UVector3::operator != (const UVector3& v) const
{
return (v.x != x || v.y != y || v.z != z) ? true : false;
}
inline UVector3& UVector3::operator += (const UVector3& p)
{
x += p.x;
y += p.y;
z += p.z;
return *this;
}
inline UVector3& UVector3::operator -= (const UVector3& p)
{
x -= p.x;
y -= p.y;
z -= p.z;
return *this;
}
inline UVector3 UVector3::operator - () const
{
return UVector3(-x, -y, -z);
}
inline UVector3& UVector3::operator *= (double a)
{
x *= a;
y *= a;
z *= a;
return *this;
}
inline UVector3& UVector3::operator /= (double a)
{
a = 1. / a;
x *= a;
y *= a;
z *= a;
return *this;
}
inline bool UVector3::IsNull() const
{
return ((std::abs(x) + std::abs(y) + std::abs(z)) == 0.0) ? true : false;
}
/*
inline void UVector3::SetNull() {
x = y = z = 0.0;
}
*/
inline void UVector3::Set(double xx, double yy, double zz)
{
x = xx;
y = yy;
z = zz;
}
inline void UVector3::Set(double xx)
{
x = y = z = xx;
}
inline double UVector3::Dot(const UVector3& p) const
{
return x * p.x + y * p.y + z * p.z;
}
inline UVector3 UVector3::Cross(const UVector3& p) const
{
return UVector3(y * p.z - p.y * z, z * p.x - p.z * x, x * p.y - p.x * y);
}
inline double UVector3::Mag2() const
{
return x * x + y * y + z * z;
}
inline double UVector3::Perp2() const
{
return x * x + y * y;
}
inline double UVector3::CosTheta() const
{
double ptot = Mag();
return ptot == 0.0 ? 1.0 : z / ptot;
}
inline double& UVector3::operator[](int index)
{
switch (index)
{
case 0:
return x;
case 1:
return y;
case 2:
return z;
default:
return x;
}
}
inline double UVector3::operator[](int index) const
{
// return operator()(index);
// TODO: test performance of both versions on Linux
// => first version is slightly faster
if (true)
{
double vec[3] = {x, y, z};
return vec[index];
}
switch (index)
{
case 0:
return x;
case 1:
return y;
case 2:
return z;
default:
return 0;
}
}
inline std::ostream& operator<< (std::ostream& os, const UVector3& v)
{
return os << "(" << v.x << "," << v.y << "," << v.z << ")";
}
#endif
@@ -0,0 +1,348 @@
//
// ********************************************************************
// * This Software is part of the AIDA Unified Solids Library package *
// * See: https://aidasoft.web.cern.ch/USolids *
// ********************************************************************
//
// $Id:$
//
// --------------------------------------------------------------------
//
// UVoxelizer
//
// Class description:
//
// Voxelizer used for UPolycone, UPolyhedra, UTessellatedSolid
// and UMultiUnion.
//
// 19.10.12 Marek Gayer
// Created from original implementation in ROOT
// --------------------------------------------------------------------
#ifndef UVoxelizer_HH
#define UVoxelizer_HH
#include <vector>
#include <string>
#include <map>
#include "UBits.hh"
#include "UBox.hh"
#include "VUFacet.hh"
#include "VUSolid.hh"
#include "UUtils.hh"
#include "UTransform3D.hh"
struct UVoxelBox
{
UVector3 hlen; // half length of the box
UVector3 pos; // position of the box
};
struct UVoxelInfo
{
int count;
int previous;
int next;
};
class UVoxelizer
{
// friend class UVoxelCandidatesIterator;
public:
template <typename T>
// Binary search
static inline int BinarySearch(const std::vector<T>& vec, T value)
{
// Binary search in an array of doubles. If match is found, function returns
// position of element. If no match found, function gives nearest
// element smaller than value.
typename std::vector<T>::const_iterator begin = vec.begin(), end = vec.end();
int res = std::upper_bound(begin, end, value) - begin - 1;
return res;
}
// int BinarySearch(int n, const T *array, T value);
#ifdef USOLIDSONLY
void Voxelize(std::vector<VUSolid*>& solids, std::vector<UTransform3D*>& transforms);
#endif // USOLIDSONLY
void Voxelize(std::vector<VUFacet*>& facets);
void DisplayVoxelLimits();
void DisplayBoundaries();
void DisplayListNodes();
UVoxelizer();
~UVoxelizer();
// Method displaying the nodes located in a voxel characterized by its three indexes:
void GetCandidatesVoxel(std::vector<int>& voxels);
// Method returning in a vector container the nodes located in a voxel characterized by its three indexes:
int GetCandidatesVoxelArray(const UVector3& point, std::vector<int>& list, UBits* crossed = NULL) const;
int GetCandidatesVoxelArray(const std::vector<int>& voxels, const UBits bitmasks[], std::vector<int>& list, UBits* crossed = NULL) const;
int GetCandidatesVoxelArray(const std::vector<int>& voxels, std::vector<int>& list, UBits* crossed = NULL)const;
// Method returning the pointer to the array containing the characteristics of each box:
inline const std::vector<UVoxelBox>& GetBoxes() const
{
return fBoxes;
}
inline const std::vector<double>& GetBoundary(int index) const
{
return fBoundaries[index];
}
bool UpdateCurrentVoxel(const UVector3& point, const UVector3& direction, std::vector<int>& curVoxel) const;
inline void GetVoxel(std::vector<int>& curVoxel, const UVector3& point) const
{
for (int i = 0; i <= 2; ++i)
{
const std::vector<double>& boundary = GetBoundary(i);
int n = BinarySearch(boundary, point[i]);
if (n == -1) n = 0;
else if (n == (int) boundary.size() - 1) n--;
curVoxel[i] = n;
}
}
inline int GetBitsPerSlice() const
{
return fNPerSlice * 8 * sizeof(unsigned int);
}
bool Contains(const UVector3& point) const;
double DistanceToNext(const UVector3& point, const UVector3& direction, std::vector<int>& curVoxel) const;
double DistanceToFirst(const UVector3& point, const UVector3& direction) const;
double SafetyToBoundingBox(const UVector3& point) const;
inline int GetVoxelsIndex(int x, int y, int z) const
{
if (x < 0 || y < 0 || z < 0) return -1;
int maxX = fBoundaries[0].size();
int maxY = fBoundaries[1].size();
int index = x + y * maxX + z * maxX * maxY;
return index;
}
inline int GetVoxelsIndex(const std::vector<int>& voxels) const
{
return GetVoxelsIndex(voxels[0], voxels[1], voxels[2]);
}
inline bool GetPointVoxel(const UVector3& p, std::vector<int>& voxels) const
{
for (int i = 0; i <= 2; ++i)
if (p[i] < *fBoundaries[i].begin() || p[i] > *fBoundaries[i].end()) return false;
for (int i = 0; i <= 2; ++i)
voxels[i] = BinarySearch(fBoundaries[i], p[i]);
return true;
}
inline int GetPointIndex(const UVector3& p) const
{
int maxX = fBoundaries[0].size();
int maxY = fBoundaries[1].size();
int x = BinarySearch(fBoundaries[0], p[0]);
int y = BinarySearch(fBoundaries[1], p[1]);
int z = BinarySearch(fBoundaries[2], p[2]);
int index = x + y * maxX + z * maxX * maxY;
return index;
}
inline const UBits& Empty() const
{
return fEmpty;
}
inline bool IsEmpty(int index) const
{
return fEmpty[index];
}
void SetMaxVoxels(int max);
void SetMaxVoxels(const UVector3& reductionRatio);
inline int GetMaxVoxels(UVector3& ratioOfReduction)
{
ratioOfReduction = fReductionRatio;
return fMaxVoxels;
}
int AllocatedMemory();
inline long long GetCountOfVoxels() const
{
return fCountOfVoxels;
}
inline long long CountVoxels(std::vector<double> boundaries[]) const
{
long long sx = boundaries[0].size() - 1;
long long sy = boundaries[1].size() - 1;
long long sz = boundaries[2].size() - 1;
return sx * sy * sz;
}
/*
inline int GetCandidates(std::vector<int> &curVoxel, std::vector<int> *&candidates, std::vector<int> &space) const
{
int voxelsIndex;
int emptys = fEmpty.GetNbits();
if (!emptys || ((voxelsIndex = GetVoxelsIndex(curVoxel)) >= 0) && !fEmpty[voxelsIndex])
{
if (emptys)
{
candidates = &fCandidates[voxelsIndex];
}
else
{
GetCandidatesVoxelArray(curVoxel, space, NULL);
candidates = &space;
}
return candidates->size();
}
return 0;
}
*/
inline const std::vector<int>& GetCandidates(std::vector<int>& curVoxel) const
{
int voxelsIndex = GetVoxelsIndex(curVoxel);
if (voxelsIndex >= 0 && !fEmpty[voxelsIndex])
{
return fCandidates[voxelsIndex];
}
return fNoCandidates;
}
inline int GetVoxelBoxesSize() const
{
return fVoxelBoxes.size();
}
inline const UVoxelBox& GetVoxelBox(int i) const
{
return fVoxelBoxes[i];
}
inline const std::vector<int>& GetVoxelBoxCandidates(int i) const
{
return fVoxelBoxesCandidates[i];
}
inline int GetTotalCandidates() const
{
return fTotalCandidates;
}
static double MinDistanceToBox(const UVector3& aPoint, const UVector3& f);
static void SetDefaultVoxelsCount(int count);
static int GetDefaultVoxelsCount();
void BuildBoundingBox();
void BuildBoundingBox(UVector3& amin, UVector3& amax, double tolerance = 0);
private:
static int fDefaultVoxelsCount;
std::vector<UVoxelBox> fVoxelBoxes;
std::vector<std::vector<int> > fVoxelBoxesCandidates;
mutable std::map<int, std::vector<int> > fCandidates;
const std::vector<int> fNoCandidates;
long long fCountOfVoxels;
void BuildEmpty();
std::string GetCandidatesAsString(const UBits& bits);
void CreateSortedBoundary(std::vector<double>& boundaryRaw, int axis);
void BuildBoundaries();
void BuildReduceVoxels(std::vector<double> fBoundaries[], UVector3 reductionRatio);
void BuildReduceVoxels2(std::vector<double> fBoundaries[], UVector3 reductionRatio);
#ifdef USOLIDSONLY
void BuildVoxelLimits(std::vector<VUSolid*>& solids, std::vector<UTransform3D*>& transforms);
#endif // USOLIDSONLY
void BuildVoxelLimits(std::vector<VUFacet*>& facets);
void DisplayBoundaries(std::vector<double>& fBoundaries);
void BuildBitmasks(std::vector<double> fBoundaries[], UBits bitmasks[]);
void SetReductionRatio(int maxVoxels, UVector3& reductionRatio);
void CreateMiniVoxels(std::vector<double> fBoundaries[], UBits bitmasks[]);
int fNPerSlice;
std::vector<UVoxelBox> fBoxes; // Array of box limits on the 3 cartesian axis
std::vector<double> fBoundaries[3]; // Sorted and if need skimmed fBoundaries along X,Y,Z axis
std::vector<int> fCandidatesCounts[3];
int fTotalCandidates;
UBits fBitmasks[3];
UVector3 fBoundingBoxCenter;
UBox fBoundingBox;
UVector3 fBoundingBoxSize;
UVector3 fReductionRatio;
int fMaxVoxels;
double fTolerance;
UBits fEmpty;
};
#ifdef USOLIDSONLY
/*
class UVoxelCandidatesIterator
{
private:
unsigned int mask;
int curInt, curBit, carNodes, n, sliceX, sliceY, sliceZ;
unsigned int *maskX, *maskY, *maskZ;
unsigned int *maskXLeft, *maskYLeft, *maskZLeft;
bool nextAvailable;
public:
UVoxelCandidatesIterator(const UVoxelizer &f, const UVector3 &point);
int Next();
};
*/
#endif // USOLIDSONLY
#endif
@@ -0,0 +1,92 @@
//
// ********************************************************************
// * License and Disclaimer *
// * *
// * The Geant4 software is copyright of the Copyright Holders of *
// * the Geant4 Collaboration. It is provided under the terms and *
// * conditions of the Geant4 Software License, included in the file *
// * LICENSE and available at http://cern.ch/geant4/license . These *
// * include a list of copyright holders. *
// * *
// * Neither the authors of this software system, nor their employing *
// * institutes,nor the agencies providing financial support for this *
// * work make any representation or warranty, express or implied, *
// * regarding this software system or assume any liability for its *
// * use. Please see the license in the file LICENSE and URL above *
// * for the full disclaimer and the limitation of liability. *
// * *
// * This code implementation is the result of the scientific and *
// * technical work of the GEANT4 collaboration and of QinetiQ Ltd, *
// * subject to DEFCON 705 IPR conditions. *
// * By using, copying, modifying or distributing the software (or *
// * any work based on the software) you agree to acknowledge its *
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
// $Id: UFacet.hh,v 1.8 2010-09-23 10:27:25 gcosmo Exp $
// GEANT4 tag $Name: not supported by cvs2svn $
//
// Author: Marek Gayer, started from original implementation by P R Truscott, 2004
//
////
// Class description:
//
// Base class defining the facets which are components of a
// G4TessellatedSolid shape.
//
///////////////////////////////////////////////////////////////////////////////
#ifndef UFacet_hh
#define UFacet_hh
#include <iostream>
#include <vector>
#include "UVector3.hh"
#include "UTypes.hh"
enum UFacetVertexType {UABSOLUTE, URELATIVE};
class UTessellatedSolid;
class VUFacet
{
public:
virtual ~VUFacet () {};
virtual int GetNumberOfVertices () const = 0;
virtual UVector3 GetVertex (int i) const = 0;
virtual void SetVertex (int i, const UVector3 &val) = 0;
virtual UGeometryType GetEntityType () const = 0;
virtual UVector3 GetSurfaceNormal () const = 0;
virtual bool IsDefined () const = 0;
virtual UVector3 GetCircumcentre () const = 0;
virtual double GetRadius () const = 0;
virtual VUFacet *GetClone () = 0;
virtual double Distance (const UVector3&, const double) = 0;
virtual double Distance (const UVector3&, const double, const bool) = 0;
virtual double Extent (const UVector3) = 0;
virtual bool Intersect (const UVector3&, const UVector3 &, const bool , double &, double &, UVector3 &) = 0;
virtual double GetArea() = 0;
virtual UVector3 GetPointOnFace() const = 0;
bool operator== (const VUFacet &right) const;
void ApplyTranslation (const UVector3 v);
std::ostream &StreamInfo(std::ostream &os) const;
bool IsInside(const UVector3 &p) const;
virtual int AllocatedMemory() = 0;
virtual void SetVertexIndex (const int i, const int j) = 0;
virtual int GetVertexIndex (const int i) const = 0;
virtual void SetVertices(std::vector<UVector3> *vertices) = 0;
protected:
static const double dirTolerance;
static const double kCarTolerance;
};
#endif
@@ -0,0 +1,156 @@
#ifndef USOLIDS_VUSolid
#define USOLIDS_VUSolid
////////////////////////////////////////////////////////////////////////////////
// "Universal" Solid Interface
// Authors: J. Apostolakis, G. Cosmo, M. Gayer, A. Gheata, A. Munnich, T. Nikitina (CERN)
//
// Created: 25 May 2011
//
////////////////////////////////////////////////////////////////////////////////
#include "UTypes.hh"
#include "UVector3.hh"
#include "UUtils.hh"
#define USOLIDS
#define USOLIDSONLY
class VUSolid
{
public:
enum EnumInside { eInside=0, eSurface=1, eOutside=2 };
// Use eInside < eSurface < eOutside: allows "max(,)" to combine Inside of surfaces
// Potentially replace eSurface with eInSurface, eOutSurface
enum EAxisType { eXaxis=0, eYaxis=1, eZaxis=2};
protected:
static double fgTolerance;
static double frTolerance;
static double faTolerance;
// =>10 degrees/wedge for complete tube
public:
VUSolid();
VUSolid(const std::string &name);
virtual ~VUSolid();
// Accessors and modifiers for Tolerance
inline double GetCarTolerance() const;
inline double GetRadTolerance() const;
inline double GetAngTolerance() const;
void SetCarTolerance(double eps);
void SetRadTolerance(double eps);
void SetAngTolerance(double eps);
// Navigation methods
virtual EnumInside Inside (const UVector3 &aPoint) const = 0;
//
// Evaluate if point is inside, outside or on the surface within the tolerance
virtual double SafetyFromInside ( const UVector3 &aPoint,
bool aAccurate=false) const = 0;
virtual double SafetyFromOutside( const UVector3 &aPoint,
bool aAccurate=false) const = 0;
//
// Estimates isotropic distance to the surface of the solid. This must
// be either accurate or an underestimate.
// Two modes: - default/fast mode, sacrificing accuracy for speed
// - "precise" mode, requests accurate value if available.
// For both modes, if at a large distance from solid ( > ? )
// it is expected that a simplified calculation will be made if available.
virtual double DistanceToIn( const UVector3 &aPoint,
const UVector3 &aDirection,
double aPstep = UUtils::kInfinity) const = 0;
virtual double DistanceToOut( const UVector3 &aPoint,
const UVector3 &aDirection,
UVector3 &aNormalVector,
bool &aConvex,
double aPstep = UUtils::kInfinity) const = 0;
//
// o return the exact distance (double) from a surface, given a direction
// o compute the normal on the surface, returned as argument, calculated
// within the method to verify if it is close to the surface or not
// o for DistanceToOut(), normal-vector and convexity flag could be optional (to decide).
// If normal cannot be computed (or shape is not convex), set 'convex' to 'false'.
// o for DistanceToIn(), the normal-vector could be added as optional
virtual bool Normal( const UVector3& aPoint, UVector3 &aNormal ) const = 0;
// Computes the normal on a surface and returns it as a unit vector
// In case a point is further than tolerance_normal from a surface, set validNormal=false
// Must return a valid vector. (even if the point is not on the surface.)
//
// On an edge or corner, provide an average normal of all facets within tolerance
// Decision: provide or not the Boolean 'validNormal' argument for returning validity
virtual void ExtentAxis(EAxisType aAxis, double &aMin, double &aMax) const;
virtual void Extent( UVector3 &aMin, UVector3 &aMax ) const = 0;
// Return the minimum and maximum extent along all Cartesian axes
// For both the Extent methods
// o Expect mostly to use a GetBBox()/CalculateBBox() method internally to compute the extent
// o Decision: whether to store the computed BBox (containing or representing 6 double values),
// and whether to compute it at construction time.
// Methods are *not* const to allow caching of the Bounding Box
virtual UGeometryType GetEntityType() const = 0;
// Provide identification of the class of an object.
// (required for persistency and STEP interface)
const std::string &GetName() const {return fName;}
void SetName(const std::string &aName) {fName = aName;}
// Auxiliary methods
virtual double Capacity() = 0 ; // like CubicVolume()
virtual double SurfaceArea() = 0 ;
// Expect the solids to cache the values of Capacity and Surface Area
// Sampling
virtual void SamplePointsInside(int /*aNpoints*/, UVector3 * /*aArray*/) const {}
virtual void SamplePointsOnSurface(int /*aNpoints*/, UVector3 * /*aArray*/) const {}
virtual void SamplePointsOnEdge(int /*aNpoints*/, UVector3 * /*aArray*/) const {}
// o generates points on the edges of a solid - primarily for testing purposes
// o for solids composed only of curved surfaces(like full spheres or toruses) or
// where an implementation is not available, it defaults to PointOnSurface.
// Visualisation
virtual void GetParametersList(int aNumber,double *aArray) const =0;
virtual VUSolid* Clone() const =0;
// o provide a new object which is a clone of the solid
// Visualization
static double Tolerance() {return fgTolerance;}
inline virtual std::ostream& StreamInfo( std::ostream& os ) const = 0;
virtual UVector3 GetPointOnSurface() const = 0;
double EstimateCubicVolume(int nStat, double epsilon) const;
// Calculate cubic volume based on Inside() method.
// Accuracy is limited by the second argument or the statistics
// expressed by the first argument.
double EstimateSurfaceArea(int nStat, double ell) const;
// Calculate surface area only based on Inside() method.
// Accuracy is limited by the second argument or the statistics
// expressed by the first argument.
protected:
virtual void ComputeBBox(UBBox *aBox, bool aStore = false) = 0;
// o Compute the bounding box for the solid. Called automatically and stored ?
// o Can throw an exception if the solid is invalid
private:
std::string fName; // Name of the solid
//UBBox *fBBox; // Bounding box
};
inline double VUSolid::GetCarTolerance() const { return fgTolerance;}
inline double VUSolid::GetRadTolerance() const { return frTolerance;}
inline double VUSolid::GetAngTolerance() const { return faTolerance;}
#endif
@@ -0,0 +1,112 @@
#------------------------------------------------------------------------------
# sources.cmake
# Module : G4geomUSolids
# Package: Geant4.src.G4geometry.G4geomUSolids
#
# Sources description for a library.
# Lists the sources and headers of the code explicitely.
# Lists include paths needed.
# Lists the internal granular and global dependencies of the library.
# Source specific properties should be added at the end.
#
# Generated on : 24/9/2010
#
# $Id: sources.cmake 66356 2012-12-18 09:02:32Z gcosmo $
#
#------------------------------------------------------------------------------
# List external includes needed.
include_directories(${CLHEP_INCLUDE_DIRS})
# List internal includes needed.
include_directories(${CMAKE_SOURCE_DIR}/source/geometry/management/include)
include_directories(${CMAKE_SOURCE_DIR}/source/geometry/volumes/include)
include_directories(${CMAKE_SOURCE_DIR}/source/global/HEPGeometry/include)
include_directories(${CMAKE_SOURCE_DIR}/source/global/management/include)
include_directories(${CMAKE_SOURCE_DIR}/source/graphics_reps/include)
include_directories(${CMAKE_SOURCE_DIR}/source/intercoms/include)
#
# Define the Geant4 Module.
#
include(Geant4MacroDefineModule)
GEANT4_DEFINE_MODULE(NAME G4geomUSolids
HEADERS
G4USolid.hh
UBits.hh
UBox.hh
UCons.hh
UCons.icc
UEnclosingCylinder.hh
UGenericPolycone.hh
UGenericPolycone.icc
UIntersectingCone.hh
UOrb.hh
UPolycone.hh
UPolycone.icc
UPolyconeSide.hh
UPolyhedra.hh
UPolyhedra.icc
UPolyhedraSide.hh
UPolyPhiFace.hh
UPolyPhiFace.icc
UReduciblePolygon.hh
USphere.hh
UTet.hh
UTransform3D.hh
UTrd.hh
UTrd.icc
UTubs.hh
UTubs.icc
UTypes.hh
UUtils.hh
UVCSGface.hh
UVCSGfaceted.hh
UVector2.hh
UVector2.icc
UVector3.hh
UVoxelizer.hh
VUFacet.hh
VUSolid.hh
SOURCES
G4USolid.cc
UBits.cc
UBox.cc
UCons.cc
UEnclosingCylinder.cc
UGenericPolycone.cc
UIntersectingCone.cc
UOrb.cc
UPolycone.cc
UPolyconeSide.cc
UPolyhedra.cc
UPolyhedraSide.cc
UPolyPhiFace.cc
UReduciblePolygon.cc
USphere.cc
UTet.cc
UTransform3D.cc
UTrd.cc
UTubs.cc
UUtils.cc
UVCSGfaceted.cc
UVector2.cc
UVector3.cc
UVoxelizer.cc
VUFacet.cc
VUSolid.cc
GRANULAR_DEPENDENCIES
G4geometrymng
G4globman
G4graphics_reps
G4intercoms
G4volumes
GLOBAL_DEPENDENCIES
G4global
G4graphics_reps
G4intercoms
LINK_LIBRARIES
)
# List any source specific properties here
@@ -0,0 +1,557 @@
//
// ********************************************************************
// * License and Disclaimer *
// * *
// * The Geant4 software is copyright of the Copyright Holders of *
// * the Geant4 Collaboration. It is provided under the terms and *
// * conditions of the Geant4 Software License, included in the file *
// * LICENSE and available at http://cern.ch/geant4/license . These *
// * include a list of copyright holders. *
// * *
// * Neither the authors of this software system, nor their employing *
// * institutes,nor the agencies providing financial support for this *
// * work make any representation or warranty, express or implied, *
// * regarding this software system or assume any liability for its *
// * use. Please see the license in the file LICENSE and URL above *
// * for the full disclaimer and the limitation of liability. *
// * *
// * This code implementation is the result of the scientific and *
// * technical work of the GEANT4 collaboration. *
// * By using, copying, modifying or distributing the software (or *
// * any work based on the software) you agree to acknowledge its *
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
//
// $Id:$
// GEANT4 tag $Name:$
//
//
// G4USolid implementation
//
// --------------------------------------------------------------------
#include "G4USolid.hh"
#include "G4AffineTransform.hh"
#include "G4VoxelLimits.hh"
#include "G4VGraphicsScene.hh"
#include "G4Polyhedron.hh"
#include "G4PolyhedronArbitrary.hh"
#include "G4VisExtent.hh"
#include "G4PhysicalConstants.hh"
G4USolid::G4USolid(const G4String& name, VUSolid* s) :
G4VSolid(name), fShape(s), fPolyhedron(0)
{
}
G4USolid::G4USolid(__void__& a)
: G4VSolid(a), fShape(0), fPolyhedron(0)
{
}
G4USolid::~G4USolid()
{
}
G4bool G4USolid::operator==(const G4USolid& s) const
{
return (this == &s) ? true : false;
}
EInside G4USolid::Inside(const G4ThreeVector& p) const
{
UVector3 pt;
VUSolid::EnumInside in_temp;
EInside in = kOutside;
pt.x = p.x();
pt.y = p.y();
pt.z = p.z(); // better assign at construction
in_temp = fShape->Inside(pt);
if (in_temp == VUSolid::eSurface)return kSurface;
if (in_temp == VUSolid::eInside)return kInside;
return in;
}
G4ThreeVector G4USolid::SurfaceNormal(const G4ThreeVector& pt) const
{
UVector3 p;
p.x = pt.x();
p.y = pt.y();
p.z = pt.z();
UVector3 n;
fShape->Normal(p, n);
return G4ThreeVector(n.x, n.y, n.z);
}
G4double G4USolid::DistanceToIn(const G4ThreeVector& pt,
const G4ThreeVector& d)const
{
UVector3 p;
p.x = pt.x();
p.y = pt.y();
p.z = pt.z(); // better assign at construction
UVector3 v;
v.x = d.x();
v.y = d.y();
v.z = d.z(); // better assign at construction
G4double dist = fShape->DistanceToIn(p, v);
if (dist > kInfinity) dist = kInfinity;
return dist;
}
G4double G4USolid::DistanceToIn(const G4ThreeVector& pt) const
{
UVector3 p;
p.x = pt.x();
p.y = pt.y();
p.z = pt.z(); // better assign at construction
G4double dist = fShape->SafetyFromOutside(p); // true?
if (dist > kInfinity) dist = kInfinity;
return dist;
}
G4double G4USolid::DistanceToOut(const G4ThreeVector& pt,
const G4ThreeVector& d,
const G4bool calcNorm,
G4bool* validNorm,
G4ThreeVector* norm) const
{
UVector3 p;
p.x = pt.x();
p.y = pt.y();
p.z = pt.z(); // better assign at construction
UVector3 v;
v.x = d.x();
v.y = d.y();
v.z = d.z(); // better assign at construction
UVector3 n;
bool valid;
G4double dist = fShape->DistanceToOut(p, v, n,valid); // should use local variable
if(calcNorm)
{
if(valid){ *validNorm = true;}
else {* validNorm =false;}
if(*validNorm)
{ norm->setX(n.x);
norm->setY(n.y);
norm->setZ(n.z);
} // *norm = n, but only after calcNorm check
}
if (dist > kInfinity) dist = kInfinity;
return dist;
}
G4double G4USolid::DistanceToOut(const G4ThreeVector& pt) const
{
UVector3 p;
p.x = pt.x();
p.y = pt.y();
p.z = pt.z(); // better assign at construction
return fShape->SafetyFromInside(p); // true?
}
G4double G4USolid::GetCubicVolume()
{
return fShape->Capacity();
}
G4double G4USolid::GetSurfaceArea()
{
return fShape->SurfaceArea();
}
G4ThreeVector G4USolid::GetPointOnSurface() const
{
UVector3 p;
p = fShape->GetPointOnSurface();
return G4ThreeVector(p.x, p.y, p.z);
}
G4bool G4USolid::CalculateExtent(const EAxis pAxis,
const G4VoxelLimits& pVoxelLimit,
const G4AffineTransform& pTransform,
G4double& pMin, G4double& pMax) const
{
if (!pTransform.IsRotated())
{
VUSolid::EAxisType eAxis = VUSolid::eXaxis;
G4double offset = pTransform.NetTranslation().x();
if (pAxis == kYAxis)
{
eAxis = VUSolid::eYaxis;
offset = pTransform.NetTranslation().y();
}
if (pAxis == kZAxis)
{
eAxis = VUSolid::eZaxis;
offset = pTransform.NetTranslation().z();
}
fShape->ExtentAxis(eAxis, pMin, pMax);
pMin += offset;
pMax += offset;
if (pVoxelLimit.IsLimited())
{
switch (pAxis)
{
case kXAxis:
if ((pMin > pVoxelLimit.GetMaxXExtent() + kCarTolerance) ||
(pMax < pVoxelLimit.GetMinXExtent() - kCarTolerance))
{
return false;
}
else
{
pMin = std::max(pMin, pVoxelLimit.GetMinXExtent());
pMax = std::min(pMax, pVoxelLimit.GetMaxXExtent());
}
break;
case kYAxis:
if ((pMin > pVoxelLimit.GetMaxYExtent() + kCarTolerance) ||
(pMax < pVoxelLimit.GetMinYExtent() - kCarTolerance))
{
return false;
}
else
{
pMin = std::max(pMin, pVoxelLimit.GetMinYExtent());
pMax = std::min(pMax, pVoxelLimit.GetMaxYExtent());
}
break;
case kZAxis:
if ((pMin > pVoxelLimit.GetMaxZExtent() + kCarTolerance) ||
(pMax < pVoxelLimit.GetMinZExtent() - kCarTolerance))
{
return false;
}
else
{
pMin = std::max(pMin, pVoxelLimit.GetMinZExtent());
pMax = std::min(pMax, pVoxelLimit.GetMaxZExtent());
}
break;
default:
break;
}
pMin -= kCarTolerance ;
pMax += kCarTolerance ;
}
return true;
}
else // General rotated case - create and clip mesh to boundaries
{
// Rotate BoundingBox and Calculate Extent as for BREPS
G4bool existsAfterClip = false ;
G4ThreeVectorList* vertices ;
pMin = +kInfinity ;
pMax = -kInfinity ;
// Calculate rotated vertex coordinates
vertices = CreateRotatedVertices(pTransform) ;
ClipCrossSection(vertices, 0, pVoxelLimit, pAxis, pMin, pMax) ;
ClipCrossSection(vertices, 4, pVoxelLimit, pAxis, pMin, pMax) ;
ClipBetweenSections(vertices, 0, pVoxelLimit, pAxis, pMin, pMax) ;
if (pVoxelLimit.IsLimited(pAxis) == false)
{
if ((pMin != kInfinity) || (pMax != -kInfinity))
{
existsAfterClip = true ;
// Add 2*tolerance to avoid precision troubles
pMin -= kCarTolerance;
pMax += kCarTolerance;
}
}
else
{
G4ThreeVector clipCentre(
(pVoxelLimit.GetMinXExtent() + pVoxelLimit.GetMaxXExtent()) * 0.5,
(pVoxelLimit.GetMinYExtent() + pVoxelLimit.GetMaxYExtent()) * 0.5,
(pVoxelLimit.GetMinZExtent() + pVoxelLimit.GetMaxZExtent()) * 0.5);
if ((pMin != kInfinity) || (pMax != -kInfinity))
{
existsAfterClip = true ;
// Check to see if endpoints are in the solid
clipCentre(pAxis) = pVoxelLimit.GetMinExtent(pAxis);
if (Inside(pTransform.Inverse().TransformPoint(clipCentre)) != kOutside)
{
pMin = pVoxelLimit.GetMinExtent(pAxis);
}
else
{
pMin -= kCarTolerance;
}
clipCentre(pAxis) = pVoxelLimit.GetMaxExtent(pAxis);
if (Inside(pTransform.Inverse().TransformPoint(clipCentre)) != kOutside)
{
pMax = pVoxelLimit.GetMaxExtent(pAxis);
}
else
{
pMax += kCarTolerance;
}
}
// Check for case where completely enveloping clipping volume
// If point inside then we are confident that the solid completely
// envelopes the clipping volume. Hence set min/max extents according
// to clipping volume extents along the specified axis.
else if (Inside(pTransform.Inverse().TransformPoint(clipCentre))
!= kOutside)
{
existsAfterClip = true ;
pMin = pVoxelLimit.GetMinExtent(pAxis) ;
pMax = pVoxelLimit.GetMaxExtent(pAxis) ;
}
}
delete vertices;
return existsAfterClip;
}
}
void G4USolid::DescribeYourselfTo(G4VGraphicsScene& scene) const
{
scene.AddSolid(*this);
}
G4GeometryType G4USolid::GetEntityType() const
{
G4String string = fShape->GetEntityType();
return "G4" + string;
}
std::ostream& G4USolid::StreamInfo(std::ostream& os) const
{
os << "-----------------------------------------------------------\n"
<< " *** Dump for solid - " << fShape->GetName() << " ***\n";
// << " ===================================================\n"
// << " Solid type: " << fShape->GetEntityType() << "\n"
// << "-----------------------------------------------------------\n";
return os;//fShape->StreamInfo(os);
}
G4USolid::G4USolid(const G4USolid& rhs)
: G4VSolid(rhs), fShape(rhs.fShape), fPolyhedron(rhs.fPolyhedron)
{
}
G4USolid& G4USolid::operator=(const G4USolid& rhs)
{
// Check assignment to self
//
if (this == &rhs)
{
return *this;
}
// Copy base class data
//
G4VSolid::operator=(rhs);
// Copy data
//
fShape = rhs.fShape;
return *this;
}
G4VSolid* G4USolid::Clone() const
{
return new G4USolid(fShape->GetName(), fShape->Clone());
}
G4ThreeVectorList*
G4USolid::CreateRotatedVertices(const G4AffineTransform& pTransform) const
{
G4double xMin, xMax, yMin, yMax, zMin, zMax;
fShape->ExtentAxis(VUSolid::eXaxis, xMin, xMax);
fShape->ExtentAxis(VUSolid::eYaxis, yMin, yMax);
fShape->ExtentAxis(VUSolid::eZaxis, zMin, zMax);
G4ThreeVectorList* vertices;
vertices = new G4ThreeVectorList();
if (vertices)
{
vertices->reserve(8);
G4ThreeVector vertex0(xMin, yMin, zMin);
G4ThreeVector vertex1(xMax, yMin, zMin);
G4ThreeVector vertex2(xMax, yMax, zMin);
G4ThreeVector vertex3(xMin, yMax, zMin);
G4ThreeVector vertex4(xMin, yMin, zMax);
G4ThreeVector vertex5(xMax, yMin, zMax);
G4ThreeVector vertex6(xMax, yMax, zMax);
G4ThreeVector vertex7(xMin, yMax, zMax);
vertices->push_back(pTransform.TransformPoint(vertex0));
vertices->push_back(pTransform.TransformPoint(vertex1));
vertices->push_back(pTransform.TransformPoint(vertex2));
vertices->push_back(pTransform.TransformPoint(vertex3));
vertices->push_back(pTransform.TransformPoint(vertex4));
vertices->push_back(pTransform.TransformPoint(vertex5));
vertices->push_back(pTransform.TransformPoint(vertex6));
vertices->push_back(pTransform.TransformPoint(vertex7));
}
else
{
G4Exception("G4VUSolid::CreateRotatedVertices()", "FatalError",
FatalException, "Out of memory - Cannot allocate vertices!");
}
return vertices;
}
G4Polyhedron* G4USolid::CreatePolyhedron() const
{
G4int index = 0;
if (fShape->GetEntityType() == "Box")
{
double array[3];
fShape->GetParametersList(index, array);
return new G4PolyhedronBox(array[0], array[1], array[2]);
}
if (fShape->GetEntityType() == "Tubs")
{
double array[5];
fShape->GetParametersList(index, array);
return new G4PolyhedronTubs(array[0], array[1], array[2], array[3], array[4]);
}
if (fShape->GetEntityType() == "Cons")
{
double array[7];
fShape->GetParametersList(index, array);
return new G4PolyhedronCons(array[0], array[1], array[2], array[3], array[4], array[5], array[6]);
}
if (fShape->GetEntityType() == "Orb")
{
double array[1];
fShape->GetParametersList(index, array);
return new G4PolyhedronSphere(0., array[0], 0., 2 * pi, 0., pi);
}
if (fShape->GetEntityType() == "Sphere")
{
double array[6];
fShape->GetParametersList(index, array);
return new G4PolyhedronSphere(array[0], array[1], array[2], array[3], array[4], array[5]);
}
if (fShape->GetEntityType() == "Tet")
{
double array[12];
fShape->GetParametersList(index, array);
G4Polyhedron* ph = new G4Polyhedron;
double xyz[4][3];
static int faces[4][4] = {{1, 3, 2, 0}, {1, 4, 3, 0}, {1, 2, 4, 0}, {2, 3, 4, 0}};
xyz[0][0] = array[0];
xyz[0][1] = array[1];
xyz[0][2] = array[2];
xyz[1][0] = array[3];
xyz[1][1] = array[4];
xyz[1][2] = array[5];
xyz[2][0] = array[6];
xyz[2][1] = array[7];
xyz[2][2] = array[8];
xyz[3][0] = array[9];
xyz[3][1] = array[10];
xyz[3][2] = array[11];
ph->createPolyhedron(4, 4, xyz, faces);
return ph;
}
if (fShape->GetEntityType() == "Trd")
{
double array[5];
fShape->GetParametersList(index, array);
return new G4PolyhedronTrd2(array[0], array[1], array[2], array[3], array[4]);
}
if (fShape->GetEntityType() == "Trap")
{
double array[12];
fShape->GetParametersList(index, array);
double phi = (array[11] != 1.0) ? (std::atan(array[10] / array[9])) : (0.0);
double alpha1 = std::atan(array[4]);
double alpha2 = std::atan(array[8]);
double theta = std::acos(array[11]);
return new G4PolyhedronTrap(array[0], theta, phi,
array[1], array[2], array[3], alpha1,
array[5], array[6], array[7], alpha2);
}
/*
if(fShape->GetEntityType()=="TessellatedSolid"){
G4Polyhedron *uPolyhedron=fShape->GetPolyhedron();
std::size_t nVertices = (*uPolyhedron).vertices.size();
std::size_t nFacets = (*uPolyhedron).facets.size();
G4PolyhedronArbitrary *polyhedron =
new G4PolyhedronArbitrary (nVertices, nFacets);
for (std::vector<UVector3>::const_iterator v = (*uPolyhedron).vertices.begin();
v!=(*uPolyhedron).vertices.end(); v++)
{
UVector3 p=(*v);
G4ThreeVector pt(p.x,p.y,p.z);
polyhedron->AddVertex(pt);
}
for (std::vector<UFacet>::const_iterator f=(*uPolyhedron).facets.begin();
f != (*uPolyhedron).facets.end(); f++)
{
polyhedron->AddFacet((*f).f1,(*f).f2,(*f).f3,(*f).f4);
}
return (G4Polyhedron*) polyhedron;
}
*/
return 0;
}
G4Polyhedron* G4USolid::GetPolyhedron() const
{
if (!fPolyhedron) fPolyhedron = CreatePolyhedron();
return fPolyhedron;
}
void G4USolid::ResetPolyhedron() const
{
if (fPolyhedron) delete fPolyhedron;
fPolyhedron = 0;
}
G4VisExtent G4USolid:: GetExtent() const
{
G4VisExtent extent;
G4VoxelLimits voxelLimits; // Defaults to "infinite" limits.
G4AffineTransform affineTransform;
G4double vmin, vmax;
CalculateExtent(kXAxis, voxelLimits, affineTransform, vmin, vmax);
extent.SetXmin(vmin);
extent.SetXmax(vmax);
CalculateExtent(kYAxis, voxelLimits, affineTransform, vmin, vmax);
extent.SetYmin(vmin);
extent.SetYmax(vmax);
CalculateExtent(kZAxis, voxelLimits, affineTransform, vmin, vmax);
extent.SetZmin(vmin);
extent.SetZmax(vmax);
return extent;
}
+458
View File
@@ -0,0 +1,458 @@
//
// ********************************************************************
// * This Software is part of the AIDA Unified Solids Library package *
// * See: https://aidasoft.web.cern.ch/USolids *
// ********************************************************************
//
// $Id:$
//
// --------------------------------------------------------------------
//
// UBits
//
// 19.10.12 Marek Gayer
// Created from original implementation in ROOT (TBits)
// --------------------------------------------------------------------
#include "UBits.hh"
#include <stdio.h>
//______________________________________________________________________________
UBits::UBits(unsigned int nBits) : fNBits(nBits)
{
// UBits constructor. All bits set to 0
if (fNBits <= 0) fNBits = 0;
fNBytes = fNBits ? ((fNBits - 1) / 8) + 1 : 1;
fAllBits = new unsigned char[fNBytes];
// this is redundant only with libNew
std::memset(fAllBits, 0, fNBytes);
}
//______________________________________________________________________________
UBits::UBits(const UBits& original) : fNBits(original.fNBits),
fNBytes(original.fNBytes)
{
// UBits copy constructor
fAllBits = new unsigned char[fNBytes];
std::memcpy(fAllBits, original.fAllBits, fNBytes);
}
//______________________________________________________________________________
UBits& UBits::operator=(const UBits& rhs)
{
// UBits assignment operator
// Check assignment to self
if (this == &rhs) { return *this; }
// TObject::operator=(rhs);
fNBits = rhs.fNBits;
fNBytes = rhs.fNBytes;
delete [] fAllBits;
if (fNBytes != 0) {
fAllBits = new unsigned char[fNBytes];
std::memcpy(fAllBits,rhs.fAllBits,fNBytes);
} else {
fAllBits = 0;
}
return *this;
}
//______________________________________________________________________________
UBits::~UBits()
{
// UBits destructor
delete [] fAllBits;
}
//______________________________________________________________________________
void UBits::Clear()
{
// Clear the value.
delete [] fAllBits;
fAllBits = 0;
fNBits = 0;
fNBytes = 0;
}
//______________________________________________________________________________
void UBits::Compact()
{
// Reduce the storage used by the object to a minimun
if (!fNBits || !fAllBits) return;
unsigned int needed;
for (needed = fNBytes - 1;
needed > 0 && fAllBits[needed] == 0;)
{
needed--;
};
needed++;
if (needed != fNBytes)
{
unsigned char* old_location = fAllBits;
fAllBits = new unsigned char[needed];
std::memcpy(fAllBits, old_location, needed);
delete [] old_location;
fNBytes = needed;
fNBits = 8 * fNBytes;
}
}
/*
//______________________________________________________________________________
unsigned int UBits::CounUBits(unsigned int startBit) const
{
// Return number of bits set to 1 starting at bit startBit
static const int nBitsCached[256] = {
0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,
1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8};
unsigned int i,count = 0;
if (startBit == 0) {
for(i=0; i<fNBytes; i++) {
count += nBitsCached[fAllBits[i]];
}
return count;
}
if (startBit >= fNBits) return count;
unsigned int startByte = startBit/8;
unsigned int ibit = startBit%8;
if (ibit) {
for (i=ibit;i<8;i++) {
if (fAllBits[startByte] & (1<<ibit)) count++;
}
startByte++;
}
for(i=startByte; i<fNBytes; i++) {
count += nBitsCached[fAllBits[i]];
}
return count;
}
*/
/*
//______________________________________________________________________________
void UBits::DoAndEqual(const UBits& rhs)
{
// Execute (*this) &= rhs;
// Extra bits in rhs are ignored
// Missing bits in rhs are assumed to be zero.
unsigned int min = (fNBytes<rhs.fNBytes) ? fNBytes : rhs.fNBytes;
for(unsigned int i=0; i<min; ++i) {
fAllBits[i] &= rhs.fAllBits[i];
}
if (fNBytes>min) {
std::memset(&(fAllBits[min]),0,fNBytes-min);
}
}
*/
/*
//______________________________________________________________________________
void UBits::DoOrEqual(const UBits& rhs)
{
// Execute (*this) &= rhs;
// Extra bits in rhs are ignored
// Missing bits in rhs are assumed to be zero.
unsigned int min = (fNBytes<rhs.fNBytes) ? fNBytes : rhs.fNBytes;
for(unsigned int i=0; i<min; ++i) {
fAllBits[i] |= rhs.fAllBits[i];
}
}
//______________________________________________________________________________
void UBits::DoXorEqual(const UBits& rhs)
{
// Execute (*this) ^= rhs;
// Extra bits in rhs are ignored
// Missing bits in rhs are assumed to be zero.
unsigned int min = (fNBytes<rhs.fNBytes) ? fNBytes : rhs.fNBytes;
for(unsigned int i=0; i<min; ++i) {
fAllBits[i] ^= rhs.fAllBits[i];
}
}
//______________________________________________________________________________
void UBits::DoFlip()
{
// Execute ~(*this)
for(unsigned int i=0; i<fNBytes; ++i) {
fAllBits[i] = ~fAllBits[i];
}
// NOTE: out-of-bounds bit were also flipped!
}
//______________________________________________________________________________
void UBits::DoLeftShift(unsigned int shift)
{
// Execute the left shift operation.
if (shift==0) return;
const unsigned int wordshift = shift / 8;
const unsigned int offset = shift % 8;
if (offset==0) {
for(unsigned int n = fNBytes - 1; n >= wordshift; --n) {
fAllBits[n] = fAllBits[ n - wordshift ];
}
} else {
const unsigned int sub_offset = 8 - offset;
for(unsigned int n = fNBytes - 1; n > wordshift; --n) {
fAllBits[n] = (fAllBits[n - wordshift] << offset) |
(fAllBits[n - wordshift - 1] >> sub_offset);
}
fAllBits[wordshift] = fAllBits[0] << offset;
}
std::memset(fAllBits,0,wordshift);
}
//______________________________________________________________________________
void UBits::DoRightShift(unsigned int shift)
{
// Execute the left shift operation.
if (shift==0) return;
const unsigned int wordshift = shift / 8;
const unsigned int offset = shift % 8;
const unsigned int limit = fNBytes - wordshift - 1;
if (offset == 0)
for (unsigned int n = 0; n <= limit; ++n)
fAllBits[n] = fAllBits[n + wordshift];
else
{
const unsigned int sub_offset = 8 - offset;
for (unsigned int n = 0; n < limit; ++n)
fAllBits[n] = (fAllBits[n + wordshift] >> offset) |
(fAllBits[n + wordshift + 1] << sub_offset);
fAllBits[limit] = fAllBits[fNBytes-1] >> offset;
}
std::memset(&(fAllBits[limit + 1]),0, fNBytes - limit - 1);
}
*/
/*
//______________________________________________________________________________
unsigned int UBits::FirstNullBit(unsigned int startBit) const
{
// Return position of first null bit (starting from position 0 and up)
static const int fbits[256] = {
0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,
0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,
0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,
0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,6,
0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,
0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,
0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,
0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,7,
0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,
0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,
0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,
0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,6,
0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,
0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,
0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,
0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,8};
unsigned int i;
if (startBit == 0) {
for(i=0; i<fNBytes; i++) {
if (fAllBits[i] != 255) return 8*i + fbits[fAllBits[i]];
}
return fNBits;
}
if (startBit >= fNBits) return fNBits;
unsigned int startByte = startBit/8;
unsigned int ibit = startBit%8;
if (ibit) {
for (i=ibit;i<8;i++) {
if ((fAllBits[startByte] & (1<<i)) == 0) return 8*startByte+i;
}
startByte++;
}
for(i=startByte; i<fNBytes; i++) {
if (fAllBits[i] != 255) return 8*i + fbits[fAllBits[i]];
}
return fNBits;
}
//______________________________________________________________________________
unsigned int UBits::FirstSetBit(unsigned int startBit) const
{
// Return position of first non null bit (starting from position 0 and up)
static const int fbits[256] = {
8,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
7,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0};
unsigned int i;
if (startBit == 0) {
for(i=0; i<fNBytes; i++) {
if (fAllBits[i] != 0) return 8*i + fbits[fAllBits[i]];
}
return fNBits;
}
if (startBit >= fNBits) return fNBits;
unsigned int startByte = startBit/8;
unsigned int ibit = startBit%8;
if (ibit) {
for (i=ibit;i<8;i++) {
if ((fAllBits[startByte] & (1<<i)) != 0) return 8*startByte+i;
}
startByte++;
}
for(i=startByte; i<fNBytes; i++) {
if (fAllBits[i] != 0) return 8*i + fbits[fAllBits[i]];
}
return fNBits;
}
*/
//______________________________________________________________________________
void UBits::Output(std::ostream& os) const
{
// Print the value to the std::ostream
for (unsigned int i = 0; i < fNBytes; ++i)
{
unsigned char val = fAllBits[fNBytes - 1 - i];
for (unsigned int j = 0; j < 8; ++j)
{
os << (bool)(val & 0x80);
val <<= 1;
}
}
}
//______________________________________________________________________________
void UBits::Print() const
{
// Print the list of active bits
int count = 0;
for (unsigned int i = 0; i < fNBytes; ++i)
{
unsigned char val = fAllBits[i];
for (unsigned int j = 0; j < 8; ++j)
{
if (val & 1) printf(" bit:%4d = 1\n", count);
count++;
val = val >> 1;
}
}
}
//______________________________________________________________________________
void UBits::ResetAllBits(bool value)
{
if (fAllBits) std::memset(fAllBits, value ? 0xFF : 0, fNBytes);
}
//______________________________________________________________________________
void UBits::ReserveBytes(unsigned int nbytes)
{
// Reverse each bytes.
if (nbytes > fNBytes)
{
// do it in this order to remain exception-safe.
unsigned char* newBits = new unsigned char[nbytes];
delete[] fAllBits;
fNBytes = nbytes;
fAllBits = newBits;
}
}
//______________________________________________________________________________
void UBits::Set(unsigned int nBits, const char* array)
{
// Set all the bytes
unsigned int nbytes = (nBits + 7) >> 3;
ReserveBytes(nbytes);
fNBits = nBits;
std::memcpy(fAllBits, array, nbytes);
}
//______________________________________________________________________________
void UBits::Get(char* array) const
{
// Copy all the byes.
std::memcpy(array, fAllBits, (fNBits + 7) >> 3);
}
// If we are on a little endian machine, a bitvector represented using
// any integer type is identical to a bitvector represented using bytes. -- FP.
void UBits::Set(unsigned int nBits, const int* array)
{
// Set all the bytes.
Set(nBits, (const char*)array);
}
void UBits::Get(int* array) const
{
// Get all the bytes.
Get((char*)array);
}
/*
bool UBits::operator==(const UBits &other) const
{
// Compare object.
if (fNBits == other.fNBits) {
return !memcmp(fAllBits, other.fAllBits, (fNBits+7)>>3);
} else if (fNBits < other.fNBits) {
return !memcmp(fAllBits, other.fAllBits, (fNBits+7)>>3) && other.FirstSetBit(fNBits) == other.fNBits;
} else {
return !memcmp(fAllBits, other.fAllBits, (other.fNBits+7)>>3) && FirstSetBit(other.fNBits) == fNBits;
}
}
*/
+551
View File
@@ -0,0 +1,551 @@
//
// ********************************************************************
// * This Software is part of the AIDA Unified Solids Library package *
// * See: https://aidasoft.web.cern.ch/USolids *
// ********************************************************************
//
// $Id:$
//
// --------------------------------------------------------------------
//
// UBox
//
// 10.06.11 J.Apostolakis, G.Cosmo, A.Gheata
// Created from original implementation in Geant4 and ROOT
// --------------------------------------------------------------------
#include <iostream>
#include <sstream>
#include "UUtils.hh"
#include "UBox.hh"
//______________________________________________________________________________
UBox::UBox(const std::string& name, double dx, double dy, double dz)
: VUSolid(name),
fDx(dx),
fDy(dy),
fDz(dz), fCubicVolume(0.), fSurfaceArea(0.)
{
// Named constructor
if ((dx < 2 * VUSolid::fgTolerance)
|| (dy < 2 * VUSolid::fgTolerance)
|| (dz < 2 * VUSolid::fgTolerance)) // limit to thickness of surfaces
{
//std::ostringstream message;
std::ostringstream message;
message << "Dimensions too small for Solid: " << GetName() << "!" << std::endl
<< " dx, dy, dz = " << dx << ", " << dy << ", " << dz;
UUtils::Exception("UBox::UBox()", "UGeomSolids", FatalErrorInArguments, 1, message.str().c_str());
}
}
void UBox::Set(double dx, double dy, double dz)
{
fDx = dx;
fDy = dy;
fDz = dz;
}
void UBox::Set(const UVector3& vec)
{
fDx = vec.x;
fDy = vec.y;
fDz = vec.z;
}
//Destructor
UBox::~UBox()
{
}
// Copy constructor
UBox::UBox(const UBox& rhs)
: VUSolid(rhs), fDx(rhs.fDx), fDy(rhs.fDy), fDz(rhs.fDz),
fCubicVolume(rhs.fCubicVolume), fSurfaceArea(rhs.fSurfaceArea)
{
}
//
// Assignment operator
UBox& UBox::operator = (const UBox& rhs)
{
// Check assignment to self
//
if (this == &rhs)
{
return *this;
}
// Copy base class data
//
VUSolid::operator=(rhs);
// Copy data
//
fDx = rhs.fDx;
fDy = rhs.fDy;
fDz = rhs.fDz;
fCubicVolume = rhs.fCubicVolume;
fSurfaceArea = rhs.fSurfaceArea;
return *this;
}
//______________________________________________________________________________
VUSolid::EnumInside UBox::Inside(const UVector3& aPoint) const
{
// Classify point location with respect to solid:
// o eInside - inside the solid
// o eSurface - close to surface within tolerance
// o eOutside - outside the solid
static const double delta = VUSolid::fgTolerance;
// Early returns on outside condition on any axis. Check Z first for faster
// exclusion in phi symmetric geometries.
double ddz = std::abs(aPoint.z) - fDz;
if (ddz > delta) return eOutside;
double ddx = std::abs(aPoint.x) - fDx;
if (ddx > delta) return eOutside;
double ddy = std::abs(aPoint.y) - fDy;
if (ddy > delta) return eOutside;
if (ddx > - delta || ddy > -delta || ddz > -delta) return eSurface;
return eInside;
}
//______________________________________________________________________________
double UBox::DistanceToIn(const UVector3& aPoint,
const UVector3& aDirection,
// UVector3 &aNormal,
double aPstep) const
{
// Computes distance from a point presumably outside the solid to the solid
// surface. Ignores first surface if the point is actually inside. Early return
// infinity in case the safety to any surface is found greater than the proposed
// step aPstep.
// The normal vector to the crossed surface is filled only in case the box is
// crossed, otherwise aNormal.IsNull() is true.
// Compute safety to the closest surface on each axis.
// Early exits if safety bigger than proposed step.
static const double delta = VUSolid::fgTolerance;
// aNormal.SetNull();
double safx = std::abs(aPoint.x) - fDx;
double safy = std::abs(aPoint.y) - fDy;
double safz = std::abs(aPoint.z) - fDz;
if ((safx > aPstep) || (safy > aPstep) || (safz > aPstep))
return UUtils::kInfinity;
// Check numerical outside.
bool outside = (safx > 0) || (safy > 0) || (safz > 0);
if (!outside)
{
// If point close to this surface, check against the normal
if (safx > -delta)
{
// aNormal.x = UUtils::Sign(1.0, aPoint.x);
return (aPoint.x * aDirection.x > 0) ? UUtils::kInfinity : 0.0;
}
if (safy > -delta)
{
// aNormal.y = UUtils::Sign(1.0, aPoint.y);
return (aPoint.y * aDirection.y > 0) ? UUtils::kInfinity : 0.0;
}
if (safz > -delta)
{
// aNormal.z = UUtils::Sign(1.0, aPoint.z);
return (aPoint.z * aDirection.z > 0) ? UUtils::kInfinity : 0.0;
}
// Point actually "deep" inside, return zero distance, normal un-defined
return 0.0;
}
// The point is really outside. Only axis with positive safety to be
// considered. Early exit on each axis if point and direction components
// have the same .sign.
double dist = 0.0;
double coordinate = 0.0;
if (safx > 0)
{
if (aPoint.x * aDirection.x >= 0) return UUtils::kInfinity;
dist = safx / std::abs(aDirection.x);
coordinate = aPoint.y + dist * aDirection.y;
if (std::abs(coordinate) < fDy)
{
coordinate = aPoint.z + dist * aDirection.z;
if (std::abs(coordinate) < fDz)
{
// aNormal.x = UUtils::Sign(1.0, aPoint.x);
if (dist < 0.5 * delta) dist = 0.;
return dist;
}
}
}
if (safy > 0)
{
if (aPoint.y * aDirection.y >= 0) return UUtils::kInfinity;
dist = safy / std::abs(aDirection.y);
coordinate = aPoint.x + dist * aDirection.x;
if (std::abs(coordinate) < fDx)
{
coordinate = aPoint.z + dist * aDirection.z;
if (std::abs(coordinate) < fDz)
{
// aNormal.y = UUtils::Sign(1.0, aPoint.y);
if (dist < 0.5 * delta) dist = 0.;
return dist;
}
}
}
if (safz > 0)
{
if (aPoint.z * aDirection.z >= 0) return UUtils::kInfinity;
dist = safz / std::abs(aDirection.z);
coordinate = aPoint.x + dist * aDirection.x;
if (std::abs(coordinate) < fDx)
{
coordinate = aPoint.y + dist * aDirection.y;
if (std::abs(coordinate) < fDy)
{
// aNormal.z = UUtils::Sign(1.0, aPoint.z);
if (dist < 0.5 * delta) dist = 0.;
return dist;
}
}
}
return UUtils::kInfinity;
}
//______________________________________________________________________________
double UBox::DistanceToOut(const UVector3& aPoint, const UVector3& aDirection,
UVector3& aNormal,
bool& convex,
double /*aPstep*/) const
{
// Computes distance from a point presumably intside the solid to the solid
// surface. Ignores first surface along each axis systematically (for points
// inside or outside. Early returns zero in case the second surface is behind
// the starting point.
// o The proposed step is ignored.
// o The normal vector to the crossed surface is always filled.
double smin = UUtils::kInfinity;
double snxt, signDir;
convex = true; // Box is convex (even if the starting point is outside)
// Check always the "away" surface along direction on axis. This responds
// corectly even for points outside the solid (no need for tolerance check)
if (aDirection.x != 0.0)
{
signDir = UUtils::Sign(1.0, aDirection.x);
aNormal.Set(signDir, 0., 0.);
snxt = (-aPoint.x + signDir * fDx) / aDirection.x;
if (snxt <= 0) return 0.0; // point outside moving outwards
smin = snxt;
}
if (aDirection.y != 0.0)
{
signDir = UUtils::Sign(1.0, aDirection.y);
snxt = (-aPoint.y + signDir * fDy) / aDirection.y;
if (snxt <= 0)
{
aNormal.Set(0., signDir, 0.);
return 0.0; // point outside moving outwards
}
if (snxt < smin)
{
smin = snxt;
aNormal.Set(0., signDir, 0.);
}
}
if (aDirection.z != 0.0)
{
signDir = UUtils::Sign(1.0, aDirection.z);
snxt = (-aPoint.z + signDir * fDz) / aDirection.z;
if (snxt <= 0)
{
aNormal.Set(0., 0., signDir);
return 0.0; // point outside moving outwards
}
if (snxt < smin)
{
smin = snxt;
aNormal.Set(0., 0., signDir);
}
}
if (smin < 0.5 * VUSolid::fgTolerance) smin = 0.;
return smin;
}
//______________________________________________________________________________
double UBox::SafetyFromInside(const UVector3& aPoint,
bool /*aAccurate*/) const
{
// Estimates the isotropic safety from a point inside the current solid to any
// of its surfaces. The algorithm may be accurate or should provide a fast
// underestimate.
double safe, safy, safz;
safe = fDx - std::abs(aPoint.x);
safy = fDy - std::abs(aPoint.y);
if (safy < safe) safe = safy;
safz = fDz - std::abs(aPoint.z);
if (safz < safe) safe = safz;
return std::max(0.0, safe);
}
//______________________________________________________________________________
double UBox::SafetyFromOutside(const UVector3& aPoint,
bool aAccurate) const
{
// Estimates the isotropic safety from a point outside the current solid to any
// of its surfaces. The algorithm may be accurate or should provide a fast
// underestimate.
double safe, safx, safy, safz;
safe = safx = -fDx + std::abs(aPoint.x);
safy = -fDy + std::abs(aPoint.y);
if (safy > safe) safe = safy;
safz = -fDz + std::abs(aPoint.z);
if (safz > safe) safe = safz;
if (safe < 0.0) return 0.0; // point is inside
if (!aAccurate) return safe;
double safsq = 0.0;
int count = 0;
if (safx > 0)
{
safsq += safx * safx;
count++;
}
if (safy > 0)
{
safsq += safy * safy;
count++;
}
if (safz > 0)
{
safsq += safz * safz;
count++;
}
if (count == 1) return safe;
return std::sqrt(safsq);
}
//______________________________________________________________________________
bool UBox::Normal(const UVector3& aPoint, UVector3& aNormal) const
{
// Computes the normal on a surface and returns it as a unit vector
// In case a point is further than tolerance_normal from a surface, set validNormal=false
// Must return a valid vector. (even if the point is not on the surface.)
//
// On an edge or corner, provide an average normal of all facets within tolerance
// NOTE: the tolerance value used in here is not yet the global surface
// tolerance - we will have to revise this value - TODO
static const double delta = 100.*VUSolid::fgTolerance;
static const double kInvSqrt2 = 1. / std::sqrt(2.);
static const double kInvSqrt3 = 1. / std::sqrt(3.);
aNormal.Set(0.);
UVector3 crt_normal, min_normal;
int nsurf = 0;
double safx = std::abs(std::abs(aPoint.x) - fDx);
double safmin = safx;
crt_normal.Set(UUtils::Sign(1., aPoint.x), 0., 0.);
min_normal = crt_normal;
if (safx < delta)
{
nsurf++;
aNormal += crt_normal;
}
double safy = std::abs(std::abs(aPoint.y) - fDy);
crt_normal.Set(0., UUtils::Sign(1., aPoint.y), 0.);
if (safy < delta)
{
nsurf++;
aNormal += crt_normal;
}
if (safy < safmin)
{
min_normal = crt_normal;
safmin = safy;
}
double safz = std::abs(std::abs(aPoint.z) - fDz);
crt_normal.Set(0., 0., UUtils::Sign(1., aPoint.z));
if (safz < delta)
{
nsurf++;
aNormal += crt_normal;
}
if (safz < safmin)
{
min_normal = crt_normal;
safmin = safz;
}
bool valid = true;
switch (nsurf)
{
case 0:
aNormal = min_normal;
valid = false;
break;
case 1:
break;
case 2:
aNormal *= kInvSqrt2;
break;
case 3:
aNormal *= kInvSqrt3;
};
return valid;
}
//______________________________________________________________________________
void UBox::Extent(UVector3& aMin, UVector3& aMax) const
{
// Returns the full 3D cartesian extent of the solid.
aMin.x = -fDx;
aMax.x = fDx;
aMin.y = -fDy;
aMax.y = fDy;
aMin.z = -fDz;
aMax.z = fDz;
}
/////////////////////////////////////////////////////////////////////////////////////
//
// GetPointOnSurface
//
// Return a point (UVector3) randomly and uniformly selected
// on the solid surface
UVector3 UBox::GetPointOnSurface() const
{
double px, py, pz, select, sumS;
double Sxy = fDx * fDy, Sxz = fDx * fDz, Syz = fDy * fDz;
sumS = Sxy + Sxz + Syz;
select = sumS * UUtils::Random();
if (select < Sxy)
{
px = -fDx + 2 * fDx * UUtils::Random();
py = -fDy + 2 * fDy * UUtils::Random();
if (UUtils::Random() > 0.5)
{
pz = fDz;
}
else
{
pz = -fDz;
}
}
else if ((select - Sxy) < Sxz)
{
px = -fDx + 2 * fDx * UUtils::Random();
pz = -fDz + 2 * fDz * UUtils::Random();
if (UUtils::Random() > 0.5)
{
py = fDy;
}
else
{
py = -fDy;
}
}
else
{
py = -fDy + 2 * fDy * UUtils::Random();
pz = -fDz + 2 * fDz * UUtils::Random();
if (UUtils::Random() > 0.5)
{
px = fDx;
}
else
{
px = -fDx;
}
}
return UVector3(px, py, pz);
}
std::ostream& UBox::StreamInfo(std::ostream& os) const
{
int oldprc = os.precision(16);
os << "-----------------------------------------------------------\n"
<< " *** Dump for solid - " << GetName() << " ***\n"
<< " ===================================================\n"
<< " Solid type: UBox\n"
<< " Parameters: \n"
<< " half length X: " << fDx << " mm \n"
<< " half length Y: " << fDy << " mm \n"
<< " half length Z: " << fDz << " mm \n"
<< "-----------------------------------------------------------\n";
os.precision(oldprc);
return os;
}
void UBox::SetXHalfLength(double dx)
{
if (dx > 2 * VUSolid::fgTolerance) // limit to thickness of surfaces
{
fDx = dx;
}
else
{
std::ostringstream message;
message << "Dimension X too small for solid: " << GetName() << "!"
<< std::endl
<< " hX = " << dx;
UUtils::Exception("UBox::SetXHalfLength()", "GeomSolids0002",
FatalErrorInArguments, 1, message.str().c_str());
}
fCubicVolume = 0.;
fSurfaceArea = 0.;
}
void UBox::SetYHalfLength(double dy)
{
if (dy > 2 * VUSolid::fgTolerance) // limit to thickness of surfaces
{
fDy = dy;
}
else
{
std::ostringstream message;
message << "Dimension Y too small for solid: " << GetName() << "!"
<< std::endl
<< " hY = " << dy;
UUtils::Exception("UBox::SetYHalfLength()", "GeomSolids0002",
FatalErrorInArguments, 1, message.str().c_str());
}
fCubicVolume = 0.;
fSurfaceArea = 0.;
}
void UBox::SetZHalfLength(double dz)
{
if (dz > 2 * VUSolid::fgTolerance) // limit to thickness of surfaces
{
fDz = dz;
}
else
{
std::ostringstream message;
message << "Dimension Z too small for solid: " << GetName() << "!"
<< std::endl
<< " hZ = " << dz;
UUtils::Exception("G4Box::SetZHalfLength()", "GeomSolids0002",
FatalErrorInArguments, 1, message.str().c_str());
}
fCubicVolume = 0.;
fSurfaceArea = 0.;
}
UGeometryType UBox::GetEntityType() const
{
return "Box";
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,187 @@
//
// ********************************************************************
// * This Software is part of the AIDA Unified Solids Library package *
// * See: https://aidasoft.web.cern.ch/USolids *
// ********************************************************************
//
// $Id:$
//
// --------------------------------------------------------------------
//
// UEnclosingCylinder
//
// 19.10.12 Marek Gayer
// Created from original implementation in Geant4
// --------------------------------------------------------------------
#include "UUtils.hh"
#include <string>
#include <cmath>
#include <sstream>
#include "UEnclosingCylinder.hh"
#include "UReduciblePolygon.hh"
#include "VUSolid.hh"
#include "UBox.hh"
#include "UTubs.hh"
//
// Constructor
//
UEnclosingCylinder::UEnclosingCylinder(/*const UReduciblePolygon *rz*/double r, double hi, double lo,
bool thePhiIsOpen,
double theStartPhi,
double theTotalPhi)
: startPhi(theStartPhi), totalPhi(theTotalPhi),
rx1(0.), ry1(0.), dx1(0.), dy1(0.),
rx2(0.), ry2(0.), dx2(0.), dy2(0.),
concave(theTotalPhi > UUtils::kPi)
{
//
// Obtain largest r and smallest and largest z
//
/*
radius = rz->Amax();
zHi = rz->Bmax();
zLo = rz->Bmin();
*/
radius = r;
zHi = hi;
zLo = lo;
double fTolerance = VUSolid::Tolerance();
tube = new UTubs("", 0, radius + fTolerance, zHi - zLo, theStartPhi, theTotalPhi);
//
// Save phi info
//
phiIsOpen = thePhiIsOpen;
if (phiIsOpen)
{
rx1 = std::cos(startPhi);
ry1 = std::sin(startPhi);
dx1 = +ry1 * 10 * fTolerance;
dy1 = -rx1 * 10 * fTolerance;
rx2 = std::cos(startPhi + totalPhi);
ry2 = std::sin(startPhi + totalPhi);
dx2 = -ry2 * 10 * fTolerance;
dy2 = +rx2 * 10 * fTolerance;
}
//
// Add safety
//
radius += 10 * fTolerance;
zLo -= 10 * fTolerance;
zHi += 10 * fTolerance;
}
//
// Destructor
//
UEnclosingCylinder::~UEnclosingCylinder()
{
}
//
// Outside
//
// Decide very rapidly if the point is outside the cylinder
//
// If one is not certain, return false
//
bool UEnclosingCylinder::MustBeOutside(const UVector3& p) const
{
// if (p.Perp() > radius ) return true;
if (p.Perp2() > radius * radius) return true;
if (p.z < zLo) return true;
if (p.z > zHi) return true;
if (phiIsOpen)
{
if (concave)
{
if (((p.x - dx1)*ry1 - (p.y - dy1)*rx1) < 0) return false;
if (((p.x - dx2)*ry2 - (p.y - dy2)*rx2) > 0) return false;
}
else
{
if (((p.x - dx1)*ry1 - (p.y - dy1)*rx1) > 0) return true;
if (((p.x - dx2)*ry2 - (p.y - dy2)*rx2) < 0) return true;
}
}
return false;
}
//
// Misses
//
// Decide very rapidly if the trajectory is going to miss the cylinder
//
// If one is not sure, return false
//
bool UEnclosingCylinder::ShouldMiss(const UVector3& p,
const UVector3& v) const
{
if (!MustBeOutside(p)) return false;
// if (p.z < zLo - VUSolid::Tolerance() && v.z <= 0) return true;
// if (p.z > zHi + VUSolid::Tolerance() && v.z >= 0) return true;
double cross = p.x * v.y - p.y * v.x;
if (cross > radius) return true;
double r2 = p.Perp2();
if (r2 > radius * radius)
{
double dot = p.x * v.x + p.y * v.y;
if (dot > 0) return true;
// double n = v.Perp2();
// if (Dot < std::sqrt(r2 - radius * radius) * n) return true;
}
/*
if (phiIsOpen)
{
if (concave)
{
if ( ((p.x-dx1)*ry1 - (p.y-dy1)*rx1) < 0) return false;
if ( ((p.x-dx2)*ry2 - (p.y-dy2)*rx2) > 0) return false;
}
else
{
if ( ((p.x-dx1)*ry1 - (p.y-dy1)*rx1) > 0) return true;
if ( ((p.x-dx2)*ry2 - (p.y-dy2)*rx2) < 0) return true;
}
return false;
}
*/
return false;
}
void UEnclosingCylinder::Extent(UVector3& aMin, UVector3& aMax) const
{
aMin = UVector3(-radius, -radius, zLo);
aMax = UVector3(radius, radius, zHi);
}
double UEnclosingCylinder::DistanceTo(const UVector3& p, const UVector3& v) const
{
return tube->DistanceToIn(p, v);
}
double UEnclosingCylinder::SafetyFromOutside(const UVector3& p) const
{
return tube->SafetyFromOutside(p);
}
@@ -0,0 +1,431 @@
//
// ********************************************************************
// * This Software is part of the AIDA Unified Solids Library package *
// * See: https://aidasoft.web.cern.ch/USolids *
// ********************************************************************
//
// $Id:$
//
// --------------------------------------------------------------------
//
// UGenericPolycone
//
// 19.10.13 Tatiana Nikitina
// Created from original implementation in Geant4
// --------------------------------------------------------------------
#include "UUtils.hh"
#include <string>
#include <cmath>
#include <sstream>
#include "UGenericPolycone.hh"
#include "UPolyconeSide.hh"
#include "UPolyPhiFace.hh"
#include "UEnclosingCylinder.hh"
#include "UReduciblePolygon.hh"
using namespace std;
//
// Constructor (generic parameters)
//
UGenericPolycone::UGenericPolycone(const std::string& name,
double phiStart,
double phiTotal,
int numRZ,
const double r[],
const double z[])
: UVCSGfaceted(name)
{
UReduciblePolygon* rz = new UReduciblePolygon(r, z, numRZ);
Create(phiStart, phiTotal, rz);
delete rz;
}
//
// Create
//
// Generic create routine, called by each constructor after
// conversion of arguments
//
void UGenericPolycone::Create(double phiStart,
double phiTotal,
UReduciblePolygon* rz)
{
//
// Perform checks of rz values
//
if (rz->Amin() < 0.0)
{
std::ostringstream message;
message << "Illegal input parameters - " << GetName() << std::endl
<< " All R values must be >= 0 !";
UUtils::Exception("UGenericPolycone::Create()", "GeomSolids0002",
FatalErrorInArguments, 1, message.str().c_str());
}
double rzArea = rz->Area();
if (rzArea < -VUSolid::Tolerance())
rz->ReverseOrder();
else if (rzArea < -VUSolid::Tolerance())
{
std::ostringstream message;
message << "Illegal input parameters - " << GetName() << std::endl
<< " R/Z Cross section is zero or near zero: " << rzArea;
UUtils::Exception("UGenericPolycone::Create()", "GeomSolids0002",
FatalErrorInArguments, 1, message.str().c_str());
}
if ((!rz->RemoveDuplicateVertices(VUSolid::Tolerance()))
|| (!rz->RemoveRedundantVertices(VUSolid::Tolerance())))
{
std::ostringstream message;
message << "Illegal input parameters - " << GetName() << std::endl
<< " Too few unique R/Z values !";
UUtils::Exception("UGenericPolycone::Create()", "GeomSolids0002",
FatalErrorInArguments, 1, message.str().c_str());
}
if (rz->CrossesItself(1 / UUtils::kInfinity))
{
std::ostringstream message;
message << "Illegal input parameters - " << GetName() << std::endl
<< " R/Z segments Cross !";
UUtils::Exception("UGenericPolycone::Create()", "GeomSolids0002",
FatalErrorInArguments, 1, message.str().c_str());
}
numCorner = rz->NumVertices();
//
// Phi opening? Account for some possible roundoff, and interpret
// nonsense value as representing no phi opening
//
if (phiTotal <= 0 || phiTotal > 2 * UUtils::kPi - 1E-10)
{
phiIsOpen = false;
startPhi = 0;
endPhi = 2 * UUtils::kPi;
}
else
{
phiIsOpen = true;
//
// Convert phi into our convention
//
startPhi = phiStart;
while (startPhi < 0) startPhi += 2 * UUtils::kPi;
endPhi = phiStart + phiTotal;
while (endPhi < startPhi) endPhi += 2 * UUtils::kPi;
}
//
// Allocate corner array.
//
corners = new UPolyconeSideRZ[numCorner];
//
// Copy corners
//
UReduciblePolygonIterator iterRZ(rz);
UPolyconeSideRZ* next = corners;
iterRZ.Begin();
do
{
next->r = iterRZ.GetA();
next->z = iterRZ.GetB();
}
while (++next, iterRZ.Next());
//
// Allocate face pointer array
//
numFace = phiIsOpen ? numCorner + 2 : numCorner;
faces = new UVCSGface*[numFace];
//
// Construct conical faces
//
// But! Don't construct a face if both points are at zero radius!
//
UPolyconeSideRZ* corner = corners,
*prev = corners + numCorner - 1,
*nextNext;
UVCSGface** face = faces;
do
{
next = corner + 1;
if (next >= corners + numCorner) next = corners;
nextNext = next + 1;
if (nextNext >= corners + numCorner) nextNext = corners;
if (corner->r < 1 / UUtils::kInfinity && next->r < 1 / UUtils::kInfinity) continue;
//
// We must decide here if we can dare declare one of our faces
// as having a "valid" normal (i.e. allBehind = true). This
// is never possible if the face faces "inward" in r.
//
bool allBehind;
if (corner->z > next->z)
{
allBehind = false;
}
else
{
//
// Otherwise, it is only true if the line passing
// through the two points of the segment do not
// split the r/z Cross section
//
allBehind = !rz->BisectedBy(corner->r, corner->z,
next->r, next->z, VUSolid::Tolerance());
}
*face++ = new UPolyconeSide(prev, corner, next, nextNext,
startPhi, endPhi - startPhi, phiIsOpen, allBehind);
}
while (prev = corner, corner = next, corner > corners);
if (phiIsOpen)
{
//
// Construct phi open edges
//
*face++ = new UPolyPhiFace(rz, startPhi, 0, endPhi);
*face++ = new UPolyPhiFace(rz, endPhi, 0, startPhi);
}
//
// We might have dropped a face or two: recalculate numFace
//
numFace = face - faces;
//
// Make enclosingCylinder
//
enclosingCylinder =
new UEnclosingCylinder(rz->Amax(), rz->Bmax(), rz->Bmin(), phiIsOpen, phiStart, phiTotal);
InitVoxels(*rz, enclosingCylinder->radius);
fNoVoxels = fMaxSection < 2;
}
//
// Fake default constructor - sets only member data and allocates memory
// for usage restricted to object persistency.
//
/*
UGenericPolycone::UGenericPolycone( __void__& a )
: UVCSGfaceted(a), startPhi(0.), endPhi(0.), phiIsOpen(false),
genericPcon(false), numCorner(0), corners(0),
fOriginalParameters(0), enclosingCylinder(0)
{
}
*/
//
// Destructor
//
UGenericPolycone::~UGenericPolycone()
{
delete [] corners;
delete enclosingCylinder;
}
//
// Copy constructor
//
UGenericPolycone::UGenericPolycone(const UGenericPolycone& source)
: UVCSGfaceted(source)
{
CopyStuff(source);
}
//
// Assignment operator
//
UGenericPolycone& UGenericPolycone::operator=(const UGenericPolycone& source)
{
if (this == &source) return *this;
UVCSGfaceted::operator=(source);
delete [] corners;
delete enclosingCylinder;
CopyStuff(source);
return *this;
}
//
// CopyStuff
//
void UGenericPolycone::CopyStuff(const UGenericPolycone& source)
{
//
// Simple stuff
//
startPhi = source.startPhi;
endPhi = source.endPhi;
phiIsOpen = source.phiIsOpen;
numCorner = source.numCorner;
//
// The corner array
//
corners = new UPolyconeSideRZ[numCorner];
UPolyconeSideRZ* corn = corners,
*sourceCorn = source.corners;
do
{
*corn = *sourceCorn;
}
while (++sourceCorn, ++corn < corners + numCorner);
//
// Enclosing cylinder
//
enclosingCylinder = new UEnclosingCylinder(*source.enclosingCylinder);
}
//
// Reset
//
bool UGenericPolycone::Reset()
{
std::ostringstream message;
message << "Solid " << GetName() << " built using generic construct."
<< std::endl << "Not applicable to the generic construct !";
// UException("UGenericPolycone::Reset(,,)", "GeomSolids1001",
// JustWarning, message, "Parameters NOT resetted.");
return 1;
}
//
// Inside
//
// This is an override of UVCSGfaceted::Inside, created in order
// to speed things up by first checking with UEnclosingCylinder.
//
VUSolid::EnumInside UGenericPolycone::Inside(const UVector3& p) const
{
//
// Quick test
//
if (enclosingCylinder->MustBeOutside(p)) return eOutside;
//
// Long answer
//
return UVCSGfaceted::Inside(p);
}
//
// DistanceToIn
//
// This is an override of UVCSGfaceted::Inside, created in order
// to speed things up by first checking with UEnclosingCylinder.
//
double UGenericPolycone::DistanceToIn(const UVector3& p,
const UVector3& v, double aPstep) const
{
//
// Quick test
//
if (enclosingCylinder->ShouldMiss(p, v))
return UUtils::kInfinity;
//
// Long answer
//
return UVCSGfaceted::DistanceToIn(p, v, aPstep);
}
//
// GetEntityType
//
UGeometryType UGenericPolycone::GetEntityType() const
{
return std::string("GenericPolycone");
}
//
// Make a clone of the object
//
VUSolid* UGenericPolycone::Clone() const
{
return new UGenericPolycone(*this);
}
//
// Stream object contents to an output stream
//
std::ostream& UGenericPolycone::StreamInfo(std::ostream& os) const
{
int oldprc = os.precision(16);
os << "-----------------------------------------------------------\n"
<< " *** Dump for solid - " << GetName() << " ***\n"
<< " ===================================================\n"
<< " Solid type: UGenericPolycone\n"
<< " Parameters: \n"
<< " starting phi angle : " << startPhi / (UUtils::kPi / 180.0) << " degrees \n"
<< " ending phi angle : " << endPhi / (UUtils::kPi / 180.0) << " degrees \n";
int i = 0;
os << " number of RZ points: " << numCorner << "\n"
<< " RZ values (corners): \n";
for (i = 0; i < numCorner; i++)
{
os << " "
<< corners[i].r << ", " << corners[i].z << "\n";
}
os << "-----------------------------------------------------------\n";
os.precision(oldprc);
return os;
}
//
// GetPointOnSurface
//
UVector3 UGenericPolycone::GetPointOnSurface() const
{
return GetPointOnSurfaceGeneric();
}
void UGenericPolycone::Extent(UVector3& aMin, UVector3& aMax) const
{
enclosingCylinder->Extent(aMin, aMax);
}
@@ -0,0 +1,512 @@
//
// ********************************************************************
// * This Software is part of the AIDA Unified Solids Library package *
// * See: https://aidasoft.web.cern.ch/USolids *
// ********************************************************************
//
// $Id:$
//
// --------------------------------------------------------------------
//
// UIntersectingCone
//
// 19.02.13 Marek Gayer
// Created from original implementation in Geant4
// --------------------------------------------------------------------
#include "UUtils.hh"
#include <string>
#include <cmath>
#include <sstream>
#include "UIntersectingCone.hh"
#include "VUSolid.hh"
const double UIntersectingCone::EpsilonQuad = 1.0 / 9.0E99;
//
// Constructor
//
UIntersectingCone::UIntersectingCone(const double r[2],
const double z[2])
{
static const double halfCarTolerance
= 0.5 * VUSolid::Tolerance(); // UGeometryTolerance::GetInstance()->GetSurfaceTolerance();
//
// What type of cone are we?
//
type1 = (std::fabs(z[1] - z[0]) > std::fabs(r[1] - r[0]));
if (type1)
{
B = (r[1] - r[0]) / (z[1] - z[0]); // tube like
A = 0.5 * (r[1] + r[0] - B * (z[1] + z[0]));
}
else
{
B = (z[1] - z[0]) / (r[1] - r[0]); // disk like
A = 0.5 * (z[1] + z[0] - B * (r[1] + r[0]));
}
//
// Calculate extent
//
if (r[0] < r[1])
{
rLo = r[0] - halfCarTolerance;
rHi = r[1] + halfCarTolerance;
}
else
{
rLo = r[1] - halfCarTolerance;
rHi = r[0] + halfCarTolerance;
}
if (z[0] < z[1])
{
zLo = z[0] - halfCarTolerance;
zHi = z[1] + halfCarTolerance;
}
else
{
zLo = z[1] - halfCarTolerance;
zHi = z[0] + halfCarTolerance;
}
}
/*
//
// Fake default constructor - sets only member data and allocates memory
// for usage restricted to object persistency.
//
UIntersectingCone::UIntersectingCone( __void__& )
: zLo(0.), zHi(0.), rLo(0.), rHi(0.), type1(false), A(0.), B(0.)
{
}
*/
//
// Destructor
//
UIntersectingCone::~UIntersectingCone()
{
}
//
// HitOn
//
// Check r or z extent, as appropriate, to see if the point is possibly
// on the cone.
//
bool UIntersectingCone::HitOn(const double r,
const double z)
{
//
// Be careful! The inequalities cannot be "<=" and ">=" here without
// punching a tiny hole in our shape!
//
if (type1)
{
if (z < zLo || z > zHi) return false;
}
else
{
if (r < rLo || r > rHi) return false;
}
return true;
}
//
// LineHitsCone
//
// Calculate the intersection of a line with our conical surface, ignoring
// any phi division
//
int UIntersectingCone::LineHitsCone(const UVector3& p, const UVector3& v, double& s1, double& s2)
{
if (type1)
{
return LineHitsCone1(p, v, s1, s2);
}
else
{
return LineHitsCone2(p, v, s1, s2);
}
}
//
// LineHitsCone1
//
// Calculate the intersections of a line with a conical surface. Only
// suitable if zPlane[0] != zPlane[1].
//
// Equation of a line:
//
// x = x0 + s*tx y = y0 + s*ty z = z0 + s*tz
//
// Equation of a conical surface:
//
// x**2 + y**2 = (A + B*z)**2
//
// Solution is quadratic:
//
// a*s**2 + b*s + c = 0
//
// where:
//
// a = x0**2 + y0**2 - (A + B*z0)**2
//
// b = 2*( x0*tx + y0*ty - (A*B - B*B*z0)*tz)
//
// c = tx**2 + ty**2 - (B*tz)**2
//
// Notice, that if a < 0, this indicates that the two solutions (assuming
// they exist) are in opposite cones (that is, given z0 = -A/B, one z < z0
// and the other z > z0). For our shapes, the invalid solution is one
// which produces A + Bz < 0, or the one where Bz is smallest (most negative).
// Since Bz = B*s*tz, if B*tz > 0, we want the largest s, otherwise,
// the smaller.
//
// If there are two solutions on one side of the cone, we want to make
// sure that they are on the "correct" side, that is A + B*z0 + s*B*tz >= 0.
//
// If a = 0, we have a linear problem: s = c/b, which again gives one solution.
// This should be rare.
//
// For b*b - 4*a*c = 0, we also have one solution, which is almost always
// a line just grazing the surface of a the cone, which we want to ignore.
// However, there are two other, very rare, possibilities:
// a line intersecting the z axis and either:
// 1. At the same angle std::atan(B) to just miss one side of the cone, or
// 2. Intersecting the cone apex (0,0,-A/B)
// We *don't* want to miss these! How do we identify them? Well, since
// this case is rare, we can at least swallow a little more CPU than we would
// normally be comfortable with. Intersection with the z axis means
// x0*ty - y0*tx = 0. Case (1) means a==0, and we've already dealt with that
// above. Case (2) means a < 0.
//
// Now: x0*tx + y0*ty = 0 in terms of roundoff error. We can write:
// Delta = x0*tx + y0*ty
// b = 2*( Delta - (A*B + B*B*z0)*tz )
// For:
// b*b - 4*a*c = epsilon
// where epsilon is small, then:
// Delta = epsilon/2/B
//
/*
int UIntersectingCone::Solution (const UVector3 &p, const UVector3 &v, double a, double b, double c, double &s1, double &s2)
{
return 0 || 1 || 2;
}
*/
int UIntersectingCone::LineHitsCone1(const UVector3& p, const UVector3& v, double& s1, double& s2)
{
double x0 = p.x, y0 = p.y, z0 = p.z;
double tx = v.x, ty = v.y, tz = v.z;
double a = tx * tx + ty * ty - UUtils::sqr(B * tz);
double b = 2 * (x0 * tx + y0 * ty - (A * B + B * B * z0) * tz);
double c = x0 * x0 + y0 * y0 - UUtils::sqr(A + B * z0);
double radical = b * b - 4 * a * c;
double radicalSqrt;
double minRadical = 1E-6 * std::fabs(b);
if (radical < -minRadical)
{
return 0; // No solution
}
if (radical < minRadical)
{
//
// The radical is roughly zero: check for special, very rare, cases
//
if (std::fabs(a) > EpsilonQuad)
{
if (B == 0.)
{
return 0;
}
if (std::fabs(x0 * ty - y0 * tx) < std::fabs(1E-6 / B))
{
s1 = -0.5 * b / a;
return 1;
}
return 0;
}
radicalSqrt = radical; //TODO: check this case
}
else
{
radicalSqrt = std::sqrt(radical);
}
if (a > EpsilonQuad)
{
double sa, sb, q = -0.5 * (b + (b < 0 ? -radicalSqrt : +radicalSqrt));
sa = q / a;
sb = c / q;
if (sa < sb)
{
s1 = sa;
s2 = sb;
}
else
{
s1 = sb;
s2 = sa;
}
if (A + B * (z0 + (s1)*tz) < 0)
{
return 0;
}
// if ((z0 + (s1)*tz - A)/B < 0) { return 0; } // these lines are equivalent
return 2;
}
else if (a < -EpsilonQuad)
{
double sa, sb, q = -0.5 * (b + (b < 0 ? -radicalSqrt : +radicalSqrt));
sa = q / a;
sb = c / q;
s1 = (tz * B > 0) ^ (sa > sb) ? sb : sa;
return 1;
}
else if (std::fabs(b) < EpsilonQuad)
{
return 0;
}
else
{
s1 = -c / b;
if (A + B * (z0 + (s1)*tz) < 0)
{
return 0;
}
return 1;
}
}
int UIntersectingCone::LineHitsCone1Optimized(const UVector3& p, const UVector3& v, double& s1, double& s2)
{
double x0 = p.x, y0 = p.y, z0 = p.z;
double tx = v.x, ty = v.y, tz = v.z;
double a = tx * tx + ty * ty - UUtils::sqr(B * tz);
double b = 2 * (x0 * tx + y0 * ty - (A * B + B * B * z0) * tz);
double c = x0 * x0 + y0 * y0 - UUtils::sqr(A + B * z0);
double radical = b * b - 4 * a * c;
double minRadical = 1E-6 * std::fabs(b);
if (radical < -minRadical)
{
return 0; // No solution
}
if (std::fabs(a) > EpsilonQuad)
{
if (radical < minRadical)
{
//
// The radical is roughly zero: check for special, very rare, cases
//
if (B == 0.)
{
return 0;
}
if (std::fabs(x0 * ty - y0 * tx) < std::fabs(1E-6 / B))
{
s1 = -0.5 * b / a;
return 1;
}
return 0;
}
else
{
double radicalSqrt = std::sqrt(radical);
if (a > 0)
{
double sa, sb, q = -0.5 * (b + (b < 0 ? -radicalSqrt : +radicalSqrt));
sa = q / a;
sb = c / q;
if (sa < sb)
{
s1 = sa;
s2 = sb;
}
else
{
s1 = sb;
s2 = sa;
}
if (A + B * (z0 + (s1)*tz) < 0)
{
return 0;
}
// if ((z0 + (s1)*tz - A)/B < 0) { return 0; } // these lines are equivalent
return 2;
}
else
{
double sa, sb, q = -0.5 * (b + (b < 0 ? -radicalSqrt : +radicalSqrt));
sa = q / a;
sb = c / q;
s1 = (tz * B > 0) ^ (sa > sb) ? sb : sa;
return 1;
}
}
}
if (std::fabs(b) < EpsilonQuad)
{
return 0;
}
else
{
s1 = -c / b;
if (A + B * (z0 + (s1)*tz) < 0)
{
return 0;
}
return 1;
}
}
//
// LineHitsCone2
//
// See comments under LineHitsCone1. In this routine, case2, we have:
//
// Z = A + B*R
//
// The solution is still quadratic:
//
// a = tz**2 - B*B*(tx**2 + ty**2)
//
// b = 2*( (z0-A)*tz - B*B*(x0*tx+y0*ty) )
//
// c = ( (z0-A)**2 - B*B*(x0**2 + y0**2) )
//
// The rest is much the same, except some details.
//
// a > 0 now means we intersect only once in the correct hemisphere.
//
// a > 0 ? We only want solution which produces R > 0.
// since R = (z0+s*tz-A)/B, for tz/B > 0, this is the largest s
// for tz/B < 0, this is the smallest s
// thus, same as in case 1 ( since sign(tz/B) = sign(tz*B) )
//
int UIntersectingCone::LineHitsCone2(const UVector3& p,
const UVector3& v,
double& s1, double& s2)
{
double x0 = p.x, y0 = p.y, z0 = p.z;
double tx = v.x, ty = v.y, tz = v.z;
// Special case which might not be so rare: B = 0 (precisely)
//
if (B == 0)
{
if (std::fabs(tz) < EpsilonQuad)
{
return 0;
}
s1 = (A - z0) / tz;
return 1;
}
double B2 = B * B;
double a = tz * tz - B2 * (tx * tx + ty * ty);
double b = 2 * ((z0 - A) * tz - B2 * (x0 * tx + y0 * ty));
double c = UUtils::sqr(z0 - A) - B2 * (x0 * x0 + y0 * y0);
double radical = b * b - 4 * a * c;
if (radical < -1E-6 * std::fabs(b))
{
return 0; // No solution
}
if (radical < 1E-6 * std::fabs(b))
{
//
// The radical is roughly zero: check for special, very rare, cases
//
if (std::fabs(a) > EpsilonQuad)
{
if (std::fabs(x0 * ty - y0 * tx) < std::fabs(1E-6 / B))
{
s1 = -0.5 * b / a;
return 1;
}
return 0;
}
}
else
{
radical = std::sqrt(radical);
}
if (a < -EpsilonQuad)
{
double sa, sb, q = -0.5 * (b + (b < 0 ? -radical : +radical));
sa = q / a;
sb = c / q;
if (sa < sb)
{
s1 = sa;
s2 = sb;
}
else
{
s1 = sb;
s2 = sa;
}
if ((z0 + (s1)*tz - A) / B < 0)
{
return 0;
}
return 2;
}
else if (a > EpsilonQuad)
{
double sa, sb, q = -0.5 * (b + (b < 0 ? -radical : +radical));
sa = q / a;
sb = c / q;
s1 = (tz * B > 0) ^ (sa > sb) ? sb : sa;
return 1;
}
else if (std::fabs(b) < EpsilonQuad)
{
return 0;
}
else
{
s1 = -c / b;
if ((z0 + (s1)*tz - A) / B < 0)
{
return 0;
}
return 1;
}
}
+541
View File
@@ -0,0 +1,541 @@
//
// ********************************************************************
// * This Software is part of the AIDA Unified Solids Library package *
// * See: https://aidasoft.web.cern.ch/USolids *
// ********************************************************************
//
// $Id:$
//
// --------------------------------------------------------------------
//
// UOrb
//
// 19.10.12 Marek Gayer
// Created from original implementation in Geant4
// --------------------------------------------------------------------
#include <cmath>
#include <iostream>
#include "UOrb.hh"
#include "UUtils.hh"
using namespace std;
//______________________________________________________________________________
UOrb::UOrb(const std::string& name, double r)
: VUSolid(name), fR(r), fCubicVolume(0), fSurfaceArea(0)
{
const double epsilon = 2.e-11; // relative tolerance of fR
// Check radius
//
if (r < 10 * VUSolid::fgTolerance) // cartesian tolerance
{
UUtils::Exception("G4Orb::G4Orb()", "InvalidSetup", FatalErrorInArguments, 1, "Invalid radius > 10*kCarTolerance.");
}
// VUSolid::fRTolerance is radial tolerance (note: half of G4 tolerance)
fRTolerance = max(VUSolid::frTolerance, epsilon * r);
}
//______________________________________________________________________________
/**
*
* Return whether point inside/outside/on surface
* Split into radius checks
*
* Classify point location with respect to solid:
* o eInside - inside the solid
* o eSurface - close to surface within tolerance
* o eOutside - outside the solid
*/
// ok
VUSolid::EnumInside UOrb::Inside(const UVector3& p) const
{
double rad2 = p.x * p.x + p.y * p.y + p.z * p.z;
// if (false) double rad = sqrt(rad2);
double tolRMax = fR - fRTolerance * 0.5;
// Check radial surface
double tolRMax2 = tolRMax * tolRMax;
if (rad2 <= tolRMax2)
return eInside;
else
{
tolRMax = fR + fRTolerance * 0.5;
tolRMax2 = tolRMax * tolRMax;
if (rad2 <= tolRMax2)
return eSurface;
else
return eOutside;
}
}
/*
* Computes distance from a point presumably outside the solid to the solid
* surface. Ignores first surface if the point is actually inside. Early return
* infinity in case the safety to any surface is found greater than the proposed
* step aPstep.
* The normal vector to the crossed surface is filled only in case the Orb is
* crossed, otherwise aNormal.IsNull() is true.
*/
double UOrb::DistanceToIn(const UVector3& p,
const UVector3& v,
// UVector3 &aNormal,
double /*aPstep*/) const
{
double snxt = UUtils::kInfinity; // snxt = default return value
double rad, pDotV3d; // , tolORMax2, tolIRMax2;
double c, d2, s = UUtils::kInfinity;
const double dRmax = 100.*fR;
// General Precalcs
rad = sqrt(p.x * p.x + p.y * p.y + p.z * p.z);
pDotV3d = p.x * v.x + p.y * v.y + p.z * v.z;
// Radial Precalcs
// tolORMax2 = (fR+fRTolerance*0.5)*(fR+fRTolerance*0.5);
// tolIRMax2 = (fR-fRTolerance*0.5)*(fR-fRTolerance*0.5);
// Outer spherical shell intersection
// - Only if outside tolerant fR
// - Check for if inside and outer G4Orb heading through solid (-> 0)
// - No intersect -> no intersection with G4Orb
//
// Shell eqn: x^2+y^2+z^2 = RSPH^2
//
// => (px+svx)^2+(py+svy)^2+(pz+svz)^2=R^2
//
// => (px^2+py^2+pz^2) +2s(pxvx+pyvy+pzvz)+s^2(vx^2+vy^2+vz^2)=R^2
// => rad2 +2s(pDotV3d) +s^2 =R^2
//
// => s=-pDotV3d+-sqrt(pDotV3d^2-(rad2-R^2))
c = (rad - fR) * (rad + fR); // c = (rad2-R^2))
if (rad > fR - fRTolerance * 0.5) // not inside in terms of Inside(p)
{
if (c > fRTolerance * fR)
{
// If outside tolerant boundary of outer G4Orb in terms of c
// [ should be sqrt(rad2) - fR > fRTolerance*0.5 ]
d2 = pDotV3d * pDotV3d - c;
if (d2 >= 0)
{
s = -pDotV3d - sqrt(d2); // ok! = [ ( -2 p dot v) +- sqrt [(-2p dot v)2 - 4*(rad - fR)*(rad + fR)] ] / 2
// pDotV3d must be positive always, if not use alternative http://en.wikipedia.org/wiki/Quadratic_equation#Alternative_quadratic_formula
if (s >= 0)
{
if (s > dRmax) // Avoid rounding errors due to precision issues seen on
{
// 64 bits systems. Split long distances and recompute
double fTerm = s - fmod(s, dRmax);
s = fTerm + DistanceToIn(p + fTerm * v, v);
}
return snxt = s;
}
}
else // No intersection with UOrb
{
return snxt = UUtils::kInfinity;
}
}
else // not outside in terms of c
{
if (c > -fRTolerance * fR) // on surface
{
d2 = pDotV3d * pDotV3d - c;
if ((d2 < fRTolerance * fR) || (pDotV3d >= 0)) // pDotV3d = cos si >= 0
{
return snxt = UUtils::kInfinity;
}
else
{
return snxt = 0.;
}
}
}
}
#ifdef UDEBUG
else // inside ???
{
UUtils::Exception("UOrb::DistanceToIn(p,v)", "Notification", Warning, 1, "Point p is inside !?");
}
#endif
return snxt;
}
double UOrb::DistanceToOutForOutsidePoints(const UVector3& p, const UVector3& v, UVector3& n) const
{
double distanceIn = DistanceToIn(p, v);
UVector3 shift = distanceIn * v;
UVector3 surfacePoint = p + shift;
UVector3 normal;
((UOrb&)*this).Normal(surfacePoint, normal);
double dot = normal.Dot(v);
if (dot > 0) return 0;
else
{
bool convex;
double distanceOut = DistanceToOut(surfacePoint, v, n, convex);
return distanceIn + distanceOut;
}
}
/*
* Computes distance from a point presumably intside the solid to the solid
* surface. Ignores first surface along each axis systematically (for points
* inside or outside. Early returns zero in case the second surface is behind
* the starting point.
* o The proposed step is ignored.
* o The normal vector to the crossed surface is always filled.
* ______________________________________________________________________________
*/
double UOrb::DistanceToOut(const UVector3& p, const UVector3& v,
UVector3& n, bool& convex, double /*aPstep*/) const
{
double snxt = 0; // snxt: distance to next surface, is default return value
bool notOutside = false;
convex = true; // orb is always convex, if we leave surface of Orb, we will neber bump on the orb again ...
double rad2, pDotV3d;
double xi, yi, zi; // Intersection point
double c, d2;
rad2 = p.x * p.x + p.y * p.y + p.z * p.z;
pDotV3d = p.x * v.x + p.y * v.y + p.z * v.z;
// Radial Intersection from UOrb::DistanceToIn
//
// Outer spherical shell intersection
// - Only if outside tolerant fR
// - Check for if inside and outer UOrb heading through solid (-> 0)
// - No intersect -> no intersection with UOrb
//
// Shell eqn: x^2+y^2+z^2=RSPH^2
//
// => (px+svx)^2+(py+svy)^2+(pz+svz)^2=R^2
//
// => (px^2+py^2+pz^2) +2s(pxvx+pyvy+pzvz)+s^2(vx^2+vy^2+vz^2)=R^2
// => rad2 +2s(pDotV3d) +s^2 =R^2
//
// => s=-pDotV3d+-sqrt(pDotV3d^2-(rad2-R^2))
const double rPlus = fR + fRTolerance;
double rad = sqrt(rad2);
if (rad <= rPlus)
{
c = (rad - fR) * (rad + fR); // rad2 - fR2
if (c < fRTolerance * fR)
{
// Within tolerant Outer radius
//
// The test is
// rad - fR < 0.5*fRTolerance
// => rad < fR + 0.5*kRadTol
// => rad2 < (fR + 0.5*kRadTol)^2
// => rad2 < fR^2 + 2.*0.5*fR*kRadTol + 0.25*kRadTol*kRadTol
// => rad2 - fR^2 <~ fR*kRadTol
d2 = pDotV3d * pDotV3d - c;
if ((c > -2 * fRTolerance * fR) && // => point is on tolerant surface (i.e. within +- tolerance)
((pDotV3d >= 0) || (d2 < 0))) // if (pDotV3d >= 0 ) => leaving outside from Rmax; i.e. from surface
// not re-entering
// if (d2 < 0) => it means the point is already outside
{
// if(calcNorm) // NOTE: we do not have this variable, calcNorm is true always
{
// *validNorm = true; // NOTE: we do not have this variable, probably always true
n = UVector3(p.x / fR, p.y / fR, p.z / fR);
}
return snxt = 0;
}
else
{
// we are inside, with + version of quadratic eq. solution we calculate solution for distance
snxt = -pDotV3d + sqrt(d2); // second root since inside Rmax
// the solution is safe because pDotV3d is negative
// c alternative formula, see http://en.wikipedia.org/wiki/Quadratic_equation#Alternative_quadratic_formula
// is not neccessary in this case
notOutside = true;
}
}
}
else // p is outside ???
{
// Rule 2: DistanceToOut
// Surface points = 0
// Outside points: If pointing outwards (dot product with normal positive) return 0, otherwise ignore first surface, another surface should always be on the direction line, use instead distance to this one.
// double res = DistanceToOutForOutsidePoints(p, v, n);
cout.precision(16);
cout << endl;
// DumpInfo();
cout << "Position:" << endl << endl;
cout << "p.x() = " << p.x << endl;
cout << "p.y() = " << p.y << endl;
cout << "p.z() = " << p.z << endl << endl;
cout << "Rp = " << sqrt(p.x * p.x + p.y * p.y + p.z * p.z) << endl << endl;
cout << "Direction:" << endl << endl;
cout << "v.x() = " << v.x << endl;
cout << "v.y() = " << v.y << endl;
cout << "v.z() = " << v.z << endl << endl;
cout << "Proposed distance :" << endl << endl;
cout << "snxt = " << snxt << endl << endl;
cout.precision(6);
UUtils::Exception("UOrb::DistanceToOut(p,v,..)", "Notification",
Warning, 1, "Logic error: snxt = kInfinity ???");
}
// if (calcNorm) // Output switch operator
{
if (notOutside)
{
xi = p.x + snxt * v.x; // we move to the point on surface, then return normal at that point which for orb, see method bool UOrb::Normal( const UVector3& p, UVector3 &n)
yi = p.y + snxt * v.y;
zi = p.z + snxt * v.z;
n = UVector3(xi / fR, yi / fR, zi / fR); // we return normalized vector
}
else
{
cout.precision(16);
cout << endl;
// DumpInfo();
cout << "Position:" << endl << endl;
cout << "p.x() = " << p.x << " mm" << endl;
cout << "p.y() = " << p.y << " mm" << endl;
cout << "p.z() = " << p.z << " mm" << endl << endl;
cout << "Direction:" << endl << endl;
cout << "v.x() = " << v.x << endl;
cout << "v.y() = " << v.y << endl;
cout << "v.z() = " << v.z << endl << endl;
cout << "Proposed distance :" << endl << endl;
cout << "snxt = " << snxt << " mm" << endl << endl;
cout.precision(6);
UUtils::Exception("UOrb::DistanceToOut(p,v,..)", "Notification", Warning, 1, "Undefined side for valid surface normal to solid.");
}
}
return snxt;
}
/*
* Estimates the isotropic safety from a point inside the current solid to any
* of its surfaces. The algorithm may be accurate or should provide a fast
* underestimate.
* ______________________________________________________________________________
* Note: In geant4, these methods are DistanceToOut, without given direction
* Note: ??? Should not Return 0 anymore if point outside, just the value
* OK
*/
double UOrb::SafetyFromInside(const UVector3& p, bool /*aAccurate*/) const
{
/////////////////////////////////////////////////////////////////////////
//
// Calculate distance (<=actual) to closest surface of shape from inside
double safe = 0.0, rad = sqrt(p.x * p.x + p.y * p.y + p.z * p.z);
#ifdef UDEBUG
if (Inside(p) == kOutside)
{
// int oldprc = cout.precision(16);
cout << endl;
// DumpInfo();
cout << "Position:" << endl << endl;
cout << "p.x = " << p.x << endl;
cout << "p.y = " << p.y << endl;
cout << "p.z = " << p.z << endl << endl;
// cout.precision(oldprc);
UUtils::Exception("UOrb::DistanceToOut(p)", "Notification", Warning, 1,
"Point p is outside !?");
}
#endif
safe = fR - rad;
if (safe < 0.) safe = 0.;
return safe;
}
/*
* Estimates the isotropic safety from a point outside the current solid to any
* of its surfaces. The algorithm may be accurate or should provide a fast
* underestimate.
* Note: In geant4, this method is equivalent to DistanceToIn, without given direction
* ______________________________________________________________________________
*
* Calculate distance (<= actual) to closest surface of shape from outside
* - Calculate distance to radial plane
* - Return 0 if point inside
* OK
*/
double UOrb::SafetyFromOutside(const UVector3& p, bool /*aAccurate*/) const
{
double safe = 0.0;
double rad = sqrt(p.x * p.x + p.y * p.y + p.z * p.z);
safe = rad - fR;
if (safe < 0)
{
safe = 0.;
}
return safe;
}
/**
*
* Return unit normal of surface closest to p
*
* From http://lists.trolltech.com/qt-interest/2002-09/thread01124-0.html :
* > does anybody here have an algorithm to calculate the normal vector in a
* > given point in space (x, y, z) in a sphere? I know that it's not about qt
* > but i'll like very mutch the help.
* It's simply the connecting vector from the centre of the sphere to the point
* (other way around for inward normals) obtained through vector subtraction,
* normalized to unity.
*
* You really should get an algebra book though, as you are bound to encounter
* more of these problems in a 3d application.
*/
bool UOrb::Normal(const UVector3& p, UVector3& n) const
{
double rad2 = p.x * p.x + p.y * p.y + p.z * p.z;
double rad = sqrt(rad2);
n = UVector3(p.x / rad, p.y / rad, p.z / rad);
double tolRMaxP = fR + fRTolerance;
double tolRMaxM = fR - fRTolerance;
// Check radial surface
bool result = ((rad2 <= tolRMaxP * tolRMaxP) && (rad2 >= tolRMaxM * tolRMaxM)); // means we are on surface
return result;
}
/**
* Returns extent of the solid along a given cartesian axis
* OK
*/
void UOrb::Extent(UVector3& aMin, UVector3& aMax) const
{
aMin.Set(-fR);
aMax.Set(fR);
}
//////////////////////////////////////////////////////////////////////////
//
// Stream object contents to an output stream
std::ostream& UOrb::StreamInfo(std::ostream& os) const
{
int oldprc = os.precision(16);
os << "-----------------------------------------------------------\n"
<< " *** Dump for solid - " << GetName() << " ***\n"
<< " ===================================================\n"
<< " Solid type: UOrb\n"
<< " Parameters: \n"
<< " outer radius: " << fR << " mm \n"
<< "-----------------------------------------------------------\n";
os.precision(oldprc);
return os;
}
/////////////////////////////////////////////////////////////////////////
//
// GetPointOnSurface
UVector3 UOrb::GetPointOnSurface() const
{
// generate a random number from zero to 2UUtils::kPi...
//
double phi = UUtils::Random(0., 2.*UUtils::kPi);
double cosphi = std::cos(phi);
double sinphi = std::sin(phi);
// generate a random point uniform in area
double costheta = UUtils::Random(-1., 1.);
double sintheta = std::sqrt(1. - UUtils::sqr(costheta));
return UVector3(fR * sintheta * cosphi, fR * sintheta * sinphi, fR * costheta);
}
VUSolid* UOrb:: Clone() const
{
return new UOrb(GetName(), fR);
}
// Copy constructor
UOrb::UOrb(const UOrb& rhs)
: VUSolid(rhs), fR(rhs.fR), fRTolerance(rhs.fRTolerance), fCubicVolume(rhs.fCubicVolume), fSurfaceArea(rhs.fSurfaceArea)
{
}
//////////////////////////////////////////////////////////////////////////
//
// Assignment operator
UOrb& UOrb::operator = (const UOrb& rhs)
{
// Check assignment to self
//
if (this == &rhs)
{
return *this;
}
// Copy base class data
//
VUSolid::operator=(rhs);
// Copy data
//
fR = rhs.fR;
fRTolerance = rhs.fRTolerance;
fCubicVolume = rhs.fCubicVolume;
fSurfaceArea = rhs.fSurfaceArea;
return *this;
}
//////////////////////////////////////////////////////////////////////////
//
// Get Parameters List for visualisation
void UOrb::GetParametersList(int, double* aArray)const
{
aArray[0] = GetRadius();
}
//////////////////////////////////////////////////////////////////////////
//
// Get Entity Type
UGeometryType UOrb::GetEntityType() const
{
return "Orb";
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,948 @@
//
// ********************************************************************
// * This Software is part of the AIDA Unified Solids Library package *
// * See: https://aidasoft.web.cern.ch/USolids *
// ********************************************************************
//
// $Id:$
//
// --------------------------------------------------------------------
//
// UPolyhedra
//
// --------------------------------------------------------------------
//
// To be done:
// * Cracks: there are probably small cracks in the seams between the
// phi face (UPolyPhiFace) and sides (UPolyhedraSide) that are not
// entirely leakproof. Also, I am not sure all vertices are leak proof.
// * Many optimizations are possible, but not implemented.
// * Visualization needs to be updated outside of this routine.
//
// Utility classes:
// * UEnclosingCylinder: I decided a quick check of geometry would be a
// good idea (for CPU speed). If the quick check fails, the regular
// full-blown UVCSGfaceted version is invoked.
// * UReduciblePolygon: Really meant as a check of input parameters,
// this utility class also "converts" the GEANT3-like PGON/PCON
// arguments into the newer ones.
// Both these classes are implemented outside this file because they are
// shared with UPolycone.
//
// 19.09.13 Marek Gayer
// Created from original implementation in Geant4
// --------------------------------------------------------------------
#include "UUtils.hh"
#include <string>
#include <cmath>
#include <sstream>
#include "UPolyhedra.hh"
#include "UPolyhedraSide.hh"
#include "UPolyPhiFace.hh"
#include "UEnclosingCylinder.hh"
#include "UReduciblePolygon.hh"
using namespace std;
UPolyhedra::UPolyhedra(const std::string& name,
double phiStart,
double thePhiTotal,
int thefNumSide,
int numZPlanes,
const double zPlane[],
const double rInner[],
const double rOuter[])
: UVCSGfaceted(name)
{
Init(phiStart, thePhiTotal, thefNumSide, numZPlanes, zPlane, rInner, rOuter);
}
//
// Constructor (GEANT3 style parameters)
//
// GEANT3 PGON radii are specified in the distance to the norm of each face.
//
void UPolyhedra::Init(
double phiStart,
double thePhiTotal,
int thefNumSide,
int numZPlanes,
const double zPlane[],
const double rInner[],
const double rOuter[])
{
fGenericPgon = false;
if (thefNumSide <= 0)
{
std::ostringstream message;
message << "Solid must have at least one side - " << GetName() << std::endl
<< " No sides specified !";
UUtils::Exception("UPolyhedra::UPolyhedra()", "GeomSolids0002",
FatalErrorInArguments, 1, message.str().c_str());
}
//
// Calculate conversion factor from G3 radius to U radius
//
double phiTotal = thePhiTotal;
if ((phiTotal <= 0) || (phiTotal >= 2 * UUtils::kPi * (1 - DBL_EPSILON)))
{
phiTotal = 2 * UUtils::kPi;
}
double convertRad = std::cos(0.5 * phiTotal / thefNumSide);
//
// Some historical stuff
//
// fOriginalParameters = new UPolyhedraHistorical;
fOriginalParameters.fNumSide = thefNumSide;
fOriginalParameters.fStartAngle = phiStart;
fOriginalParameters.fOpeningAngle = phiTotal;
fOriginalParameters.fNumZPlanes = numZPlanes;
fOriginalParameters.fZValues.resize(numZPlanes);
fOriginalParameters.Rmin.resize(numZPlanes);
fOriginalParameters.Rmax.resize(numZPlanes);
int i;
for (i = 0; i < numZPlanes; i++)
{
if ((i < numZPlanes - 1) && (zPlane[i] == zPlane[i + 1]))
{
if ((rInner[i] > rOuter[i + 1])
|| (rInner[i + 1] > rOuter[i]))
{
std::ostringstream message;
message << "Cannot create a Polyhedra with no contiguous segments."
<< std::endl
<< " Segments are not contiguous !" << std::endl
<< " rMin[" << i << "] = " << rInner[i]
<< " -- rMax[" << i + 1 << "] = " << rOuter[i + 1] << std::endl
<< " rMin[" << i + 1 << "] = " << rInner[i + 1]
<< " -- rMax[" << i << "] = " << rOuter[i];
UUtils::Exception("UPolyhedra::UPolyhedra()", "GeomSolids0002",
FatalErrorInArguments, 1, message.str().c_str());
}
}
fOriginalParameters.fZValues[i] = zPlane[i];
fOriginalParameters.Rmin[i] = rInner[i] / convertRad;
fOriginalParameters.Rmax[i] = rOuter[i] / convertRad;
}
//
// Build RZ polygon using special PCON/PGON GEANT3 constructor
//
UReduciblePolygon* rz =
new UReduciblePolygon(rInner, rOuter, zPlane, numZPlanes);
rz->ScaleA(1 / convertRad);
//
// Do the real work
//
Create(phiStart, phiTotal, thefNumSide, rz);
delete rz;
}
//
// Constructor (generic parameters)
//
UPolyhedra::UPolyhedra(const std::string& name,
double phiStart,
double phiTotal,
int thefNumSide,
int numRZ,
const double r[],
const double z[])
: UVCSGfaceted(name), fGenericPgon(true)
{
UReduciblePolygon* rz = new UReduciblePolygon(r, z, numRZ);
Create(phiStart, phiTotal, thefNumSide, rz);
// Set fOriginalParameters struct for consistency
//
SetOriginalParameters();
delete rz;
}
//
// Create
//
// Generic create routine, called by each constructor
// after conversion of arguments
//
void UPolyhedra::Create(double phiStart,
double phiTotal,
int thefNumSide,
UReduciblePolygon* rz)
{
//
// Perform checks of rz values
//
if (rz->Amin() < 0.0)
{
std::ostringstream message;
message << "Illegal input parameters - " << GetName() << std::endl
<< " All R values must be >= 0 !";
UUtils::Exception("UPolyhedra::Create()", "GeomSolids0002",
FatalErrorInArguments, 1, message.str().c_str());
}
double rzArea = rz->Area();
if (rzArea < -VUSolid::Tolerance())
rz->ReverseOrder();
else if (rzArea < -VUSolid::Tolerance())
{
std::ostringstream message;
message << "Illegal input parameters - " << GetName() << std::endl
<< " R/Z Cross section is zero or near zero: " << rzArea;
UUtils::Exception("UPolyhedra::Create()", "GeomSolids0002",
FatalErrorInArguments, 1, message.str().c_str());
}
if ((!rz->RemoveDuplicateVertices(VUSolid::Tolerance()))
|| (!rz->RemoveRedundantVertices(VUSolid::Tolerance())))
{
std::ostringstream message;
message << "Illegal input parameters - " << GetName() << std::endl
<< " Too few unique R/Z values !";
UUtils::Exception("UPolyhedra::Create()", "GeomSolids0002",
FatalErrorInArguments, 1, message.str().c_str());
}
if (rz->CrossesItself(1 / UUtils::kInfinity))
{
std::ostringstream message;
message << "Illegal input parameters - " << GetName() << std::endl
<< " R/Z segments Cross !";
UUtils::Exception("UPolyhedra::Create()", "GeomSolids0002",
FatalErrorInArguments, 1, message.str().c_str());
}
fNumCorner = rz->NumVertices();
fStartPhi = phiStart;
while (fStartPhi < 0) fStartPhi += 2 * UUtils::kPi;
//
// Phi opening? Account for some possible roundoff, and interpret
// nonsense value as representing no phi opening
//
if ((phiTotal <= 0) || (phiTotal > 2 * UUtils::kPi * (1 - DBL_EPSILON)))
{
fPhiIsOpen = false;
fEndPhi = phiStart + 2 * UUtils::kPi;
}
else
{
fPhiIsOpen = true;
//
// Convert phi into our convention
//
fEndPhi = phiStart + phiTotal;
while (fEndPhi < fStartPhi) fEndPhi += 2 * UUtils::kPi;
}
//
// Save number sides
//
fNumSides = thefNumSide;
//
// Allocate corner array.
//
fCorners = new UPolyhedraSideRZ[fNumCorner];
//
// Copy fCorners
//
UReduciblePolygonIterator iterRZ(rz);
UPolyhedraSideRZ* next = fCorners;
iterRZ.Begin();
do
{
next->r = iterRZ.GetA();
next->z = iterRZ.GetB();
}
while (++next, iterRZ.Next());
//
// Allocate face pointer array
//
numFace = fPhiIsOpen ? fNumCorner + 2 : fNumCorner;
faces = new UVCSGface*[numFace];
//
// Construct side faces
//
// To do so properly, we need to keep track of four successive RZ
// fCorners.
//
// But! Don't construct a face if both points are at zero radius!
//
UPolyhedraSideRZ* corner = fCorners,
*prev = fCorners + fNumCorner - 1,
*nextNext;
UVCSGface** face = faces;
do
{
next = corner + 1;
if (next >= fCorners + fNumCorner) next = fCorners;
nextNext = next + 1;
if (nextNext >= fCorners + fNumCorner) nextNext = fCorners;
if (corner->r < 1 / UUtils::kInfinity && next->r < 1 / UUtils::kInfinity) continue;
/*
// We must decide here if we can dare declare one of our faces
// as having a "valid" normal (i.e. allBehind = true). This
// is never possible if the face faces "inward" in r *unless*
// we have only one side
//
bool allBehind;
if ((corner->z > next->z) && (fNumSides > 1))
{
allBehind = false;
}
else
{
//
// Otherwise, it is only true if the line passing
// through the two points of the segment do not
// split the r/z Cross section
//
allBehind = !rz->BisectedBy( corner->r, corner->z,
next->r, next->z, VUSolid::Tolerance() );
}
*/
*face++ = new UPolyhedraSide(prev, corner, next, nextNext,
fNumSides, fStartPhi, fEndPhi - fStartPhi, fPhiIsOpen);
}
while (prev = corner, corner = next, corner > fCorners);
if (fPhiIsOpen)
{
//
// Construct phi open edges
//
*face++ = new UPolyPhiFace(rz, fStartPhi, phiTotal / fNumSides, fEndPhi);
*face++ = new UPolyPhiFace(rz, fEndPhi, phiTotal / fNumSides, fStartPhi);
}
//
// We might have dropped a face or two: recalculate numFace
//
numFace = face - faces;
//
// Make fEnclosingCylinder
//
/*
double mxy = rz->Amax();
double alfa = UUtils::kPi / fNumSides;
double r= rz->Amax();
if (fNumSides != 0)
{
// mxy *= std::sqrt(2.0); // this is old and wrong, works only for n = 4
double k = std::tan(alfa) * mxy;
double l = mxy / std::cos(alfa);
mxy = l;
r = l;
}
mxy += fgTolerance;
*/
fEnclosingCylinder =
new UEnclosingCylinder(rz->Amax(), rz->Bmax(), rz->Bmin(), fPhiIsOpen, phiStart, phiTotal);
InitVoxels(*rz, fEnclosingCylinder->radius);
fNoVoxels = fMaxSection < 2; // minimally, sections with at least numbers 0,1,2 values required, this corresponds to fMaxSection == 2
}
//
// Destructor
//
UPolyhedra::~UPolyhedra()
{
delete [] fCorners;
// if (fOriginalParameters) delete fOriginalParameters;
delete fEnclosingCylinder;
}
//
// Copy constructor
//
UPolyhedra::UPolyhedra(const UPolyhedra& source)
: UVCSGfaceted(source)
{
CopyStuff(source);
}
//
// Assignment operator
//
UPolyhedra& UPolyhedra::operator=(const UPolyhedra& source)
{
if (this == &source) return *this;
UVCSGfaceted::operator=(source);
delete [] fCorners;
// if (fOriginalParameters) delete fOriginalParameters;
delete fEnclosingCylinder;
CopyStuff(source);
return *this;
}
//
// CopyStuff
//
void UPolyhedra::CopyStuff(const UPolyhedra& source)
{
//
// Simple stuff
//
fNumSides = source.fNumSides;
fStartPhi = source.fStartPhi;
fEndPhi = source.fEndPhi;
fPhiIsOpen = source.fPhiIsOpen;
fNumCorner = source.fNumCorner;
fGenericPgon = source.fGenericPgon;
//
// The corner array
//
fCorners = new UPolyhedraSideRZ[fNumCorner];
UPolyhedraSideRZ* corn = fCorners,
*sourceCorn = source.fCorners;
do
{
*corn = *sourceCorn;
}
while (++sourceCorn, ++corn < fCorners + fNumCorner);
fOriginalParameters = source.fOriginalParameters;
//
// Enclosing cylinder
//
fEnclosingCylinder = new UEnclosingCylinder(*source.fEnclosingCylinder);
}
//
// Reset
//
// Recalculates and reshapes the solid, given pre-assigned scaled
// fOriginalParameters.
//
bool UPolyhedra::Reset()
{
if (fGenericPgon)
{
std::ostringstream message;
message << "Solid " << GetName() << " built using generic construct."
<< std::endl << "Not applicable to the generic construct !";
UUtils::Exception("UPolyhedra::Reset(,,)", "GeomSolids1001",
Warning, 1, message.str().c_str());
return 1;
}
//
// Clear old setup
//
UVCSGfaceted::DeleteStuff();
delete [] fCorners;
delete fEnclosingCylinder;
//
// Rebuild polyhedra
//
UReduciblePolygon* rz =
new UReduciblePolygon(&fOriginalParameters.Rmin[0],
&fOriginalParameters.Rmax[0],
&fOriginalParameters.fZValues[0],
fOriginalParameters.fNumZPlanes);
Create(fOriginalParameters.fStartAngle,
fOriginalParameters.fOpeningAngle,
fOriginalParameters.fNumSide, rz);
delete rz;
return 0;
}
//
// Inside
//
// This is an override of UVCSGfaceted::Inside, created in order
// to speed things up by first checking with UEnclosingCylinder.
//
VUSolid::EnumInside UPolyhedra::Inside(const UVector3& p) const
{
//
// Quick test
//
if (fEnclosingCylinder->MustBeOutside(p)) return eOutside;
//
// Long answer
//
return UVCSGfaceted::Inside(p);
}
//
// DistanceToIn
//
double UPolyhedra::SafetyFromOutside(const UVector3& aPoint, bool aAccurate) const
{
return UVCSGfaceted::SafetyFromOutside(aPoint, aAccurate);
}
//
// GetEntityType
//
UGeometryType UPolyhedra::GetEntityType() const
{
return std::string("Polyhedra");
}
//
// Make a clone of the object
//
VUSolid* UPolyhedra::Clone() const
{
return new UPolyhedra(*this);
}
//
// Stream object contents to an output stream
//
std::ostream& UPolyhedra::StreamInfo(std::ostream& os) const
{
int oldprc = os.precision(16);
os << "-----------------------------------------------------------\n"
<< " *** Dump for solid - " << GetName() << " ***\n"
<< " ===================================================\n"
<< " Solid type: UPolyhedra\n"
<< " Parameters: \n"
<< " starting phi angle : " << fStartPhi / (UUtils::kPi / 180.0) << " degrees \n"
<< " ending phi angle : " << fEndPhi / (UUtils::kPi / 180.0) << " degrees \n";
int i = 0;
if (!fGenericPgon)
{
int numPlanes = fOriginalParameters.fNumZPlanes;
os << " number of Z planes: " << numPlanes << "\n"
<< " Z values: \n";
for (i = 0; i < numPlanes; i++)
{
os << " Z plane " << i << ": "
<< fOriginalParameters.fZValues[i] << "\n";
}
os << " Tangent distances to inner surface (Rmin): \n";
for (i = 0; i < numPlanes; i++)
{
os << " Z plane " << i << ": "
<< fOriginalParameters.Rmin[i] << "\n";
}
os << " Tangent distances to outer surface (Rmax): \n";
for (i = 0; i < numPlanes; i++)
{
os << " Z plane " << i << ": "
<< fOriginalParameters.Rmax[i] << "\n";
}
}
os << " number of RZ points: " << fNumCorner << "\n"
<< " RZ values (fCorners): \n";
for (i = 0; i < fNumCorner; i++)
{
os << " "
<< fCorners[i].r << ", " << fCorners[i].z << "\n";
}
os << "-----------------------------------------------------------\n";
os.precision(oldprc);
return os;
}
//
// GetPointOnPlane
//
// Auxiliary method for get point on surface
//
UVector3 UPolyhedra::GetPointOnPlane(UVector3 p0, UVector3 p1,
UVector3 p2, UVector3 p3) const
{
double lambda1, lambda2, chose, aOne, aTwo;
UVector3 t, u, v, w, Area, normal;
aOne = 1.;
aTwo = 1.;
t = p1 - p0;
u = p2 - p1;
v = p3 - p2;
w = p0 - p3;
chose = UUtils::Random(0., aOne + aTwo);
if ((chose >= 0.) && (chose < aOne))
{
lambda1 = UUtils::Random(0., 1.);
lambda2 = UUtils::Random(0., lambda1);
return (p2 + lambda1 * v + lambda2 * w);
}
lambda1 = UUtils::Random(0., 1.);
lambda2 = UUtils::Random(0., lambda1);
return (p0 + lambda1 * t + lambda2 * u);
}
//
// GetPointOnTriangle
//
// Auxiliary method for get point on surface
//
UVector3 UPolyhedra::GetPointOnTriangle(UVector3 p1,
UVector3 p2,
UVector3 p3) const
{
double lambda1, lambda2;
UVector3 v = p3 - p1, w = p1 - p2;
lambda1 = UUtils::Random(0., 1.);
lambda2 = UUtils::Random(0., lambda1);
return (p2 + lambda1 * w + lambda2 * v);
}
//
// GetPointOnSurface
//
UVector3 UPolyhedra::GetPointOnSurface() const
{
if (!fGenericPgon) // Polyhedra by faces
{
int j, numPlanes = fOriginalParameters.fNumZPlanes, Flag = 0;
double chose, totArea = 0., Achose1, Achose2,
rad1, rad2, sinphi1, sinphi2, cosphi1, cosphi2;
double a, b, l2, rang, totalPhi, ksi,
area, aTop = 0., aBottom = 0., zVal = 0.;
UVector3 p0, p1, p2, p3;
std::vector<double> aVector1;
std::vector<double> aVector2;
std::vector<double> aVector3;
totalPhi = (fPhiIsOpen) ? (fEndPhi - fStartPhi) : 2 * UUtils::kPi;
ksi = totalPhi / fNumSides;
double cosksi = std::cos(ksi / 2.);
// Below we generate the areas relevant to our solid
//
for (j = 0; j < numPlanes - 1; j++)
{
a = fOriginalParameters.Rmax[j + 1];
b = fOriginalParameters.Rmax[j];
l2 = UUtils::sqr(fOriginalParameters.fZValues[j]
- fOriginalParameters.fZValues[j + 1]) + UUtils::sqr(b - a);
area = std::sqrt(l2 - UUtils::sqr((a - b) * cosksi)) * (a + b) * cosksi;
aVector1.push_back(area);
}
for (j = 0; j < numPlanes - 1; j++)
{
a = fOriginalParameters.Rmin[j + 1]; //*cosksi;
b = fOriginalParameters.Rmin[j];//*cosksi;
l2 = UUtils::sqr(fOriginalParameters.fZValues[j]
- fOriginalParameters.fZValues[j + 1]) + UUtils::sqr(b - a);
area = std::sqrt(l2 - UUtils::sqr((a - b) * cosksi)) * (a + b) * cosksi;
aVector2.push_back(area);
}
for (j = 0; j < numPlanes - 1; j++)
{
if (fPhiIsOpen == true)
{
aVector3.push_back(0.5 * (fOriginalParameters.Rmax[j]
- fOriginalParameters.Rmin[j]
+ fOriginalParameters.Rmax[j + 1]
- fOriginalParameters.Rmin[j + 1])
*std::fabs(fOriginalParameters.fZValues[j + 1]
- fOriginalParameters.fZValues[j]));
}
else
{
aVector3.push_back(0.);
}
}
for (j = 0; j < numPlanes - 1; j++)
{
totArea += fNumSides * (aVector1[j] + aVector2[j]) + 2.*aVector3[j];
}
// Must include top and bottom areas
//
if (fOriginalParameters.Rmax[numPlanes - 1] != 0.)
{
a = fOriginalParameters.Rmax[numPlanes - 1];
b = fOriginalParameters.Rmin[numPlanes - 1];
l2 = UUtils::sqr(a - b);
aTop = std::sqrt(l2 - UUtils::sqr((a - b) * cosksi)) * (a + b) * cosksi;
}
if (fOriginalParameters.Rmax[0] != 0.)
{
a = fOriginalParameters.Rmax[0];
b = fOriginalParameters.Rmin[0];
l2 = UUtils::sqr(a - b);
aBottom = std::sqrt(l2 - UUtils::sqr((a - b) * cosksi)) * (a + b) * cosksi;
}
Achose1 = 0.;
Achose2 = fNumSides * (aVector1[0] + aVector2[0]) + 2.*aVector3[0];
chose = UUtils::Random(0., totArea + aTop + aBottom);
if ((chose >= 0.) && (chose < aTop + aBottom))
{
chose = UUtils::Random(fStartPhi, fStartPhi + totalPhi);
rang = std::floor((chose - fStartPhi) / ksi - 0.01);
if (rang < 0)
{
rang = 0;
}
rang = std::fabs(rang);
sinphi1 = std::sin(fStartPhi + rang * ksi);
sinphi2 = std::sin(fStartPhi + (rang + 1) * ksi);
cosphi1 = std::cos(fStartPhi + rang * ksi);
cosphi2 = std::cos(fStartPhi + (rang + 1) * ksi);
chose = UUtils::Random(0., aTop + aBottom);
if (chose >= 0. && chose < aTop)
{
rad1 = fOriginalParameters.Rmin[numPlanes - 1];
rad2 = fOriginalParameters.Rmax[numPlanes - 1];
zVal = fOriginalParameters.fZValues[numPlanes - 1];
}
else
{
rad1 = fOriginalParameters.Rmin[0];
rad2 = fOriginalParameters.Rmax[0];
zVal = fOriginalParameters.fZValues[0];
}
p0 = UVector3(rad1 * cosphi1, rad1 * sinphi1, zVal);
p1 = UVector3(rad2 * cosphi1, rad2 * sinphi1, zVal);
p2 = UVector3(rad2 * cosphi2, rad2 * sinphi2, zVal);
p3 = UVector3(rad1 * cosphi2, rad1 * sinphi2, zVal);
return GetPointOnPlane(p0, p1, p2, p3);
}
else
{
for (j = 0; j < numPlanes - 1; j++)
{
if (((chose >= Achose1) && (chose < Achose2)) || (j == numPlanes - 2))
{
Flag = j;
break;
}
Achose1 += fNumSides * (aVector1[j] + aVector2[j]) + 2.*aVector3[j];
Achose2 = Achose1 + fNumSides * (aVector1[j + 1] + aVector2[j + 1])
+ 2.*aVector3[j + 1];
}
}
// At this point we have chosen a subsection
// between to adjacent plane cuts...
j = Flag;
totArea = fNumSides * (aVector1[j] + aVector2[j]) + 2.*aVector3[j];
chose = UUtils::Random(0., totArea);
if ((chose >= 0.) && (chose < fNumSides * aVector1[j]))
{
chose = UUtils::Random(fStartPhi, fStartPhi + totalPhi);
rang = std::floor((chose - fStartPhi) / ksi - 0.01);
if (rang < 0)
{
rang = 0;
}
rang = std::fabs(rang);
rad1 = fOriginalParameters.Rmax[j];
rad2 = fOriginalParameters.Rmax[j + 1];
sinphi1 = std::sin(fStartPhi + rang * ksi);
sinphi2 = std::sin(fStartPhi + (rang + 1) * ksi);
cosphi1 = std::cos(fStartPhi + rang * ksi);
cosphi2 = std::cos(fStartPhi + (rang + 1) * ksi);
zVal = fOriginalParameters.fZValues[j];
p0 = UVector3(rad1 * cosphi1, rad1 * sinphi1, zVal);
p1 = UVector3(rad1 * cosphi2, rad1 * sinphi2, zVal);
zVal = fOriginalParameters.fZValues[j + 1];
p2 = UVector3(rad2 * cosphi2, rad2 * sinphi2, zVal);
p3 = UVector3(rad2 * cosphi1, rad2 * sinphi1, zVal);
return GetPointOnPlane(p0, p1, p2, p3);
}
else if ((chose >= fNumSides * aVector1[j])
&& (chose <= fNumSides * (aVector1[j] + aVector2[j])))
{
chose = UUtils::Random(fStartPhi, fStartPhi + totalPhi);
rang = std::floor((chose - fStartPhi) / ksi - 0.01);
if (rang < 0)
{
rang = 0;
}
rang = std::fabs(rang);
rad1 = fOriginalParameters.Rmin[j];
rad2 = fOriginalParameters.Rmin[j + 1];
sinphi1 = std::sin(fStartPhi + rang * ksi);
sinphi2 = std::sin(fStartPhi + (rang + 1) * ksi);
cosphi1 = std::cos(fStartPhi + rang * ksi);
cosphi2 = std::cos(fStartPhi + (rang + 1) * ksi);
zVal = fOriginalParameters.fZValues[j];
p0 = UVector3(rad1 * cosphi1, rad1 * sinphi1, zVal);
p1 = UVector3(rad1 * cosphi2, rad1 * sinphi2, zVal);
zVal = fOriginalParameters.fZValues[j + 1];
p2 = UVector3(rad2 * cosphi2, rad2 * sinphi2, zVal);
p3 = UVector3(rad2 * cosphi1, rad2 * sinphi1, zVal);
return GetPointOnPlane(p0, p1, p2, p3);
}
chose = UUtils::Random(0., 2.2);
if ((chose >= 0.) && (chose < 1.))
{
rang = fStartPhi;
}
else
{
rang = fEndPhi;
}
cosphi1 = std::cos(rang);
rad1 = fOriginalParameters.Rmin[j];
sinphi1 = std::sin(rang);
rad2 = fOriginalParameters.Rmax[j];
p0 = UVector3(rad1 * cosphi1, rad1 * sinphi1,
fOriginalParameters.fZValues[j]);
p1 = UVector3(rad2 * cosphi1, rad2 * sinphi1,
fOriginalParameters.fZValues[j]);
rad1 = fOriginalParameters.Rmax[j + 1];
rad2 = fOriginalParameters.Rmin[j + 1];
p2 = UVector3(rad1 * cosphi1, rad1 * sinphi1,
fOriginalParameters.fZValues[j + 1]);
p3 = UVector3(rad2 * cosphi1, rad2 * sinphi1,
fOriginalParameters.fZValues[j + 1]);
return GetPointOnPlane(p0, p1, p2, p3);
}
else // Generic polyhedra
{
return GetPointOnSurfaceGeneric();
}
}
//
// UPolyhedraHistorical stuff
//
UPolyhedraHistorical::UPolyhedraHistorical()
: fStartAngle(0.), fOpeningAngle(0.), fNumSide(0), fNumZPlanes(0),
fZValues(0), Rmin(0), Rmax(0)
{
}
UPolyhedraHistorical::~UPolyhedraHistorical()
{
}
UPolyhedraHistorical::
UPolyhedraHistorical(const UPolyhedraHistorical& source)
{
fStartAngle = source.fStartAngle;
fOpeningAngle = source.fOpeningAngle;
fNumSide = source.fNumSide;
fNumZPlanes = source.fNumZPlanes;
fZValues = source.fZValues;
Rmin = source.Rmin;
Rmax = source.Rmax;
}
UPolyhedraHistorical&
UPolyhedraHistorical::operator=(const UPolyhedraHistorical& right)
{
if (&right == this) return *this;
fStartAngle = right.fStartAngle;
fOpeningAngle = right.fOpeningAngle;
fNumSide = right.fNumSide;
fNumZPlanes = right.fNumZPlanes;
fZValues = right.fZValues;
Rmin = right.Rmin;
Rmax = right.Rmax;
return *this;
}
void UPolyhedra::Extent(UVector3& aMin, UVector3& aMax) const
{
fEnclosingCylinder->Extent(aMin, aMax);
}
//
// DistanceToIn
//
// This is an override of G4VCSGfaceted::Inside, created in order
// to speed things up by first checking with G4EnclosingCylinder.
//
double UPolyhedra::DistanceToIn(const UVector3& p,
const UVector3& v, double aPstep) const
{
//
// Quick test
//
if (fNoVoxels && fEnclosingCylinder->ShouldMiss(p, v))
return UUtils::kInfinity;
//
// Long answer
//
return UVCSGfaceted::DistanceToIn(p, v, aPstep);
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,597 @@
//
// ********************************************************************
// * This Software is part of the AIDA Unified Solids Library package *
// * See: https://aidasoft.web.cern.ch/USolids *
// ********************************************************************
//
// $Id:$
//
// --------------------------------------------------------------------
//
// UReduciblePolygon
//
// 19.09.13 Marek Gayer
// Created from original implementation in Geant4
// --------------------------------------------------------------------
#include "UUtils.hh"
#include <string>
#include <cmath>
#include <sstream>
#include <iostream>
#include "UReduciblePolygon.hh"
//
// Constructor: with simple arrays
//
UReduciblePolygon::UReduciblePolygon(const double a[],
const double b[],
int n)
: aMin(0.), aMax(0.), bMin(0.), bMax(0.),
vertexHead(0)
{
//
// Do all of the real work in Create
//
Create(a, b, n);
}
//
// Constructor: special PGON/PCON case
//
UReduciblePolygon::UReduciblePolygon(const double rmin[],
const double rmax[],
const double z[], int n)
: aMin(0.), aMax(0.), bMin(0.), bMax(0.),
vertexHead(0)
{
//
// Translate
//
double* a = new double[n * 2];
double* b = new double[n * 2];
double* rOut = a + n,
*zOut = b + n,
*rIn = rOut - 1,
*zIn = zOut - 1;
int i;
for (i = 0; i < n; i++, rOut++, zOut++, rIn--, zIn--)
{
*rOut = rmax[i];
*rIn = rmin[i];
*zOut = *zIn = z[i];
}
Create(a, b, n * 2);
delete [] a;
delete [] b;
}
//
// Create
//
// To be called by constructors, fill in the list and statistics for a new
// polygon
//
void UReduciblePolygon::Create(const double a[],
const double b[], int n)
{
if (n < 3)
UUtils::Exception("UReduciblePolygon::Create()", "GeomSolids0002",
FatalErrorInArguments, 1, "Less than 3 vertices specified.");
const double* anext = a, *bnext = b;
ABVertex* prev = 0;
do
{
ABVertex* newVertex = new ABVertex;
newVertex->a = *anext;
newVertex->b = *bnext;
newVertex->next = 0;
if (prev == 0)
{
vertexHead = newVertex;
}
else
{
prev->next = newVertex;
}
prev = newVertex;
}
while (++anext, ++bnext < b + n);
numVertices = n;
CalculateMaxMin();
}
//
// Destructor
//
UReduciblePolygon::~UReduciblePolygon()
{
ABVertex* curr = vertexHead;
while (curr)
{
ABVertex* toDelete = curr;
curr = curr->next;
delete toDelete;
}
}
//
// CopyVertices
//
// Copy contents into simple linear arrays.
// ***** CAUTION ***** Be care to declare the arrays to a large
// enough size!
//
void UReduciblePolygon::CopyVertices(double a[], double b[]) const
{
double* anext = a, *bnext = b;
ABVertex* curr = vertexHead;
while (curr)
{
*anext++ = curr->a;
*bnext++ = curr->b;
curr = curr->next;
}
}
//
// ScaleA
//
// Multiply all a values by a common scale
//
void UReduciblePolygon::ScaleA(double scale)
{
ABVertex* curr = vertexHead;
while (curr)
{
curr->a *= scale;
curr = curr->next;
}
}
//
// ScaleB
//
// Multiply all b values by a common scale
//
void UReduciblePolygon::ScaleB(double scale)
{
ABVertex* curr = vertexHead;
while (curr)
{
curr->b *= scale;
curr = curr->next;
}
}
//
// RemoveDuplicateVertices
//
// Remove adjacent vertices that are equal. Returns "false" if there
// is a problem (too few vertices remaining).
//
bool UReduciblePolygon::RemoveDuplicateVertices(double tolerance)
{
ABVertex* curr = vertexHead,
*prev = 0, *next = 0;
while (curr)
{
next = curr->next;
if (next == 0) next = vertexHead;
if (std::fabs(curr->a - next->a) < tolerance &&
std::fabs(curr->b - next->b) < tolerance)
{
//
// Duplicate found: do we have > 3 vertices?
//
if (numVertices <= 3)
{
CalculateMaxMin();
return false;
}
//
// Delete
//
ABVertex* toDelete = curr;
curr = curr->next;
delete toDelete;
numVertices--;
if (prev) prev->next = curr;
else vertexHead = curr;
}
else
{
prev = curr;
curr = curr->next;
}
}
//
// In principle, this is not needed, but why not just play it safe?
//
CalculateMaxMin();
return true;
}
//
// RemoveRedundantVertices
//
// Remove any unneeded vertices, i.e. those vertices which
// are on the line connecting the previous and next vertices.
//
bool UReduciblePolygon::RemoveRedundantVertices(double tolerance)
{
//
// Under these circumstances, we can quit now!
//
if (numVertices <= 2) return false;
double tolerance2 = tolerance * tolerance;
//
// Loop over all vertices
//
ABVertex* curr = vertexHead, *next = 0;
while (curr)
{
next = curr->next;
if (next == 0) next = vertexHead;
double da = next->a - curr->a,
db = next->b - curr->b;
//
// Loop over all subsequent vertices, up to curr
//
for (;;)
{
//
// Get vertex after next
//
ABVertex* test = next->next;
if (test == 0) test = vertexHead;
//
// If we are back to the original vertex, stop
//
if (test == curr) break;
//
// Test for parallel line segments
//
double dat = test->a - curr->a,
dbt = test->b - curr->b;
if (std::fabs(dat * db - dbt * da) > tolerance2) break;
//
// Redundant vertex found: do we have > 3 vertices?
//
if (numVertices <= 3)
{
CalculateMaxMin();
return false;
}
//
// Delete vertex pointed to by next. Carefully!
//
if (curr->next)
{
// next is not head
if (next->next)
curr->next = test; // next is not tail
else
curr->next = 0; // New tail
}
else
vertexHead = test; // New head
if ((curr != next) && (next != test)) delete next;
numVertices--;
//
// Replace next by the vertex we just tested,
// and keep on going...
//
next = test;
da = dat;
db = dbt;
}
curr = curr->next;
}
//
// In principle, this is not needed, but why not just play it safe?
//
CalculateMaxMin();
return true;
}
//
// ReverseOrder
//
// Reverse the order of the vertices
//
void UReduciblePolygon::ReverseOrder()
{
//
// Loop over all vertices
//
ABVertex* prev = vertexHead;
if (prev == 0) return; // No vertices
ABVertex* curr = prev->next;
if (curr == 0) return; // Just one vertex
//
// Our new tail
//
vertexHead->next = 0;
for (;;)
{
//
// Save pointer to next vertex (in original order)
//
ABVertex* save = curr->next;
//
// Replace it with a pointer to the previous one
// (in original order)
//
curr->next = prev;
//
// Last vertex?
//
if (save == 0) break;
//
// Next vertex
//
prev = curr;
curr = save;
}
//
// Our new head
//
vertexHead = curr;
}
// StartWithZMin
//
// Starting alway with Zmin=bMin
// This method is used for GenericPolycone
//
void UReduciblePolygon::StartWithZMin()
{
ABVertex* curr = vertexHead;
double bcurr = curr->b;
ABVertex* prev = curr;
while (curr)
{
if (curr->b < bcurr)
{
bcurr = curr->b;
ABVertex* curr1 = curr;
while (curr1)
{
if (curr1->next == 0)
{
curr1->next = vertexHead;
break;
}
curr1 = curr1->next;
}
vertexHead = curr;
prev->next = 0;
}
prev = curr;
curr = curr->next;
}
}
//
// CrossesItself
//
// Return "true" if the polygon crosses itself
//
// Warning: this routine is not very fast (runs as N**2)
//
bool UReduciblePolygon::CrossesItself(double tolerance)
{
double tolerance2 = tolerance * tolerance;
double one = 1.0 - tolerance,
zero = tolerance;
//
// Top loop over line segments. By the time we finish
// with the second to last segment, we're done.
//
ABVertex* curr1 = vertexHead, *next1 = 0;
while (curr1->next)
{
next1 = curr1->next;
double da1 = next1->a - curr1->a,
db1 = next1->b - curr1->b;
//
// Inner loop over subsequent line segments
//
ABVertex* curr2 = next1->next;
while (curr2)
{
ABVertex* next2 = curr2->next;
if (next2 == 0) next2 = vertexHead;
double da2 = next2->a - curr2->a,
db2 = next2->b - curr2->b;
double a12 = curr2->a - curr1->a,
b12 = curr2->b - curr1->b;
//
// Calculate intersection of the two lines
//
double deter = da1 * db2 - db1 * da2;
if (std::fabs(deter) > tolerance2)
{
double s1, s2;
s1 = (a12 * db2 - b12 * da2) / deter;
if (s1 >= zero && s1 < one)
{
s2 = -(da1 * b12 - db1 * a12) / deter;
if (s2 >= zero && s2 < one) return true;
}
}
curr2 = curr2->next;
}
curr1 = next1;
}
return false;
}
//
// BisectedBy
//
// Decide if a line through two points crosses the polygon, within tolerance
//
bool UReduciblePolygon::BisectedBy(double a1, double b1,
double a2, double b2,
double tolerance)
{
int nNeg = 0, nPos = 0;
double a12 = a2 - a1, b12 = b2 - b1;
double len12 = std::sqrt(a12 * a12 + b12 * b12);
a12 /= len12;
b12 /= len12;
ABVertex* curr = vertexHead;
do
{
double av = curr->a - a1,
bv = curr->b - b1;
double Cross = av * b12 - bv * a12;
if (Cross < -tolerance)
{
if (nPos) return true;
nNeg++;
}
else if (Cross > tolerance)
{
if (nNeg) return true;
nPos++;
}
curr = curr->next;
}
while (curr);
return false;
}
//
// Area
//
// Calculated signed polygon area, where polygons specified in a
// clockwise manner (where x==a, y==b) have negative area
//
// References: [O' Rourke (C)] pp. 18-27; [Gems II] pp. 5-6:
// "The Area of a Simple Polygon", Jon Rokne.
//
double UReduciblePolygon::Area()
{
double answer = 0;
ABVertex* curr = vertexHead, *next;
do
{
next = curr->next;
if (next == 0) next = vertexHead;
answer += curr->a * next->b - curr->b * next->a;
curr = curr->next;
}
while (curr);
return 0.5 * answer;
}
//
// Print
//
void UReduciblePolygon::Print()
{
ABVertex* curr = vertexHead;
do
{
std::cerr << curr->a << " " << curr->b << std::endl;
curr = curr->next;
}
while (curr);
}
//
// CalculateMaxMin
//
// To be called when the vertices are changed, this
// routine re-calculates global values
//
void UReduciblePolygon::CalculateMaxMin()
{
ABVertex* curr = vertexHead;
aMin = aMax = curr->a;
bMin = bMax = curr->b;
curr = curr->next;
while (curr)
{
if (curr->a < aMin)
aMin = curr->a;
else if (curr->a > aMax)
aMax = curr->a;
if (curr->b < bMin)
bMin = curr->b;
else if (curr->b > bMax)
bMax = curr->b;
curr = curr->next;
}
}
File diff suppressed because it is too large Load Diff
+655
View File
@@ -0,0 +1,655 @@
//
// ********************************************************************
// * This Software is part of the AIDA Unified Solids Library package *
// * See: https://aidasoft.web.cern.ch/USolids *
// ********************************************************************
//
// $Id:$
//
// --------------------------------------------------------------------
//
// UTet
//
// 19.07.13 Tatiana Nikitina
// Created from original implementation in Geant4
// --------------------------------------------------------------------
#include <cmath>
#include <iostream>
#include <sstream>
#include "UTet.hh"
#include "UUtils.hh"
using namespace std;
////////////////////////////////////////////////////////////////////////
//
// Constructor - create a tetrahedron
// This class is implemented separately from general polyhedra,
// because the simplex geometry can be computed very quickly,
// which may become important in situations imported from mesh generators,
// in which a very large number of G4Tets are created.
// A Tet has all of its geometrical information precomputed
UTet::UTet(const std::string& name,
UVector3 anchor,
UVector3 p2,
UVector3 p3,
UVector3 p4, bool* degeneracyFlag)
: VUSolid(name), warningFlag(0)
{
// fV<x><y> is vector from vertex <y> to vertex <x>
//
UVector3 fV21 = p2 - anchor;
UVector3 fV31 = p3 - anchor;
UVector3 fV41 = p4 - anchor;
// make sure this is a correctly oriented set of points for the tetrahedron
//
double signed_vol = fV21.Cross(fV31).Dot(fV41);
if (signed_vol < 0.0)
{
UVector3 temp(p4);
p4 = p3;
p3 = temp;
temp = fV41;
fV41 = fV31;
fV31 = temp;
}
fCubicVolume = std::fabs(signed_vol) / 6.;
//UVector3 fV24=p2-p4;
UVector3 fV43 = p4 - p3;
UVector3 fV32 = p3 - p2;
fXMin = std::min(std::min(std::min(anchor.x, p2.x), p3.x), p4.x);
fXMax = std::max(std::max(std::max(anchor.x, p2.x), p3.x), p4.x);
fYMin = std::min(std::min(std::min(anchor.y, p2.y), p3.y), p4.y);
fYMax = std::max(std::max(std::max(anchor.y, p2.y), p3.y), p4.y);
fZMin = std::min(std::min(std::min(anchor.z, p2.z), p3.z), p4.z);
fZMax = std::max(std::max(std::max(anchor.z, p2.z), p3.z), p4.z);
fDx = (fXMax - fXMin) * 0.5;
fDy = (fYMax - fYMin) * 0.5;
fDz = (fZMax - fZMin) * 0.5;
fMiddle = UVector3(fXMax + fXMin, fYMax + fYMin, fZMax + fZMin) * 0.5;
fMaxSize = std::max(std::max(std::max((anchor - fMiddle).Mag(),
(p2 - fMiddle).Mag()),
(p3 - fMiddle).Mag()),
(p4 - fMiddle).Mag());
bool degenerate = std::fabs(signed_vol) < 1e-9 * fMaxSize * fMaxSize * fMaxSize;
if (degeneracyFlag) *degeneracyFlag = degenerate;
else if (degenerate)
{
UUtils::Exception("UTet::UTet()", "GeomSolids0002", FatalErrorInArguments, 1,
"Degenerate tetrahedron not allowed.");
}
fTol = 1e-9 * (std::fabs(fXMin) + std::fabs(fXMax) + std::fabs(fYMin)
+ std::fabs(fYMax) + std::fabs(fZMin) + std::fabs(fZMax));
//fTol=kCarTolerance;
fAnchor = anchor;
fP2 = p2;
fP3 = p3;
fP4 = p4;
UVector3 fCenter123 = (anchor + p2 + p3) * (1.0 / 3.0); // face center
UVector3 fCenter134 = (anchor + p4 + p3) * (1.0 / 3.0);
UVector3 fCenter142 = (anchor + p4 + p2) * (1.0 / 3.0);
UVector3 fCenter234 = (p2 + p3 + p4) * (1.0 / 3.0);
// compute area of each triangular face by cross product
// and sum for total surface area
UVector3 normal123 = fV31.Cross(fV21);
UVector3 normal134 = fV41.Cross(fV31);
UVector3 normal142 = fV21.Cross(fV41);
UVector3 normal234 = fV32.Cross(fV43);
fSurfaceArea = (
normal123.Mag() +
normal134.Mag() +
normal142.Mag() +
normal234.Mag()
) / 2.0;
fNormal123 = normal123.Unit();
fNormal134 = normal134.Unit();
fNormal142 = normal142.Unit();
fNormal234 = normal234.Unit();
fCdotN123 = fCenter123.Dot(fNormal123);
fCdotN134 = fCenter134.Dot(fNormal134);
fCdotN142 = fCenter142.Dot(fNormal142);
fCdotN234 = fCenter234.Dot(fNormal234);
}
//////////////////////////////////////////////////////////////////////////
//
// Destructor
UTet::~UTet()
{
;
}
///////////////////////////////////////////////////////////////////////////////
//
// Copy constructor
UTet::UTet(const UTet& rhs)
: VUSolid(rhs),
fCubicVolume(rhs.fCubicVolume), fSurfaceArea(rhs.fSurfaceArea),
fAnchor(rhs.fAnchor),
fP2(rhs.fP2), fP3(rhs.fP3), fP4(rhs.fP4), fMiddle(rhs.fMiddle),
fNormal123(rhs.fNormal123), fNormal142(rhs.fNormal142),
fNormal134(rhs.fNormal134), fNormal234(rhs.fNormal234),
warningFlag(rhs.warningFlag), fCdotN123(rhs.fCdotN123),
fCdotN142(rhs.fCdotN142), fCdotN134(rhs.fCdotN134),
fCdotN234(rhs.fCdotN234), fXMin(rhs.fXMin), fXMax(rhs.fXMax),
fYMin(rhs.fYMin), fYMax(rhs.fYMax), fZMin(rhs.fZMin), fZMax(rhs.fZMax),
fDx(rhs.fDx), fDy(rhs.fDy), fDz(rhs.fDz), fTol(rhs.fTol),
fMaxSize(rhs.fMaxSize)
{
}
///////////////////////////////////////////////////////////////////////////////
//
// Assignment operator
UTet& UTet::operator = (const UTet& rhs)
{
// Check assignment to self
//
if (this == &rhs)
{
return *this;
}
// Copy base class data
//
VUSolid::operator=(rhs);
// Copy data
//
fCubicVolume = rhs.fCubicVolume;
fSurfaceArea = rhs.fSurfaceArea;
fAnchor = rhs.fAnchor;
fP2 = rhs.fP2;
fP3 = rhs.fP3;
fP4 = rhs.fP4;
fMiddle = rhs.fMiddle;
fNormal123 = rhs.fNormal123;
fNormal142 = rhs.fNormal142;
fNormal134 = rhs.fNormal134;
fNormal234 = rhs.fNormal234;
warningFlag = rhs.warningFlag;
fCdotN123 = rhs.fCdotN123;
fCdotN142 = rhs.fCdotN142;
fCdotN134 = rhs.fCdotN134;
fCdotN234 = rhs.fCdotN234;
fXMin = rhs.fXMin;
fXMax = rhs.fXMax;
fYMin = rhs.fYMin;
fYMax = rhs.fYMax;
fZMin = rhs.fZMin;
fZMax = rhs.fZMax;
fDx = rhs.fDx;
fDy = rhs.fDy;
fDz = rhs.fDz;
fTol = rhs.fTol;
fMaxSize = rhs.fMaxSize;
return *this;
}
/////////////////////////////////////////////////////////////////////////
//
// Return whether point inside/outside/on surface, using tolerance
VUSolid::EnumInside UTet::Inside(const UVector3& p) const
{
double r123, r134, r142, r234;
// this is written to allow if-statement truncation so the outside test
// (where most of the world is) can fail very quickly and efficiently
if ((r123 = p.Dot(fNormal123) - fCdotN123) > fTol ||
(r134 = p.Dot(fNormal134) - fCdotN134) > fTol ||
(r142 = p.Dot(fNormal142) - fCdotN142) > fTol ||
(r234 = p.Dot(fNormal234) - fCdotN234) > fTol)
{
return eOutside; // at least one is out!
}
else if ((r123 < -fTol) && (r134 < -fTol) && (r142 < -fTol) && (r234 < -fTol))
{
return eInside; // all are definitively inside
}
else
{
return eSurface; // too close to tell
}
}
///////////////////////////////////////////////////////////////////////
//
// Calculate side nearest to p, and return normal
// If two sides are equidistant, normal of first side (x/y/z)
// encountered returned.
// This assumes that we are looking from the inside!
bool UTet::Normal(const UVector3& p, UVector3& n) const
{
double r123 = std::fabs(p.Dot(fNormal123) - fCdotN123);
double r134 = std::fabs(p.Dot(fNormal134) - fCdotN134);
double r142 = std::fabs(p.Dot(fNormal142) - fCdotN142);
double r234 = std::fabs(p.Dot(fNormal234) - fCdotN234);
static const double delta = 0.5 * fTol;
UVector3 sumnorm(0., 0., 0.);
int noSurfaces = 0;
if (r123 <= delta)
{
noSurfaces ++;
sumnorm = fNormal123;
}
if (r134 <= delta)
{
noSurfaces ++;
sumnorm += fNormal134;
}
if (r142 <= delta)
{
noSurfaces ++;
sumnorm += fNormal142;
}
if (r234 <= delta)
{
noSurfaces ++;
sumnorm += fNormal234;
}
if (noSurfaces > 0)
{
if (noSurfaces == 1)
{
n = sumnorm;
return true;
}
else
{
n = sumnorm.Unit();
return true;
}
}
else // Approximative Surface Normal
{
if ((r123 <= r134) && (r123 <= r142) && (r123 <= r234))
{
n = fNormal123;
}
else if ((r134 <= r142) && (r134 <= r234))
{
n = fNormal134;
}
else if (r142 <= r234)
{
n = fNormal142;
}
n = fNormal234;
return false;
}
}
///////////////////////////////////////////////////////////////////////////
//
// Calculate distance to box from an outside point
// - return kInfinity if no intersection.
// All this is very unrolled, for speed.
double UTet::DistanceToIn(const UVector3& p,
const UVector3& v, double /*aPstep*/) const
{
UVector3 vu(v.Unit()), hp;
double vdotn, t, tmin = UUtils::kInfinity;
double extraDistance = 10.0 * fTol; // a little ways into the solid
vdotn = -vu.Dot(fNormal123);
if (vdotn > 1e-12)
{
// this is a candidate face, since it is pointing at us
t = (p.Dot(fNormal123) - fCdotN123) / vdotn; // # distance to intersection
if ((t >= -fTol) && (t < tmin))
{
// if not true, we're going away from this face or it's not close
hp = p + vu * (t + extraDistance); // a little beyond point of intersection
if ((hp.Dot(fNormal134) - fCdotN134 < 0.0) &&
(hp.Dot(fNormal142) - fCdotN142 < 0.0) &&
(hp.Dot(fNormal234) - fCdotN234 < 0.0))
{
tmin = t;
}
}
}
vdotn = -vu.Dot(fNormal134);
if (vdotn > 1e-12)
{
// # this is a candidate face, since it is pointing at us
t = (p.Dot(fNormal134) - fCdotN134) / vdotn; // # distance to intersection
if ((t >= -fTol) && (t < tmin))
{
// if not true, we're going away from this face
hp = p + vu * (t + extraDistance); // a little beyond point of intersection
if ((hp.Dot(fNormal123) - fCdotN123 < 0.0) &&
(hp.Dot(fNormal142) - fCdotN142 < 0.0) &&
(hp.Dot(fNormal234) - fCdotN234 < 0.0))
{
tmin = t;
}
}
}
vdotn = -vu.Dot(fNormal142);
if (vdotn > 1e-12)
{
// # this is a candidate face, since it is pointing at us
t = (p.Dot(fNormal142) - fCdotN142) / vdotn; // # distance to intersection
if ((t >= -fTol) && (t < tmin))
{
// if not true, we're going away from this face
hp = p + vu * (t + extraDistance); // a little beyond point of intersection
if ((hp.Dot(fNormal123) - fCdotN123 < 0.0) &&
(hp.Dot(fNormal134) - fCdotN134 < 0.0) &&
(hp.Dot(fNormal234) - fCdotN234 < 0.0))
{
tmin = t;
}
}
}
vdotn = -vu.Dot(fNormal234);
if (vdotn > 1e-12)
{
// # this is a candidate face, since it is pointing at us
t = (p.Dot(fNormal234) - fCdotN234) / vdotn; // # distance to intersection
if ((t >= -fTol) && (t < tmin))
{
// if not true, we're going away from this face
hp = p + vu * (t + extraDistance); // a little beyond point of intersection
if ((hp.Dot(fNormal123) - fCdotN123 < 0.0) &&
(hp.Dot(fNormal134) - fCdotN134 < 0.0) &&
(hp.Dot(fNormal142) - fCdotN142 < 0.0))
{
tmin = t;
}
}
}
return std::max(0.0, tmin);
}
//////////////////////////////////////////////////////////////////////////
//
// Approximate distance to tet.
// returns distance to sphere centered on bounding box
// - If inside return 0
double UTet::SafetyFromOutside(const UVector3& p, bool /*aAccurate*/) const
{
double dd = (p - fMiddle).Mag() - fMaxSize - fTol;
return std::max(0.0, dd);
}
/////////////////////////////////////////////////////////////////////////
//
// Calcluate distance to surface of box from inside
// by calculating distances to box's x/y/z planes.
// Smallest distance is exact distance to exiting.
double UTet::DistanceToOut(const UVector3& p, const UVector3& v,
UVector3& n, bool& convex, double /*aPstep*/) const
{
UVector3 vu(v.Unit());
double t1 = UUtils::kInfinity, t2 = UUtils::kInfinity, t3 = UUtils::kInfinity, t4 = UUtils::kInfinity, vdotn, tt;
vdotn = vu.Dot(fNormal123);
if (vdotn > 1e-12) // #we're heading towards this face, so it is a candidate
{
t1 = (fCdotN123 - p.Dot(fNormal123)) / vdotn; // # distance to intersection
}
vdotn = vu.Dot(fNormal134);
if (vdotn > 1e-12) // #we're heading towards this face, so it is a candidate
{
t2 = (fCdotN134 - p.Dot(fNormal134)) / vdotn; // # distance to intersection
}
vdotn = vu.Dot(fNormal142);
if (vdotn > 1e-12) // #we're heading towards this face, so it is a candidate
{
t3 = (fCdotN142 - p.Dot(fNormal142)) / vdotn; // # distance to intersection
}
vdotn = vu.Dot(fNormal234);
if (vdotn > 1e-12) // #we're heading towards this face, so it is a candidate
{
t4 = (fCdotN234 - p.Dot(fNormal234)) / vdotn; // # distance to intersection
}
tt = std::min(std::min(std::min(t1, t2), t3), t4);
if (warningFlag && (tt == UUtils::kInfinity || tt < -fTol))
{
// DumpInfo();
std::ostringstream message;
message << "No good intersection found or already outside!?" << std::endl
<< "p = " << p << std::endl
<< "v = " << v << std::endl
<< "t1, t2, t3, t4 "
<< t1 << ", " << t2 << ", " << t3 << ", " << t4;
UUtils::Exception("UTet::DistanceToOut(p,v,...)", "GeomSolids1002",
Warning, 1, message.str().c_str());
if (convex)
{
convex = false; // flag normal as meaningless
}
}
else
{
static UVector3 normal;
if (tt == t1)
{
normal = fNormal123;
}
else if (tt == t2)
{
normal = fNormal134;
}
else if (tt == t3)
{
normal = fNormal142;
}
else if (tt == t4)
{
normal = fNormal234;
}
n = normal;
if (convex)
{
convex = true;
}
}
return std::max(tt, 0.0); // avoid tt<0.0 by a tiny bit
// if we are right on a face
}
////////////////////////////////////////////////////////////////////////////
//
// Calculate exact shortest distance to any boundary from inside
// - If outside return 0
double UTet::SafetyFromInside(const UVector3& p, bool /*aAccurate*/) const
{
double t1, t2, t3, t4;
t1 = fCdotN123 - p.Dot(fNormal123); // distance to plane, positive if inside
t2 = fCdotN134 - p.Dot(fNormal134); // distance to plane
t3 = fCdotN142 - p.Dot(fNormal142); // distance to plane
t4 = fCdotN234 - p.Dot(fNormal234); // distance to plane
// if any one of these is negative, we are outside,
// so return zero in that case
double tmin = std::min(std::min(std::min(t1, t2), t3), t4);
return (tmin < fTol) ? 0 : tmin;
}
//////////////////////////////////////////////////////////////////////////
//
// Stream object contents to an output stream
std::ostream& UTet::StreamInfo(std::ostream& os) const
{
int oldprc = os.precision(16);
os << "-----------------------------------------------------------\n"
<< " *** Dump for solid - " << GetName() << " ***\n"
<< " ===================================================\n"
<< " Solid type: UTet\n"
<< " Parameters: \n"
<< " anchor: " << fAnchor << " \n"
<< " p2: " << fP2 << " \n"
<< " p3: " << fP3 << " \n"
<< " p4: " << fP4 << " \n"
<< " normal123: " << fNormal123 << " \n"
<< " normal134: " << fNormal134 << " \n"
<< " normal142: " << fNormal142 << " \n"
<< " normal234: " << fNormal234 << " \n"
<< "-----------------------------------------------------------\n";
os.precision(oldprc);
return os;
}
////////////////////////////////////////////////////////////////////////
//
// GetPointOnFace
//
// Auxiliary method for get point on surface
UVector3 UTet::GetPointOnFace(UVector3 p1, UVector3 p2,
UVector3 p3, double& area) const
{
double lambda1, lambda2;
UVector3 v, w;
v = p3 - p1;
w = p1 - p2;
lambda1 = UUtils::Random(0., 1.);
lambda2 = UUtils::Random(0., lambda1);
area = 0.5 * (v.Cross(w)).Mag();
return (p2 + lambda1 * w + lambda2 * v);
}
////////////////////////////////////////////////////////////////////////////
//
// GetPointOnSurface
UVector3 UTet::GetPointOnSurface() const
{
double chose, aOne, aTwo, aThree, aFour;
UVector3 p1, p2, p3, p4;
p1 = GetPointOnFace(fAnchor, fP2, fP3, aOne);
p2 = GetPointOnFace(fAnchor, fP4, fP3, aTwo);
p3 = GetPointOnFace(fAnchor, fP4, fP2, aThree);
p4 = GetPointOnFace(fP4, fP3, fP2, aFour);
chose = UUtils::Random(0., aOne + aTwo + aThree + aFour);
if ((chose >= 0.) && (chose < aOne))
{
return p1;
}
else if ((chose >= aOne) && (chose < aOne + aTwo))
{
return p2;
}
else if ((chose >= aOne + aTwo) && (chose < aOne + aTwo + aThree))
{
return p3;
}
return p4;
}
////////////////////////////////////////////////////////////////////////
//
// GetVertices
std::vector<UVector3> UTet::GetVertices() const
{
std::vector<UVector3> vertices(4);
vertices[0] = fAnchor;
vertices[1] = fP2;
vertices[2] = fP3;
vertices[3] = fP4;
return vertices;
}
//______________________________________________________________________________
void UTet::Extent(UVector3& aMin, UVector3& aMax) const
{
// Returns the full 3D cartesian extent of the solid.
aMin.x = -fDx;
aMax.x = fDx;
aMin.y = -fDy;
aMax.y = fDy;
aMin.z = -fDz;
aMax.z = fDz;
}
//______________________________________________________________________________
void UTet::GetParametersList(int, double* aArray) const
{
aArray[0] = fAnchor.x;
aArray[1] = fAnchor.y;
aArray[2] = fAnchor.z;
aArray[3] = fP2.x;
aArray[4] = fP2.y;
aArray[5] = fP2.z;
aArray[6] = fP3.x;
aArray[7] = fP3.y;
aArray[8] = fP3.z;
aArray[9] = fP4.x;
aArray[10] = fP4.y;
aArray[11] = fP4.z;
}
//______________________________________________________________________________
UGeometryType UTet::GetEntityType() const
{
return "Tet";
}
//______________________________________________________________________________
double UTet::Capacity()
{
return fCubicVolume;
}
//______________________________________________________________________________
double UTet::SurfaceArea()
{
return fSurfaceArea;
}
@@ -0,0 +1,259 @@
//
// ********************************************************************
// * This Software is part of the AIDA Unified Solids Library package *
// * See: https://aidasoft.web.cern.ch/USolids *
// ********************************************************************
//
// $Id:$
//
// --------------------------------------------------------------------
//
// UTransform3D
//
// 19.09.12 Marek Gayer
// Created from original implementation in CLHEP
// --------------------------------------------------------------------
#include <cmath>
#include <cstring>
#include "UTransform3D.hh"
#include "UUtils.hh"
const static double kIdRot[9] =
{
1.0, 0.0, 0.0,
0.0, 1.0, 0.0,
0.0, 0.0, 1.0
};
//______________________________________________________________________________
UTransform3D::UTransform3D()
{
// Dummy constructor
fTr.Set(0);
std::memcpy(fRot, kIdRot, sizeof(kIdRot));
}
//______________________________________________________________________________
UTransform3D::UTransform3D(double tx, double ty, double tz,
double phi, double theta, double psi)
{
// Constructor providing a translation and Euler angles
// See description for SetAngles() method.
// This represent the composition of : first a rotation about Z axis with
// angle phi, then a rotation with theta about the rotated X axis, and
// finally a rotation with psi about the new Z axis.
fTr.Set(tx, ty, tz);
SetAngles(phi, theta, psi);
}
//______________________________________________________________________________
UTransform3D::UTransform3D(const UTransform3D& other)
{
// Copy constructor.
fTr = other.fTr;
std::memcpy(fRot, other.fRot, sizeof(kIdRot));
}
//______________________________________________________________________________
UTransform3D& UTransform3D::operator = (const UTransform3D& other)
{
if (&other == this) return *this;
fTr = other.fTr;
std::memcpy(fRot, other.fRot, sizeof(kIdRot));
return *this;
}
//______________________________________________________________________________
void UTransform3D::SetAngles(double phi, double theta, double psi)
{
// Set the rotation from Euler angles in the X-axis convention
// See: http://mathworld.wolfram.com/EulerAngles.html
// This represent the composition of : first a rotation about Z axis with
// angle phi, then a rotation with theta about the rotated X axis, and
// finally a rotation with psi about the new Z axis.
// NOTE: angles are in degrees
double degrad = UUtils::kDegToRad;
double sinphi = std::sin(degrad * phi);
double cosphi = std::cos(degrad * phi);
double sinthe = std::sin(degrad * theta);
double costhe = std::cos(degrad * theta);
double sinpsi = std::sin(degrad * psi);
double cospsi = std::cos(degrad * psi);
fRot[0] = cospsi * cosphi - costhe * sinphi * sinpsi;
fRot[1] = -sinpsi * cosphi - costhe * sinphi * cospsi;
fRot[2] = sinthe * sinphi;
fRot[3] = cospsi * sinphi + costhe * cosphi * sinpsi;
fRot[4] = -sinpsi * sinphi + costhe * cosphi * cospsi;
fRot[5] = -sinthe * cosphi;
fRot[6] = sinpsi * sinthe;
fRot[7] = cospsi * sinthe;
fRot[8] = costhe;
}
//______________________________________________________________________________
void UTransform3D::RotateX(double angle)
{
// Rotate the transformation about the X axis with a given angle (in degrees).
double phi = angle * UUtils::kDegToRad;
double c = std::cos(phi);
double s = std::sin(phi);
double v[9];
v[0] = fRot[0];
v[1] = fRot[1];
v[2] = fRot[2];
v[3] = c * fRot[3] - s * fRot[6];
v[4] = c * fRot[4] - s * fRot[7];
v[5] = c * fRot[5] - s * fRot[8];
v[6] = s * fRot[3] + c * fRot[6];
v[7] = s * fRot[4] + c * fRot[7];
v[8] = s * fRot[5] + c * fRot[8];
std::memcpy(fRot, v, sizeof(kIdRot));
fTr.Set(fTr.x, c * fTr.y - s * fTr.z, s * fTr.y + c * fTr.z);
}
//______________________________________________________________________________
void UTransform3D::RotateY(double angle)
{
// Rotate the transformation about the Y axis with a given angle (in degrees).
double phi = angle * UUtils::kDegToRad;
double c = std::cos(phi);
double s = std::sin(phi);
double v[9];
v[0] = c * fRot[0] + s * fRot[6];
v[1] = c * fRot[1] + s * fRot[7];
v[2] = c * fRot[2] + s * fRot[8];
v[3] = fRot[3];
v[4] = fRot[4];
v[5] = fRot[5];
v[6] = -s * fRot[0] + c * fRot[6];
v[7] = -s * fRot[1] + c * fRot[7];
v[8] = -s * fRot[2] + c * fRot[8];
std::memcpy(fRot, v, sizeof(kIdRot));
fTr.Set(c * fTr.x + s * fTr.z, fTr.y, -s * fTr.x + c * fTr.z);
}
//______________________________________________________________________________
void UTransform3D::RotateZ(double angle)
{
// Rotate the transformation about the Z axis with a given angle (in degrees).
double phi = angle * UUtils::kDegToRad;
double c = std::cos(phi);
double s = std::sin(phi);
double v[9];
v[0] = c * fRot[0] - s * fRot[3];
v[1] = c * fRot[1] - s * fRot[4];
v[2] = c * fRot[2] - s * fRot[5];
v[3] = s * fRot[0] + c * fRot[3];
v[4] = s * fRot[1] + c * fRot[4];
v[5] = s * fRot[2] + c * fRot[5];
v[6] = fRot[6];
v[7] = fRot[7];
v[8] = fRot[8];
std::memcpy(&fRot[0], v, sizeof(kIdRot));
fTr.Set(c * fTr.x - s * fTr.y, s * fTr.x + c * fTr.y, fTr.z);
}
//______________________________________________________________________________
UVector3 UTransform3D::GlobalPoint(const UVector3& local) const
{
// Returns global point coordinates converted from the local frame defined
// by the transformation. This is defined by multiplying this transformation
// with the local vector.
UVector3 global;
global.x = fTr.x + local.x * fRot[0] + local.y * fRot[1] + local.z * fRot[2];
global.y = fTr.y + local.x * fRot[3] + local.y * fRot[4] + local.z * fRot[5];
global.z = fTr.z + local.x * fRot[6] + local.y * fRot[7] + local.z * fRot[8];
return global;
}
//______________________________________________________________________________
UVector3 UTransform3D::GlobalVector(const UVector3& local) const
{
// Returns vector components converted from the local frame defined by the
// transformation to the global one. This is defined by multiplying this
// transformation with the local vector while ignoring the translation.
UVector3 global(
local.x * fRot[0] + local.y * fRot[1] + local.z * fRot[2],
local.x * fRot[3] + local.y * fRot[4] + local.z * fRot[5],
local.x * fRot[6] + local.y * fRot[7] + local.z * fRot[8]);
return global;
}
//______________________________________________________________________________
UVector3 UTransform3D::LocalPoint(const UVector3& global) const
{
// Returns local point coordinates converted from the global frame defined
// by the transformation. This is defined by multiplying the inverse
// transformation with the global vector.
UVector3 mt = global - fTr;
UVector3 local(
mt.x * fRot[0] + mt.y * fRot[3] + mt.z * fRot[6],
mt.x * fRot[1] + mt.y * fRot[4] + mt.z * fRot[7],
mt.x * fRot[2] + mt.y * fRot[5] + mt.z * fRot[8]);
return local;
}
//______________________________________________________________________________
UVector3 UTransform3D::LocalVector(const UVector3& global) const
{
// Returns local point coordinates converted from the global frame defined
// by the transformation. This is defined by multiplying the inverse
// transformation with the global vector.
UVector3 local(
global.x * fRot[0] + global.y * fRot[3] + global.z * fRot[6],
global.x * fRot[1] + global.y * fRot[4] + global.z * fRot[7],
global.x * fRot[2] + global.y * fRot[5] + global.z * fRot[8]);
return local;
}
//______________________________________________________________________________
UTransform3D& UTransform3D::operator *= (const UTransform3D& other)
{
// Multiply with other transformation.
fTr.x = fRot[0] * other.fTr[0] + fRot[1] * other.fTr[1] + fRot[2] * other.fTr[2];
fTr.y = fRot[3] * other.fTr[0] + fRot[4] * other.fTr[1] + fRot[5] * other.fTr[2];
fTr.z = fRot[6] * other.fTr[0] + fRot[7] * other.fTr[1] + fRot[8] * other.fTr[2];
double newrot[9];
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
newrot[3 * i + j] = fRot[3 * i] * other.fRot[j] +
fRot[3 * i + 1] * other.fRot[3 + j] +
fRot[3 * i + 2] * other.fRot[6 + j];
}
}
std::memcpy(fRot, newrot, sizeof(kIdRot));
return *this;
}
//______________________________________________________________________________
UTransform3D& UTransform3D::operator *= (const UVector3& vect)
{
// Multiply with a vector.
fTr.x = fRot[0] * vect.x + fRot[1] * vect.y + fRot[2] * vect.z;
fTr.y = fRot[3] * vect.x + fRot[4] * vect.y + fRot[5] * vect.z;
fTr.z = fRot[6] * vect.x + fRot[7] * vect.y + fRot[8] * vect.z;
return *this;
}
//______________________________________________________________________________
UVector3 operator * (const UVector3& /*p*/, const UTransform3D& /*trans*/)
{
// Multiply matrix with translation.
UVector3 vect;
return vect;
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,288 @@
//
// ********************************************************************
// * This Software is part of the AIDA Unified Solids Library package *
// * See: https://aidasoft.web.cern.ch/USolids *
// ********************************************************************
//
// $Id:$
//
// --------------------------------------------------------------------
//
// UUtils
//
// 19.10.12 Marek Gayer
// --------------------------------------------------------------------
#include <iostream>
#include <iomanip>
#include <fstream>
#include <sstream>
#include "UVector3.hh"
#include "UTransform3D.hh"
#include "UUtils.hh"
#include "VUSolid.hh"
using namespace std;
//______________________________________________________________________________
void UUtils::TransformLimits(UVector3& min, UVector3& max, const UTransform3D& transformation)
{
// The goal of this method is to convert the quantities min and max (representing the
// bounding box of a given solid in its local frame) to the main frame, using
// "transformation"
UVector3 vertices[8] = // Detemination of the vertices thanks to the extension of each solid:
{
UVector3(min.x, min.y, min.z), // 1st vertice:
UVector3(min.x, max.y, min.z), // 2nd vertice:
UVector3(max.x, max.y, min.z),
UVector3(max.x, min.y, min.z),
UVector3(min.x, min.y, max.z),
UVector3(min.x, max.y, max.z),
UVector3(max.x, max.y, max.z),
UVector3(max.x, min.y, max.z)
};
min.Set(kInfinity);
max.Set(-kInfinity);
// Loop on th vertices
int limit = sizeof(vertices) / sizeof(UVector3);
for (int i = 0 ; i < limit; i++)
{
// From local frame to the gobal one:
// Current positions on the three axis:
UVector3 current = transformation.GlobalPoint(vertices[i]);
// If need be, replacement of the min & max values:
if (current.x > max.x) max.x = current.x;
if (current.x < min.x) min.x = current.x;
if (current.y > max.y) max.y = current.y;
if (current.y < min.y) min.y = current.y;
if (current.z > max.z) max.z = current.z;
if (current.z < min.z) min.z = current.z;
}
}
double UUtils::Random(double min, double max)
{
// srand((unsigned)time(NULL));
double number = (double) rand() / RAND_MAX;
double res = min + number * (max - min);
return res;
}
int UUtils::SaveVectorToExternalFile(const vector<double>& vector, const string& filename)
{
ofstream file(filename.c_str());
// NEW: set precision, use exponential, precision 4 digits
if (file.is_open())
{
int size = vector.size();
file.precision(16);
for (int i = 0; i < size; i++)
{
double value = vector[i];
file << value << "\n";
}
return 0;
}
return 1;
}
int UUtils::SaveVectorToExternalFile(const vector<int>& vector, const string& filename)
{
ofstream file(filename.c_str());
if (file.is_open())
{
int size = vector.size();
for (int i = 0; i < size; i++)
{
int value = vector[i];
file << value << "\n";
}
return 0;
}
return 1;
}
int UUtils::SaveVectorToExternalFile(const vector<UVector3>& vector, const string& filename)
{
ofstream file(filename.c_str());
if (file.is_open())
{
int size = vector.size();
file.precision(16);
for (int i = 0; i < size; i++)
{
const UVector3& vec = vector[i];
file << vec.x << "\t" << vec.y << "\t" << vec.z << "\n";
}
return 0;
}
return 1;
}
string UUtils::ToString(int number)
{
std::stringstream ss;
ss << number;
return ss.str();
}
string UUtils::ToString(double number)
{
std::stringstream ss;
ss << number;
return ss.str();
}
int UUtils::FileSize(const std::string& filePath)
{
std::streampos fsize = 0;
std::ifstream file(filePath.c_str(), std::ios::binary);
fsize = file.tellg();
file.seekg(0, std::ios::end);
fsize = file.tellg() - fsize;
file.close();
return fsize;
}
int UUtils::StrPos(const string& haystack, const string& needle)
{
int sleng = haystack.length();
int nleng = needle.length();
if (sleng == 0 || nleng == 0)
return -1;
for (int i = 0, j = 0; i < sleng; j = 0, i++)
{
while (i + j < sleng && j < nleng && haystack[i + j] == needle[j])
j++;
if (j == nleng)
return i;
}
return -1;
}
void UUtils:: Exception(const char* originOfException,
const char* exceptionCode,
ExceptionSeverity severity,
int level,
const char* description)
{
bool toBeAborted = true;
static const std::string es_banner
= "\n-------- EEEE ------- UException-START -------- EEEE -------\n";
static const std::string ee_banner
= "\n-------- EEEE ------- UException-END --------- EEEE -------\n";
static const std::string ws_banner
= "\n-------- WWWW ------- UException-START -------- WWWW -------\n";
static const std::string we_banner
= "\n-------- WWWW -------- UException-END --------- WWWW -------\n";
std::ostringstream message;
message << "\n*** ExceptionHandler is not defined ***\n"
<< "*** Exception : " << exceptionCode << std::endl
<< " issued by : " << originOfException << std::endl
<< description << std::endl;
switch (severity)
{
case FatalError:
std::cerr << es_banner << message.str() << "*** Fatal Exception ***"
<< ee_banner << std::endl;
break;
case FatalErrorInArguments:
std::cerr << es_banner << message.str() << "*** Fatal Error In Argument ***"
<< ee_banner << std::endl;
break;
case Error:
std::cerr << es_banner << message.str() << "*** Error ***" << level
<< ee_banner << std::endl;
break;
case Warning:
std::cerr << ws_banner << message.str() << "*** This is just a warning message ***"
<< we_banner << std::endl;
toBeAborted = false;
break;
default:
std::cout << ws_banner << message.str()
<< "*** This is just a message for your information. ***"
<< we_banner << std::endl;
toBeAborted = false;
break;
}
if (toBeAborted)
{
std::cerr << std::endl << "*** GException: Aborting execution ***" << std::endl;
abort();
}
}
/*
void UTessellatedSolid::ImportFromSTLFile(std::string filename)
{
vector <UTriangularFacet *> fFacets;
USTL::ReadFromBinaryFile(filename, fFacets);
int size = fFacets.size();
for (int i = 0; i < size; ++i)
{
UTriangularFacet *facet = fFacets[i];
AddFacet(facet);
}
SetSolidClosed(true);
}
*/
/*
int size = fFacets.size();
for (int j = 0; j < 100; ++j) //2.418 , 2.511
for (int i = 0; i < size; ++i)
{
UFacet &facet = *facetsi[j];
a += facet.GetNumberOfVertices();
}
if (a % rand() == -1) cout << a;
*/
/*
for (int j = 0; j < 100; ++j) //2.917 3.01
{
int size = fFacets.size();
for (int i = 0; i < size; ++i)
{
UFacet &facet = *fFacets[i];
a += facet.GetNumberOfVertices();
}
}
*/
/*
for (int j = 0; j < 100; ++j) // 2.589
{
std::vector<UFacet *>::const_iterator i, begin = fFacets.begin(), end = fFacets.end();
for (i = begin; i < end; ++i)
{
UFacet &facet = *(*i);
a += facet.GetNumberOfVertices();
}
}
return location;
*/
@@ -0,0 +1,955 @@
//
// ********************************************************************
// * This Software is part of the AIDA Unified Solids Library package *
// * See: https://aidasoft.web.cern.ch/USolids *
// ********************************************************************
//
// $Id:$
//
// --------------------------------------------------------------------
//
// UVCSGfaceted
//
// 19.09.13 Marek Gayer
// Created from original implementation in Geant4
// --------------------------------------------------------------------
#include "UUtils.hh"
#include <string>
#include <cmath>
#include <sstream>
#include "UVCSGfaceted.hh"
#include "UVCSGface.hh"
#include "UVoxelizer.hh"
#include "UReduciblePolygon.hh"
using namespace std;
//
// Constructor
//
UVCSGfaceted::UVCSGfaceted(const std::string& name)
: VUSolid(name),
numFace(0), faces(0), fCubicVolume(0.), fSurfaceArea(0.),
fMaxSection(0),fBoxShift(0.), fNoVoxels(true),fStatistics(1000000), fCubVolEpsilon(0.001), fAreaAccuracy(-1.)
{
}
//
// Destructor
//
UVCSGfaceted::~UVCSGfaceted()
{
DeleteStuff();
}
//
// Copy constructor
//
UVCSGfaceted::UVCSGfaceted(const UVCSGfaceted& source)
: VUSolid(source)
{
fStatistics = source.fStatistics;
fCubVolEpsilon = source.fCubVolEpsilon;
fAreaAccuracy = source.fAreaAccuracy;
CopyStuff(source);
}
//
// Assignment operator
//
UVCSGfaceted& UVCSGfaceted::operator=(const UVCSGfaceted& source)
{
if (&source == this)
{
return *this;
}
// Copy base class data
//
VUSolid::operator=(source);
// Copy data
//
fStatistics = source.fStatistics;
fCubVolEpsilon = source.fCubVolEpsilon;
fAreaAccuracy = source.fAreaAccuracy;
CopyStuff(source);
return *this;
}
//
// CopyStuff (protected)
//
// Copy the contents of source
//
void UVCSGfaceted::CopyStuff(const UVCSGfaceted& source)
{
numFace = source.numFace;
if (numFace == 0)
{
return; // odd, but permissable?
}
faces = new UVCSGface*[numFace];
UVCSGface** face = faces,
**sourceFace = source.faces;
do
{
*face = (*sourceFace)->Clone();
}
while (++sourceFace, ++face < faces + numFace);
fCubicVolume = source.fCubicVolume;
fSurfaceArea = source.fSurfaceArea;
fMaxSection = source.fMaxSection;
fNoVoxels = source.fNoVoxels;
fZs = source.fZs;
fBox = source.fBox;
fBoxShift = source.fBoxShift;
}
//
// DeleteStuff (protected)
//
// Delete all allocated objects
//
void UVCSGfaceted::DeleteStuff()
{
if (numFace)
{
UVCSGface** face = faces;
do
{
delete *face;
}
while (++face < faces + numFace);
delete [] faces;
}
}
//
// Inside
//
// It could be a good idea to override this virtual
// member to add first a simple test (such as spherical
// test or whatnot) and to call this version only if
// the simplier test fails.
//
/*
VUSolid::EnumInside UVCSGfaceted::Inside( const UVector3 &p ) const
{
VUSolid::EnumInside answer=eOutside;
UVCSGface **face = faces;
double best = UUtils::kInfinity;
do
{
double distance;
VUSolid::EnumInside result = (*face)->Inside( p, fgTolerance*0.5, &distance );
if (result == eSurface) { return eSurface; }
if (distance < best)
{
best = distance;
answer = result;
}
} while( ++face < faces + numFace );
return answer;
}
*/
//
// Inside
//
// It could be a good idea to override this virtual
// member to add first a simple test (such as spherical
// test or whatnot) and to call this version only if
// the simplier test fails.
//
inline VUSolid::EnumInside UVCSGfaceted::InsideNoVoxels(const UVector3& p) const
{
VUSolid::EnumInside answer = eOutside;
UVCSGface** face = faces;
double best = UUtils::kInfinity;
do
{
double distance;
VUSolid::EnumInside result = (*face)->Inside(p, fgTolerance * 0.5, &distance);
if (result == eSurface)
{
return eSurface;
}
if (distance < best)
{
best = distance;
answer = result;
}
}
while (++face < faces + numFace);
return answer;
}
//
// SurfaceNormal
//
bool UVCSGfaceted::Normal(const UVector3& p, UVector3& n) const
{
UVector3 answer;
double best = UUtils::kInfinity;
UVector3 normal;
UBits bits(numFace);
int index = GetSection(p.z);
const vector<int>& candidates = fCandidates[index];
int size = candidates.size();
for (int i = 0; i < size; ++i)
{
int candidate = candidates[i];
if (!bits[candidate])
{
bits.SetBitNumber(candidate);
UVCSGface& face = *faces[candidate];
double distance;
normal = face.Normal(p, &distance);
if (distance < best)
{
best = distance;
answer = normal;
if (distance < fgTolerance)
break;
}
}
}
n = answer;
return true;
}
/*
// non voxelized version:
bool UVCSGfaceted::Normal( const UVector3 &p, UVector3 &n) const
{
UVector3 answer;
double best = UUtils::kInfinity;
UVector3 normal;
for (int i = 0; i < numFace; ++i)
{
UVCSGface &face = *faces[i];
double distance;
normal = face.Normal( p, &distance);
if (distance < best)
{
best = distance;
answer = normal;
}
}
n = answer;
return true;
}
*/
//
// DistanceToIn(p,v)
//
inline double UVCSGfaceted::DistanceToInNoVoxels(const UVector3& p,
const UVector3& v) const
{
double distance = UUtils::kInfinity;
double distFromSurface = UUtils::kInfinity;
UVCSGface** face = faces;
UVCSGface* bestFace = *face;
static double htol = fgTolerance * 0.5;
UVector3 faceNormal;
do
{
double faceDistance, faceDistFromSurface;
bool faceAllBehind;
if ((*face)->Distance(p, v, false, htol,
faceDistance, faceDistFromSurface,
faceNormal, faceAllBehind))
{
//
// Intersecting face
//
if (faceDistance < distance)
{
distance = faceDistance;
distFromSurface = faceDistFromSurface;
bestFace = *face;
if (distFromSurface <= 0)
{
return 0;
}
}
}
}
while (++face < faces + numFace);
if (distance < UUtils::kInfinity && distFromSurface < htol)
{
if (bestFace->Safety(p, false) < htol)
{
distance = 0;
}
}
return distance;
}
//
// DistanceToOut(p,v)
//
inline double UVCSGfaceted::DistanceToOutNoVoxels(const UVector3& p, const UVector3& v, UVector3& n, bool& aConvex) const
{
bool allBehind = true;
double distance = UUtils::kInfinity;
double distFromSurface = UUtils::kInfinity;
UVector3 normal, faceNormal;
UVCSGface** face = faces;
UVCSGface* bestFace = *face;
do
{
double faceDistance, faceDistFromSurface;
bool faceAllBehind;
if ((*face)->Distance(p, v, true, fgTolerance / 2,
faceDistance, faceDistFromSurface,
faceNormal, faceAllBehind))
{
// Intersecting face
if ((distance < UUtils::kInfinity) || (!faceAllBehind))
{
allBehind = false;
}
if (faceDistance < distance)
{
distance = faceDistance;
distFromSurface = faceDistFromSurface;
normal = faceNormal;
bestFace = *face;
if (distFromSurface <= 0)
{
break;
}
}
}
}
while (++face < faces + numFace);
if (distance < UUtils::kInfinity)
{
if (distFromSurface <= 0)
{
distance = 0;
}
else if (distFromSurface < fgTolerance / 2)
{
if (bestFace->Safety(p, true) < fgTolerance / 2)
{
distance = 0;
}
}
aConvex = allBehind;
n = normal;
}
else
{
if (Inside(p) == eSurface)
{
distance = 0;
}
aConvex = false;
}
return distance;
}
//
// DistanceTo
//
// Protected routine called by DistanceToIn and DistanceToOut
//
double UVCSGfaceted::DistanceTo(const UVector3& p,
const bool outgoing) const
{
UVCSGface** face = faces;
double best = UUtils::kInfinity;
do
{
double distance = (*face)->Safety(p, outgoing);
if (distance < best) best = distance;
}
while (++face < faces + numFace);
return (best < 0.5 * fgTolerance) ? 0 : best;
}
//
// GetEntityType
//
UGeometryType UVCSGfaceted::GetEntityType() const
{
return std::string("UCSGfaceted");
}
//
// Stream object contents to an output stream
//
std::ostream& UVCSGfaceted::StreamInfo(std::ostream& os) const
{
os << "-----------------------------------------------------------\n"
<< " *** Dump for solid - " << GetName() << " ***\n"
<< " ===================================================\n"
<< " Solid type: UVCSGfaceted\n"
<< " Parameters: \n"
<< " number of faces: " << numFace << "\n"
<< "-----------------------------------------------------------\n";
return os;
}
//
// GetCubVolStatistics
//
int UVCSGfaceted::GetCubVolStatistics() const
{
return fStatistics;
}
//
// GetCubVolEpsilon
//
double UVCSGfaceted::GetCubVolEpsilon() const
{
return fCubVolEpsilon;
}
//
// SetCubVolStatistics
//
void UVCSGfaceted::SetCubVolStatistics(int st)
{
fCubicVolume = 0.;
fStatistics = st;
}
//
// SetCubVolEpsilon
//
void UVCSGfaceted::SetCubVolEpsilon(double ep)
{
fCubicVolume = 0.;
fCubVolEpsilon = ep;
}
//
// GetAreaStatistics
//
int UVCSGfaceted::GetAreaStatistics() const
{
return fStatistics;
}
//
// GetAreaAccuracy
//
double UVCSGfaceted::GetAreaAccuracy() const
{
return fAreaAccuracy;
}
//
// SetAreaStatistics
//
void UVCSGfaceted::SetAreaStatistics(int st)
{
fSurfaceArea = 0.;
fStatistics = st;
}
//
// SetAreaAccuracy
//
void UVCSGfaceted::SetAreaAccuracy(double ep)
{
fSurfaceArea = 0.;
fAreaAccuracy = ep;
}
//
// Capacity
//
double UVCSGfaceted::Capacity()
{
if (fCubicVolume != 0.)
{
;
}
else
{
fCubicVolume = EstimateCubicVolume(fStatistics, fCubVolEpsilon);
}
return fCubicVolume;
}
//
// SurfaceArea
//
double UVCSGfaceted::SurfaceArea()
{
if (fSurfaceArea != 0.)
{
;
}
else
{
fSurfaceArea = EstimateSurfaceArea(fStatistics, fAreaAccuracy);
}
return fSurfaceArea;
}
//
// GetPointOnSurfaceGeneric proportional to Areas of faces
// in case of GenericPolycone or GenericPolyhedra
//
UVector3 UVCSGfaceted::GetPointOnSurfaceGeneric() const
{
// Preparing variables
//
UVector3 answer = UVector3(0., 0., 0.);
UVCSGface** face = faces;
double area = 0;
int i;
std::vector<double> areas;
// First step: calculate surface areas
//
do
{
double result = (*face)->SurfaceArea();
areas.push_back(result);
area = area + result;
}
while (++face < faces + numFace);
// Second Step: choose randomly one surface
//
UVCSGface** face1 = faces;
double chose = area * UUtils::Random();
double Achose1, Achose2;
Achose1 = 0;
Achose2 = 0.;
i = 0;
do
{
Achose2 += areas[i];
if (chose >= Achose1 && chose < Achose2)
{
UVector3 point;
point = (*face1)->GetPointOnFace();
return point;
}
i++;
Achose1 = Achose2;
}
while (++face1 < faces + numFace);
return answer;
}
double UVCSGfaceted::SafetyFromOutside(const UVector3& p, bool accurate) const
{
if (!accurate)
{
UVector3 pb(p.x, p.y, p.z - fBoxShift);
return fBox.SafetyFromOutside(pb);
}
return DistanceTo(p, false);
}
double UVCSGfaceted::SafetyFromInsideNoVoxels(const UVector3& p, bool) const
{
return DistanceTo(p, true);
}
void UVCSGfaceted::InitVoxels(UReduciblePolygon& rz, double radius)
{
int size = rz.NumVertices() + 1;
vector<double> r(size), z(size), zs;
rz.CopyVertices(&r[0], &z[0]);
fZs.clear();
for (int i = 0; i < size; ++i)
{
double v = z[i];
if (std::find(fZs.begin(), fZs.end(), v) == fZs.end())
{
fZs.push_back(v);
}
std::sort(fZs.begin(), fZs.end());
}
size = fZs.size();
fMaxSection = size - 2;
for (int i = 0; i <= fMaxSection; ++i)
{
vector<int> candidates;
double left = fZs[i], right = fZs[i + 1];
double middle = (left + right) / 2;
FindCandidates(middle, candidates);
FindCandidates(left, candidates, true);
FindCandidates(right, candidates, true);
fCandidates.push_back(candidates);
}
fBox.Set(radius, radius, (fZs.back() - fZs.front()) / 2);
fBoxShift = fZs[0] + fBox.GetZHalfLength();
}
void UVCSGfaceted::FindCandidates(double z, vector <int>& candidates, bool sides)
{
for (int j = 0; j < numFace; j++)
{
UVCSGface* face = faces[j];
double minZ = -face->Extent(UVector3(0, 0, -1)) ;
double maxZ = face->Extent(UVector3(0, 0, 1));
if (z >= minZ - fgTolerance * 10 && z <= maxZ + fgTolerance * 10)
{
if (!sides || std::fabs(minZ - maxZ) < fgTolerance * 10)
if (std::find(candidates.begin(), candidates.end(), j) == candidates.end())
candidates.push_back(j);
}
}
}
double UVCSGfaceted::DistanceToIn(const UVector3& p, const UVector3& v, double /*aPstep*/) const
{
if (fNoVoxels) return DistanceToInNoVoxels(p, v);
UVector3 pb(p.x, p.y, p.z - fBoxShift);
double idistance, shift;
idistance = fBox.DistanceToIn(pb, v); // using only box, this appears
// to be faster than: idistance = enclosingCylinder->DistanceTo(pb, v);
if (idistance >= UUtils::kInfinity) return idistance;
// this line can be here or not. not a big difference in performance
// TODO: fix enclosingCylinder for polyhedra!!! - the current radius appears to be too small
// if (enclosingCylinder->ShouldMiss(p, v)) return UUtils::kInfinity;
// this just takes too much time
// idistance = enclosingCylinder->DistanceTo(pb, v);
// if (idistance == UUtils::kInfinity) return idistance;
double z = p.z + idistance * v.z;
int index = GetSection(z);
int increment = (v.z > 0) ? 1 : -1;
if (std::fabs(v.z) < fgTolerance) increment = 0;
double distance = UUtils::kInfinity;
double distFromSurface = UUtils::kInfinity;
UVCSGface* bestFace = 0;
UBits bits(numFace);
UVector3 faceNormal;
do
{
const vector<int>& candidates = fCandidates[index];
int size = candidates.size();
for (int i = 0; i < size; ++i)
{
int candidate = candidates[i];
if (!bits[candidate])
{
bits.SetBitNumber(candidate);
UVCSGface& face = *faces[candidate];
double faceDistance,
faceDistFromSurface;
bool faceAllBehind;
if (face.Distance(p, v, false, fgTolerance * 0.5,
faceDistance, faceDistFromSurface,
faceNormal, faceAllBehind))
{
// Intersecting face
if (faceDistance < distance)
{
distance = faceDistance;
distFromSurface = faceDistFromSurface;
bestFace = &face;
if (distFromSurface <= 0) return 0;
}
}
}
}
if (!increment)
break;
index += increment;
if (index < 0 || index > fMaxSection)
break;
int newz = increment > 0 ? index : index + 1;
shift = (fZs[newz] - z) / v.z;
}
while (idistance + shift < distance);
if (distance < UUtils::kInfinity && distFromSurface < fgTolerance / 2)
{
if (bestFace->Safety(p, false) < fgTolerance / 2)
{
distance = 0;
}
}
return distance;
}
double UVCSGfaceted::DistanceToOut(const UVector3& p, const UVector3& v, UVector3& n, bool& aConvex, double /*aPstep*/) const
{
if (fNoVoxels) return DistanceToOutNoVoxels(p, v, n, aConvex);
int index = GetSection(p.z);
int increment = (v.z > 0) ? 1 : -1;
bool allBehind = true;
double distance = UUtils::kInfinity;
double distFromSurface = UUtils::kInfinity;
UVector3 normal, faceNormal;
double shift;
UVCSGface* bestFace = 0;
UBits bits(numFace);
do
{
const vector<int>& candidates = fCandidates[index];
int size = candidates.size();
for (int i = 0; i < size; ++i)
{
int candidate = candidates[i];
if (!bits[candidate])
{
bits.SetBitNumber(candidate);
UVCSGface& face = *faces[candidate];
double faceDistance, faceDistFromSurface;
bool faceAllBehind;
if ((face.Distance(p, v, true, fgTolerance * 0.5, faceDistance, faceDistFromSurface,
faceNormal, faceAllBehind)))
{
// Intersecting face
if ((distance < UUtils::kInfinity) || (!faceAllBehind))
{
allBehind = false;
}
if (faceDistance < distance)
{
distance = faceDistance;
distFromSurface = faceDistFromSurface;
normal = faceNormal;
bestFace = &face;
if (distFromSurface <= 0) break;
}
}
}
}
if (distFromSurface <= 0) break;
if (!increment) break;
index += increment;
if (index < 0 || index > fMaxSection)
break;
int newz = increment > 0 ? index : index + 1;
shift = (fZs[newz] - p.z) / v.z;
}
while (shift < distance);
if (distance < UUtils::kInfinity)
{
if (distFromSurface <= 0)
{
distance = 0;
}
else if (distFromSurface < fgTolerance / 2)
{
if (bestFace->Safety(p, true) < fgTolerance * 0.5)
{
distance = 0;
}
}
aConvex = allBehind;
n = normal;
}
else
{
if (Inside(p) == eSurface)
{
distance = 0;
}
aConvex = false;
}
return distance;
}
VUSolid::EnumInside UVCSGfaceted::Inside(const UVector3& p) const
{
if (fNoVoxels) return InsideNoVoxels(p);
// if (fEnclosingCylinder->MustBeOutside(p)) return eOutside;
int index = GetSection(p.z);
double shift;
UBits bits(numFace);
double best = UUtils::kInfinity;
VUSolid::EnumInside answer = eOutside;
int middle = index;
do
{
const vector<int>& candidates = fCandidates[index];
int size = candidates.size();
for (int i = 0; i < size; ++i)
{
int candidate = candidates[i];
if (!bits[candidate])
{
UVCSGface& face = *faces[candidate];
double distance;
VUSolid::EnumInside result = face.Inside(p, fgTolerance * 0.5, &distance);
if (result == eSurface) return eSurface;
if (distance < best)
{
best = distance;
answer = result;
}
bits.SetBitNumber(candidate);
}
}
if (index <= middle)
{
if (--index >= 0)
{
shift = fZs[index + 1] - p.z;
if (shift < best) continue;
}
index = middle;
}
if (++index > fMaxSection) break;
shift = p.z - fZs[index];
}
while (shift > best);
return answer;
}
double UVCSGfaceted::SafetyFromInsideSection(int index, const UVector3& p, UBits& bits) const
{
double best = UUtils::kInfinity;
const vector<int>& candidates = fCandidates[index];
int size = candidates.size();
for (int i = 0; i < size; ++i)
{
int candidate = candidates[i];
if (!bits[candidate])
{
bits.SetBitNumber(candidate);
UVCSGface& face = *faces[candidate];
double distance = face.Safety(p, true);
if (distance < best) best = distance;
}
}
return best;
}
double UVCSGfaceted::SafetyFromInside(const UVector3& p, bool) const
{
if (fNoVoxels) return SafetyFromInsideNoVoxels(p);
int index = UVoxelizer::BinarySearch(fZs, p.z);
if (index < 0 || index > fMaxSection) return 0;
UBits bits(numFace);
double minSafety = SafetyFromInsideSection(index, p, bits);
if (minSafety > UUtils::kInfinity) return 0;
if (minSafety < 1e-6) return 0;
double zbase = fZs[index + 1];
for (int i = index + 1; i <= fMaxSection; ++i)
{
double dz = fZs[i] - zbase;
if (dz >= minSafety) break;
double safety = SafetyFromInsideSection(i, p, bits);
if (safety < minSafety) minSafety = safety;
}
if (index > 0)
{
zbase = fZs[index - 1];
for (int i = index - 1; i >= 0; --i)
{
double dz = zbase - fZs[i];
if (dz >= minSafety) break;
double safety = SafetyFromInsideSection(i, p, bits);
if (safety < minSafety) minSafety = safety;
}
}
return (minSafety < 0.5 * fgTolerance) ? 0 : minSafety;
}
@@ -0,0 +1,236 @@
//
// ********************************************************************
// * This Software is part of the AIDA Unified Solids Library package *
// * See: https://aidasoft.web.cern.ch/USolids *
// ********************************************************************
//
// $Id:$
//
// --------------------------------------------------------------------
//
// UVector2
//
// 19.09.12 Marek Gayer
// Created from original implementation in CLHEP
// --------------------------------------------------------------------
#include <cmath>
#include <iostream>
#include "UVector2.hh"
double UVector2::tolerance = UVector2::ZMpvToleranceTicks * 2.22045e-16;
double UVector2::setTolerance(double tol)
{
// Set the tolerance for UVector2s to be considered near one another
double oldTolerance(tolerance);
tolerance = tol;
return oldTolerance;
}
double UVector2::operator()(int i) const
{
if (i == 0)
{
return x;
}
else if (i == 1)
{
return y;
}
else
{
// ZMthrowA(ZMxpvIndexRange("UVector2::operator(): bad index"));
return 0.0;
}
}
double& UVector2::operator()(int i)
{
static double dummy;
switch (i)
{
case X:
return x;
case Y:
return y;
default:
// ZMthrowA (ZMxpvIndexRange("UVector2::operator() : bad index"));
return dummy;
}
}
void UVector2::rotate(double angler)
{
double s = std::sin(angler);
double c = std::cos(angler);
double xx = x;
x = c * xx - s * y;
y = s * xx + c * y;
}
UVector2 operator/ (const UVector2& p, double a)
{
if (a == 0)
{
// ZMthrowA(ZMxpvInfiniteVector( "Division of UVector2 by zero"));
}
return UVector2(p.x / a, p.y / a);
}
std::ostream& operator << (std::ostream& os, const UVector2& q)
{
os << "(" << q.x << ", " << q.y << ")";
return os;
}
//void ZMinput2doubles ( std::istream & is, const char * type,
// double & x, double & y );
/*
std::istream & operator>>(std::istream & is, UVector2 & p) {
double x, y;
ZMinput2doubles ( is, "UVector2", x, y );
p.set(x, y);
return is;
} // operator>>()
*/
UVector2::operator UVector3() const
{
return UVector3(x, y, 0.0);
}
int UVector2::compare(const UVector2& v) const
{
if (y > v.y)
{
return 1;
}
else if (y < v.y)
{
return -1;
}
else if (x > v.x)
{
return 1;
}
else if (x < v.x)
{
return -1;
}
else
{
return 0;
}
} /* Compare */
bool UVector2::operator > (const UVector2& v) const
{
return (compare(v) > 0);
}
bool UVector2::operator < (const UVector2& v) const
{
return (compare(v) < 0);
}
bool UVector2::operator>= (const UVector2& v) const
{
return (compare(v) >= 0);
}
bool UVector2::operator<= (const UVector2& v) const
{
return (compare(v) <= 0);
}
bool UVector2::isNear(const UVector2& p, double epsilon) const
{
double limit = dot(p) * epsilon * epsilon;
return ((*this - p).mag2() <= limit);
} /* isNear() */
double UVector2::howNear(const UVector2& p) const
{
double d = (*this - p).mag2();
double pdp = dot(p);
if ((pdp > 0) && (d < pdp))
{
return std::sqrt(d / pdp);
}
else if ((pdp == 0) && (d == 0))
{
return 0;
}
else
{
return 1;
}
} /* howNear */
double UVector2::howParallel(const UVector2& v) const
{
// | V1 x V2 | / | V1 dot V2 |
// Of course, the "cross product" is fictitious but the math is valid
double v1v2 = std::fabs(dot(v));
if (v1v2 == 0)
{
// Zero is parallel to no other vector except for zero.
return ((mag2() == 0) && (v.mag2() == 0)) ? 0 : 1;
}
double abscross = std::fabs(x * v.y - y - v.x);
if (abscross >= v1v2)
{
return 1;
}
else
{
return abscross / v1v2;
}
} /* howParallel() */
bool UVector2::isParallel(const UVector2& v,
double epsilon) const
{
// | V1 x V2 | <= epsilon * | V1 dot V2 |
// Of course, the "cross product" is fictitious but the math is valid
double v1v2 = std::fabs(dot(v));
if (v1v2 == 0)
{
// Zero is parallel to no other vector except for zero.
return ((mag2() == 0) && (v.mag2() == 0));
}
double abscross = std::fabs(x * v.y - y - v.x);
return (abscross <= epsilon * v1v2);
} /* isParallel() */
double UVector2::howOrthogonal(const UVector2& v) const
{
// | V1 dot V2 | / | V1 x V2 |
// Of course, the "cross product" is fictitious but the math is valid
double v1v2 = std::fabs(dot(v));
if (v1v2 == 0)
{
return 0; // Even if one or both are 0, they are considered orthogonal
}
double abscross = std::fabs(x * v.y - y - v.x);
if (v1v2 >= abscross)
{
return 1;
}
else
{
return v1v2 / abscross;
}
} /* howOrthogonal() */
bool UVector2::isOrthogonal(const UVector2& v,
double epsilon) const
{
// | V1 dot V2 | <= epsilon * | V1 x V2 |
// Of course, the "cross product" is fictitious but the math is valid
double v1v2 = std::fabs(dot(v));
double abscross = std::fabs(x * v.y - y - v.x);
return (v1v2 <= epsilon * abscross);
} /* isOrthogonal() */
@@ -0,0 +1,164 @@
//
// ********************************************************************
// * This Software is part of the AIDA Unified Solids Library package *
// * See: https://aidasoft.web.cern.ch/USolids *
// ********************************************************************
//
// $Id:$
//
// --------------------------------------------------------------------
//
// UVector3
//
// 19.09.12 Marek Gayer
// Created from original implementation in CLHEP
// --------------------------------------------------------------------
#include "UVector3.hh"
#include "UUtils.hh"
//______________________________________________________________________________
UVector3::UVector3(double theta, double phi)
{
// Creates a unit vector based on theta and phi angles
x = std::sin(theta) * std::cos(phi);
y = std::sin(theta) * std::sin(phi);
z = std::cos(theta);
}
//______________________________________________________________________________
double UVector3::Angle(const UVector3& q) const
{
// return the angle w.r.t. another 3-vector
double ptot2 = Mag2() * q.Mag2();
if (ptot2 <= 0)
{
return 0.0;
}
else
{
double arg = Dot(q) / std::sqrt(ptot2);
if (arg > 1.0) arg = 1.0;
if (arg < -1.0) arg = -1.0;
return UUtils::ACos(arg);
}
}
//______________________________________________________________________________
double UVector3::Mag() const
{
// return the magnitude (rho in spherical coordinate system)
return std::sqrt(Mag2());
}
//______________________________________________________________________________
double UVector3::Perp() const
{
//return the transverse component (R in cylindrical coordinate system)
return std::sqrt(Perp2());
}
//______________________________________________________________________________
double UVector3::Phi() const
{
//return the azimuth angle. returns phi from -pi to pi
return x == 0.0 && y == 0.0 ? 0.0 : UUtils::ATan2(y, x);
}
//______________________________________________________________________________
double UVector3::Theta() const
{
//return the polar angle from 0 to pi
double mag2 = Mag2();
if (mag2 == 0.0) return 0.0;
return UUtils::ACos(z / std::sqrt(mag2));
}
//______________________________________________________________________________
UVector3 UVector3::Unit() const
{
// return unit vector parallel to this.
double tot = Mag2();
UVector3 p(x, y, z);
return tot > 0.0 ? p *= (1.0 / std::sqrt(tot)) : p;
}
//______________________________________________________________________________
double UVector3::Normalize()
{
// Normalize to unit. Return normalization factor.
double mag = Mag2();
if (mag == 0.0) return mag;;
mag = std::sqrt(mag);
x /= mag;
y /= mag;
z /= mag;
return mag;
}
//______________________________________________________________________________
void UVector3::RotateX(double angle)
{
//rotate vector around X
double s = std::sin(angle);
double c = std::cos(angle);
double yy = y;
y = c * yy - s * z;
z = s * yy + c * z;
}
//______________________________________________________________________________
void UVector3::RotateY(double angle)
{
//rotate vector around Y
double s = std::sin(angle);
double c = std::cos(angle);
double zz = z;
z = c * zz - s * x;
x = s * zz + c * x;
}
//______________________________________________________________________________
void UVector3::RotateZ(double angle)
{
//rotate vector around Z
double s = std::sin(angle);
double c = std::cos(angle);
double xx = x;
x = c * xx - s * y;
y = s * xx + c * y;
}
UVector3 operator + (const UVector3& a, const UVector3& b)
{
return UVector3(a.x + b.x, a.y + b.y, a.z + b.z);
}
UVector3 operator - (const UVector3& a, const UVector3& b)
{
return UVector3(a.x - b.x, a.y - b.y, a.z - b.z);
}
UVector3 operator * (const UVector3& p, double a)
{
return UVector3(a * p.x, a * p.y, a * p.z);
}
UVector3 operator / (const UVector3& p, double a)
{
a = 1. / a;
return UVector3(a * p.x, a * p.y, a * p.z);
}
UVector3 operator * (double a, const UVector3& p)
{
return UVector3(a * p.x, a * p.y, a * p.z);
}
double operator * (const UVector3& a, const UVector3& b)
{
return a.Dot(b);
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,109 @@
//
// ********************************************************************
// * License and Disclaimer *
// * *
// * The Geant4 software is copyright of the Copyright Holders of *
// * the Geant4 Collaboration. It is provided under the terms and *
// * conditions of the Geant4 Software License, included in the file *
// * LICENSE and available at http://cern.ch/geant4/license . These *
// * include a list of copyright holders. *
// * *
// * Neither the authors of this software system, nor their employing *
// * institutes,nor the agencies providing financial support for this *
// * work make any representation or warranty, express or implied, *
// * regarding this software system or assume any liability for its *
// * use. Please see the license in the file LICENSE and URL above *
// * for the full disclaimer and the limitation of liability. *
// * *
// * This code implementation is the result of the scientific and *
// * technical work of the GEANT4 collaboration and of QinetiQ Ltd, *
// * subject to DEFCON 705 IPR conditions. *
// * By using, copying, modifying or distributing the software (or *
// * any work based on the software) you agree to acknowledge its *
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
//
// $Id: VUFacet.cc,v 1.11 2010-09-23 10:30:07 gcosmo Exp $
// GEANT4 tag $Name: not supported by cvs2svn $
//
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//
//
// Author: Marek Gayer, started from original implementation by P R Truscott, 2004
//
#include "VUFacet.hh"
#include "VUSolid.hh"
using namespace std;
bool VUFacet::operator== (const VUFacet &right) const
{
double tolerance = kCarTolerance*kCarTolerance/4.0;
if (GetNumberOfVertices() != right.GetNumberOfVertices())
return false;
else if ((GetCircumcentre()-right.GetCircumcentre()).Mag2() > tolerance)
return false;
else if (std::fabs((right.GetSurfaceNormal()).Dot(GetSurfaceNormal())) < 0.9999999999)
return false;
bool coincident = true;
int i = 0;
do
{
coincident = false;
int j = 0;
do
{
coincident = (GetVertex(i)-right.GetVertex(j)).Mag2() < tolerance;
} while (!coincident && ++j < GetNumberOfVertices());
} while (coincident && ++i < GetNumberOfVertices());
return coincident;
}
///////////////////////////////////////////////////////////////////////////////
//
void VUFacet::ApplyTranslation(const UVector3 v)
{
int n = GetNumberOfVertices();
for (int i = 0; i < n; ++i)
SetVertex(i, GetVertex(i) + v);
}
///////////////////////////////////////////////////////////////////////////////
//
std::ostream &VUFacet::StreamInfo(std::ostream &os) const
{
os << endl;
os << "*********************************************************************" << endl;
os << "FACET TYPE = " << GetEntityType() << endl;
os << "ABSOLUTE VECTORS = " << endl;
int n = GetNumberOfVertices();
for (int i = 0; i < n; ++i)
os << "P[" << i << "] = " << GetVertex(i) << endl;
/*
os << "RELATIVE VECTORS = " << endl;
for (vector<UVector3>::const_iterator it=E.begin(); it!=E.end(); it++)
{ os << "E[" << it-E.begin()+1 << "] = " << *it << endl; }
*/
os << "*********************************************************************" << endl;
return os;
}
bool VUFacet::IsInside (const UVector3 &p) const
{
UVector3 d = p - GetVertex(0);
double displacement = d.Dot(GetSurfaceNormal());
return displacement <= 0.0;
}
const double VUFacet::dirTolerance = 1.0E-14;
const double VUFacet::kCarTolerance = VUSolid::Tolerance();
// G4GeometryTolerance::GetInstance()->GetSurfaceTolerance();
@@ -0,0 +1,347 @@
#include "VUSolid.hh"
////////////////////////////////////////////////////////////////////////////////
// "Universal" Solid Interface
// Authors: J. Apostolakis, G. Cosmo, M. Gayer, A. Gheata, A. Munnich, T. Nikitina (CERN)
//
// Created: 25 May 2011
//
////////////////////////////////////////////////////////////////////////////////
double VUSolid::fgTolerance = 1.0E-9; // cartesian tolerance; to be changed (for U was 1e-8, but we keep Geant4)
double VUSolid::frTolerance = 1.0E-9; // radial tolerance; to be changed
double VUSolid::faTolerance = 1.0E-9; // angular tolerance; to be changed
//______________________________________________________________________________
VUSolid::VUSolid() : fName()
{
}
//______________________________________________________________________________
VUSolid::VUSolid(const std::string &name) :
fName(name)
{
// Named constructor
SetName(name);
}
//______________________________________________________________________________
VUSolid::~VUSolid()
{
}
/*
int UIntersectingCone::LineHitsCone2( const UVector3 &p,
const UVector3 &v,
double &s1, double &s2 )
{
double x0 = p.x, y0 = p.y, z0 = p.z;
double tx = v.x, ty = v.y, tz = v.z;
// Special case which might not be so rare: B = 0 (precisely)
//
if (B==0)
{
if (std::fabs(tz) < 1/UUtils::kInfinity) { return 0; }
s1 = (A-z0)/tz;
return 1;
}
double B2 = B*B;
double a = tz*tz - B2*(tx*tx + ty*ty);
double b = 2*( (z0-A)*tz - B2*(x0*tx + y0*ty) );
double c = UUtils::sqr(z0-A) - B2*( x0*x0 + y0*y0 );
double radical = b*b - 4*a*c;
if (radical < -1E-6*std::fabs(b)) { return 0; } // No solution
if (radical < 1E-6*std::fabs(b))
{
//
// The radical is roughly zero: check for special, very rare, cases
//
if (std::fabs(a) > 1/UUtils::kInfinity)
{
if ( std::fabs(x0*ty - y0*tx) < std::fabs(1E-6/B) )
{
s1 = -0.5*b/a;
return 1;
}
return 0;
}
}
else
{
radical = std::sqrt(radical);
}
if (a < -1/UUtils::kInfinity)
{
double sa, sb, q = -0.5*( b + (b < 0 ? -radical : +radical) );
sa = q/a;
sb = c/q;
if (sa < sb) { s1 = sa; s2 = sb; } else { s1 = sb; s2 = sa; }
if ((z0 + (s1)*tz - A)/B < 0) { return 0; }
return 2;
}
else if (a > 1/UUtils::kInfinity)
{
double sa, sb, q = -0.5*( b + (b < 0 ? -radical : +radical) );
sa = q/a;
sb = c/q;
s1 = (tz*B > 0)^(sa > sb) ? sb : sa;
return 1;
}
else if (std::fabs(b) < 1/UUtils::kInfinity)
{
return 0;
}
else
{
s1 = -c/b;
if ((z0 + (s1)*tz - A)/B < 0) { return 0; }
return 1;
}
}
int UIntersectingCone::LineHitsCone2( const UVector3 &p,
const UVector3 &v,
double &s1, double &s2 )
{
double x0 = p.x, y0 = p.y, z0 = p.z;
double tx = v.x, ty = v.y, tz = v.z;
// Special case which might not be so rare: B = 0 (precisely)
//
if (B==0)
{
if (std::fabs(tz) < 1/UUtils::kInfinity) { return 0; }
s1 = (A-z0)/tz;
return 1;
}
double B2 = B*B;
double a = tz*tz - B2*(tx*tx + ty*ty);
double b = 2*( (z0-A)*tz - B2*(x0*tx + y0*ty) );
double c = UUtils::sqr(z0-A) - B2*( x0*x0 + y0*y0 );
double radical = b*b - 4*a*c;
if (radical < -1E-6*std::fabs(b)) { return 0; } // No solution
if (radical < 1E-6*std::fabs(b))
{
//
// The radical is roughly zero: check for special, very rare, cases
//
if (std::fabs(a) > 1/UUtils::kInfinity)
{
if ( std::fabs(x0*ty - y0*tx) < std::fabs(1E-6/B) )
{
s1 = -0.5*b/a;
return 1;
}
return 0;
}
}
else
{
radical = std::sqrt(radical);
}
if (a < -1/UUtils::kInfinity)
{
double sa, sb, q = -0.5*( b + (b < 0 ? -radical : +radical) );
sa = q/a;
sb = c/q;
if (sa < sb) { s1 = sa; s2 = sb; } else { s1 = sb; s2 = sa; }
if ((z0 + (s1)*tz - A)/B < 0) { return 0; }
return 2;
}
else if (a > 1/UUtils::kInfinity)
{
double sa, sb, q = -0.5*( b + (b < 0 ? -radical : +radical) );
sa = q/a;
sb = c/q;
s1 = (tz*B > 0)^(sa > sb) ? sb : sa;
return 1;
}
else if (std::fabs(b) < 1/UUtils::kInfinity)
{
return 0;
}
else
{
s1 = -c/b;
if ((z0 + (s1)*tz - A)/B < 0) { return 0; }
return 1;
}
}
*/
////////////////////////////////////////////////////////////////
//
// Returns an estimation of the solid volume in internal units.
// The number of statistics and error accuracy is fixed.
// This method may be overloaded by derived classes to compute the
// exact geometrical quantity for solids where this is possible.
// or anyway to cache the computed value.
// This implementation does NOT cache the computed value.
double VUSolid::Capacity()
{
int cubVolStatistics = 1000000;
double cubVolEpsilon = 0.001;
return EstimateCubicVolume(cubVolStatistics, cubVolEpsilon);
}
////////////////////////////////////////////////////////////////
//
// Calculate cubic volume based on Inside() method.
// Accuracy is limited by the second argument or the statistics
// expressed by the first argument.
// Implementation is courtesy of Vasiliki Despoina Mitsou,
// University of Athens.
double VUSolid::EstimateCubicVolume(int nStat, double epsilon) const
{
int iInside=0;
double px,py,pz,volume;
UVector3 min,max;
UVector3 p;
VUSolid::EnumInside in;
// values needed for CalculateExtent signature
// min max extents of pSolid along X,Y,Z
this->Extent(min,max);
// limits
if(nStat < 100) nStat = 100;
if(epsilon > 0.01) epsilon = 0.01;
for(int i = 0; i < nStat; i++ )
{
px = min.x+(max.x-min.x)*UUtils::Random();
py = min.y+(max.y-min.y)*UUtils::Random();
pz = min.z+(max.z-min.z)*UUtils::Random();
p = UVector3(px,py,pz);
in = this->Inside(p);
if(in != eOutside) iInside++;
}
volume = (max.x-min.x)*(max.y-min.y)*(max.z-min.z)*iInside/nStat;
return volume;
}
////////////////////////////////////////////////////////////////
//
// Returns an estimation of the solid surface area in internal units.
// The number of statistics and error accuracy is fixed.
// This method may be overloaded by derived classes to compute the
// exact geometrical quantity for solids where this is possible.
// or anyway to cache the computed value.
// This implementation does NOT cache the computed value.
double VUSolid::SurfaceArea()
{
int stat = 1000000;
double ell = -1.;
return EstimateSurfaceArea(stat,ell);
}
////////////////////////////////////////////////////////////////
//
// Estimate surface area based on Inside(), DistanceToIn(), and
// DistanceToOut() methods. Accuracy is limited by the statistics
// defined by the first argument. Implemented by Mikhail Kosov.
double VUSolid::EstimateSurfaceArea(int nStat, double ell) const
{
int inside=0;
double px,py,pz,surf;
UVector3 min,max;
UVector3 p;
VUSolid::EnumInside in;
// values needed for CalculateExtent signature
// min max extents of pSolid along X,Y,Z
this->Extent(min,max);
// limits
if(nStat < 100) { nStat = 100; }
double dX=max.x-min.x;
double dY=max.y-min.y;
double dZ=max.z-min.z;
if(ell<=0.) // Automatic definition of skin thickness
{
double minval=dX;
if(dY<dX) { minval=dY; }
if(dZ<minval) { minval=dZ; }
ell=.01*minval;
}
double dd=2*ell;
min.x-=ell; min.y-=ell; min.z-=ell; dX+=dd; dY+=dd; dZ+=dd;
for(int i = 0; i < nStat; i++ )
{
px = min.x+dX*UUtils::Random();
py = min.y+dY*UUtils::Random();
pz = min.z+dZ*UUtils::Random();
p = UVector3(px,py,pz);
in = this->Inside(p);
if(in != eOutside)
{
if (SafetyFromInside(p)<ell) { inside++; }
}
else if(SafetyFromOutside(p)<ell) { inside++; }
}
// @@ The conformal correction can be upgraded
surf = dX*dY*dZ*inside/dd/nStat;
return surf;
}
void VUSolid::ExtentAxis(EAxisType aAxis, double &aMin, double &aMax) const
// Returns the minimum and maximum extent along the specified Cartesian axis
{
// Returns extent of the solid along a given cartesian axis
if (aAxis >= 0 && aAxis <= 2)
{
UVector3 min, max;
Extent(min,max);
aMin = min[aAxis]; aMax = max[aAxis];
}
#ifdef USPECSDEBUG
else
cout << "Extent: unknown axis" << aAxis << std::endl;
#endif
}
void VUSolid::SetCarTolerance(double eps)
{
fgTolerance=eps;
}
void VUSolid::SetRadTolerance(double eps)
{
frTolerance=eps;
}
void VUSolid::SetAngTolerance(double eps)
{
faTolerance=eps;
}