Skip to content

Commit a9e17c7

Browse files
authored
Merge pull request #203 from brownd1978/ifix
Intersection fixes
2 parents 648ab33 + 7538611 commit a9e17c7

23 files changed

+221
-224
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@ debug/*
88
.vscode/*
99
.*.swp
1010
spack-*
11+
build-*
1112
.spack*

Examples/ShellXing.hh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ namespace KinKal {
7373
}
7474
mxings_.clear();
7575
// check if we are on the surface
76-
if(inter_.onsurface_ && inter_.inbounds_){
76+
if(inter_.good()){
7777
// compute the material
7878
}
7979
}

Fit/Track.hh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -725,9 +725,9 @@ namespace KinKal {
725725
while(fabs(time-tstart) < xtest.maxDt() && xtest.needsExtrapolation(*fittraj_,tdir) ){
726726
// create a domain for this extrapolation
727727
auto const& ktraj = fittraj_->nearestPiece(time);
728-
double dt = bfield_.rangeInTolerance(ktraj,time,xtest.tolerance()); // always positive
728+
double dt = bfield_.rangeInTolerance(ktraj,time,xtest.dpTolerance()); // always positive
729729
TimeRange range = tdir == TimeDir::forwards ? TimeRange(time,time+dt) : TimeRange(time-dt,time);
730-
Domain domain(range,bfield_.fieldVect(ktraj.position3(range.mid())),xtest.tolerance());
730+
Domain domain(range,bfield_.fieldVect(ktraj.position3(range.mid())),xtest.dpTolerance());
731731
addDomain(domain,tdir,true); // use exact transport
732732
time = tdir == TimeDir::forwards ? domain.end() : domain.begin();
733733
}

Geometry/Intersect.hh

Lines changed: 56 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,19 @@ namespace KinKal {
2424
Intersection retval;
2525
double ttest = tdir == TimeDir::forwards ? trange.begin() : trange.end();
2626
auto pos = ktraj.position3(ttest);
27-
double speed = ktraj.speed(ttest); // speed is constant
27+
double rbend = ktraj.bendRadius();
28+
double tstep = trange.range();
29+
double speed = ktraj.speed();
30+
// if there's curvature, take smaller steps
31+
if(rbend > 0.0){
32+
double tlenmax = 2.0*sqrt(2.0*rbend*tol); // maximum transverse length keeping the sagitta within tolerance
33+
double tspeed = ktraj.transverseSpeed();
34+
tstep = std::min(tstep,(tlenmax+tol)/tspeed); // trajectory range defines maximum step
35+
}
36+
// sign!
37+
tstep *= timeDirSign(tdir);
2838
bool startinside = surf.isInside(pos);
2939
bool stepinside;
30-
// set the step according to the range and tolerance. The maximum range division is arbitrary, it should be set to a physical value TODO
31-
double tstep = timeDirSign(tdir)*std::max(0.05*trange.range(),tol/speed); // trajectory range defines maximum step
3240
unsigned niter(0);
3341
// step until we cross the surface or the time is out of range
3442
do {
@@ -82,8 +90,8 @@ namespace KinKal {
8290
retval.norm_ = surf.normal(retval.pos_);
8391
}
8492
}
85-
// check the final time to be in range; if we're out of range, negate the intersection
86-
if(!trange.inRange(retval.time_))retval.inbounds_ = false; // I should make a separate flag for time bounds TODO
93+
// check the final time to be in range
94+
retval.inrange_ = trange.inRange(retval.time_);
8795
return retval;
8896
}
8997
//
@@ -117,10 +125,13 @@ namespace KinKal {
117125

118126
template < class HELIX> Intersection hcIntersect( HELIX const& helix, KinKal::Cylinder const& cyl, TimeRange trange ,double tol,TimeDir tdir = TimeDir::forwards) {
119127
Intersection retval;
128+
// test if the range is lnger than the radius. If so, make an axial approximation
129+
double rbend = fabs(helix.bendRadius());
120130
// compare directions and divide into cases
121131
double ddot = fabs(helix.bnom().Unit().Dot(cyl.axis()));
122-
if (ddot > 0.9) { // I need a more physical co-linear test TODO
123-
// the helix and cylinder are roughly co-linear.
132+
if(rbend < trange.range()*helix.transverseSpeed() && ddot > 0.9) { // mostly co-linear
133+
// the helix and cylinder are roughly co-linear, and the helix loops within this range
134+
// first try to limit the range using disk-axis intersections
124135
// see if the range is in bounds
125136
auto binb = cyl.inBounds(helix.position3(trange.begin()),tol);
126137
auto einb = cyl.inBounds(helix.position3(trange.end()),tol);
@@ -150,57 +161,56 @@ namespace KinKal {
150161
}
151162
}
152163
}
153-
// } else if (ddot < 0.1) {
154-
// // the helix and cylinder are mostly orthogonal, use POCA to the axis to find an initial estimate, then do a linear search
155-
// // TODO. Construct a KinematicLine object from the helix axis, and a GeometricLine from the cylinder, then invoke POCA.
156-
} else {
157-
// intermediate case: use step intersection
158-
retval = stepIntersect(helix,cyl,trange,tol,tdir);
159-
}
160-
return retval;
164+
} else {
165+
// intermediate case: use step intersection
166+
retval = stepIntersect(helix,cyl,trange,tol,tdir);
167+
}
168+
return retval;
161169
}
162170
//
163171
// Helix and planar surfaces
164172
//
165173
template <class HELIX> Intersection hpIntersect( HELIX const& helix, KinKal::Plane const& plane, TimeRange trange ,double tol,TimeDir tdir = TimeDir::forwards) {
166174
Intersection retval;
167-
double tstart = tdir == TimeDir::forwards ? trange.begin() : trange.end();
168-
auto axis = helix.axis(tstart);
169-
if(tdir == TimeDir::backwards)axis.reverse();
170-
// test for the helix being circular or tangent to the plane
171-
double vz = helix.axisSpeed(); // speed along the helix axis
172-
double ddot = fabs(axis.direction().Dot(plane.normal()));
173-
double zrange = fabs(vz*trange.range());
174-
if(zrange > tol && ddot > tol/zrange ){
175-
// Find the intersection time of the helix axis (along bnom) with the plane
176-
double dist(0.0);
177-
auto pinter = plane.intersect(axis,dist,true,tol);
178-
if(pinter.onsurface_){
179-
// translate the axis intersection to a time
180-
double tmid = tstart + timeDirSign(tdir)*dist/vz;
181-
// bound the range of intersections by the extrema of the cylinder-plane intersection
182-
double tantheta = sqrt(std::max(0.0,1.0 -ddot*ddot))/ddot;
183-
double dt = std::max(tol/vz,helix.bendRadius()*tantheta/vz); // make range finite in case the helix is exactly co-linear with the plane normal
184-
// if we're already in tolerance, finish
185-
if(dt*vz/ddot < tol){
186-
retval.onsurface_ = pinter.onsurface_;
187-
retval.inbounds_ = pinter.inbounds_;
188-
retval.time_ = tmid;
189-
retval.pos_ = helix.position3(tmid);
190-
retval.pdir_ = helix.direction(tmid);
191-
retval.norm_ = plane.normal(retval.pos_);
192-
} else {
175+
// test if the range is lnger than the radius. If so, make an axial approximation
176+
double rbend = fabs(helix.bendRadius());
177+
if(rbend > trange.range()*helix.transverseSpeed()){
178+
retval = stepIntersect(helix,plane,trange,tol,tdir);
179+
} else {
180+
// the trajectory curves macroscopically over this range: see if the axis is normal
181+
double tstart = tdir == TimeDir::forwards ? trange.begin() : trange.end();
182+
auto ray = helix.linearize(tstart);
183+
auto velo = helix.velocity(tstart);
184+
if(tdir == TimeDir::backwards) ray.reverse(); // reverse if going backwards in time
185+
double vax = velo.Dot(ray.direction()); // speed along axis
186+
// test for the helix being circular or tangent to the plane
187+
double ddot = fabs(ray.direction().Dot(plane.normal()));
188+
double zrange = fabs(vax*trange.range());
189+
if(zrange > tol && ddot > tol/zrange ){
190+
// Find the intersection time of the helix ray (along bnom) with the plane to reduce the range
191+
double dist(0.0);
192+
auto pinter = plane.intersect(ray,dist,true,tol);
193+
if(pinter.onsurface_){
194+
// translate the ray intersection distance to a time
195+
double tmid = tstart + dist/vax;
196+
// bound the range of intersections by the extrema of the cylinder-plane intersection
197+
double tantheta = sqrt(std::max(1.0 -ddot*ddot,0.0))/ddot;
198+
// distance along axis to the surface to bound the reduced range; add tolerance
199+
double dd = tol+rbend*tantheta;
200+
// intersection should be bounded by the
201+
auto dt = fabs(dd/vax);
193202
TimeRange srange(tmid-dt,tmid+dt);
203+
// if this range overlaps with the original, compute the intersection
194204
if(srange.restrict(trange)){
195205
// step to the intersection in the restricted range. Use a separate intersection object as the
196206
// range is different
197207
retval = stepIntersect(helix,plane,srange,tol,tdir);
198208
}
199209
}
210+
} else {
211+
// simply step to intersection
212+
retval = stepIntersect(helix,plane,trange,tol,tdir);
200213
}
201-
} else {
202-
// simply step to intersection
203-
retval = stepIntersect(helix,plane,trange,tol,tdir);
204214
}
205215
return retval;
206216
}
@@ -291,8 +301,8 @@ namespace KinKal {
291301
// calculate the time
292302
retval.time_ = tstart + dist*timeDirSign(tdir)/kkline.speed(tstart);
293303
}
294-
// check the final time to be in range; if we're out of range, negate the intersection
295-
if(!trange.inRange(retval.time_))retval.inbounds_ = false; // I should make a separate flag for time bounds TODO
304+
// check the final time to be in range;
305+
retval.inrange_ = trange.inRange(retval.time_);
296306
return retval;
297307
}
298308
// generic surface intersection cast down till we find something that works. This will only be used for helices, as KinematicLine

Geometry/IntersectFlag.cc

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,8 @@
66
std::ostream& operator <<(std::ostream& ost, KinKal::IntersectFlag const& iflag) {
77
if(iflag.onsurface_){
88
ost << "On surface ";
9-
if(iflag.inbounds_){
10-
ost << " and in bounds ";
11-
}
9+
if(iflag.inbounds_)ost << " in bounds ";
10+
if(iflag.inrange_)ost << " in range ";
1211
}else {
1312
ost << "No Intersection";
1413
}

Geometry/IntersectFlag.hh

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,11 @@ namespace KinKal {
1212
struct IntersectFlag {
1313
bool onsurface_ = false; // intersection is on the surface
1414
bool inbounds_ = false; // intersection is inside the surface boundaries
15-
bool operator ==(IntersectFlag const& other) const { return other.onsurface_ == onsurface_ && other.inbounds_ == inbounds_; }
16-
bool operator !=(IntersectFlag const& other) const { return other.onsurface_ != onsurface_ || other.inbounds_ != inbounds_; }
15+
bool inrange_ = false; // intersection is inside the time range
16+
bool operator ==(IntersectFlag const& other) const { return other.onsurface_ == onsurface_ && other.inbounds_ == inbounds_ && other.inrange_ == inrange_;}
17+
bool operator !=(IntersectFlag const& other) const { return other.onsurface_ != onsurface_ || other.inbounds_ != inbounds_ || other.inrange_ != inrange_;}
18+
bool good() const { return onsurface_ && inbounds_ && inrange_; }
19+
friend std::ostream& operator <<(std::ostream& ost, KinKal::IntersectFlag const& iflag);
1720
};
1821
}
19-
std::ostream& operator <<(std::ostream& ost, KinKal::IntersectFlag const& iflag);
2022
#endif

Geometry/Intersection.cc

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,18 @@
22
#include <stdexcept>
33
#include <iostream>
44
#include <cstdio>
5-
6-
std::ostream& operator <<(std::ostream& ost, KinKal::Intersection const& inter) {
7-
if(inter.onsurface_){
8-
ost << "Intersection at time " << inter.time_ << " position " << inter.pos_ << " surface normal " << inter.norm_;
9-
if(inter.inbounds_){
10-
ost << " in bounds ";
5+
namespace KinKal {
6+
std::ostream& operator <<(std::ostream& ost, KinKal::Intersection const& inter) {
7+
if(inter.onsurface_){
8+
ost << "Intersection on surface ";
9+
if(inter.inbounds_) ost << " in bounds ";
10+
if(inter.inrange_) ost << " in time range ";
11+
} else {
12+
ost << "No Intersection";
1113
}
12-
}else {
13-
ost << "No Intersection";
14+
if(inter.good()){
15+
ost << " at time " << inter.time_ << " position " << inter.pos_ << " surface normal " << inter.norm_;
16+
}
17+
return ost;
1418
}
15-
return ost;
1619
}

Geometry/Intersection.hh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ namespace KinKal {
1919
double time_ = 0.0; // time at intersection (from particle)
2020
bool gap_ = false; // intersection is in a piecewise-trajectory gap
2121
Ray ray() const { return Ray(pdir_,pos_); } // linear particle trajectory at intersection
22+
friend std::ostream& operator << (std::ostream& ost, KinKal::Intersection const& inter);
2223
};
2324
}
24-
std::ostream& operator <<(std::ostream& ost, KinKal::Intersection const& inter);
2525
#endif

0 commit comments

Comments
 (0)