+ private color calculateSpokeColor(final PVector pt) {
+ // Find the closest spoke's t-value and calculate its
+ // axis. Until everything animates in the model reference
+ // frame, this has to be calculated at every step because
+ // the helices rotate.
+ Line axis = h1.getAxis();
+ float t = axis.getTValue(pt) + spokePhase;
+ int spokeIndex = (int)floor((t - tMin + spokePeriod/2) / spokePeriod);
+ if (spokeIndex < 0 || spokeIndex >= basePairs.length) {
+ return lx.hsb(0,0,0);
+ }
+ BasePairInfo basePair = basePairs[spokeIndex];
+ Line spokeLine = basePair.line;
+ PVector pointOnSpoke = spokeLine.projectPoint(pt);
+ float d = PVector.dist(pt, pointOnSpoke);
+ float b = (PVector.dist(pointOnSpoke, spokeLine.getPoint()) < spokeRadius) ? constrain(100*(1 - ((d-.5*spokeGirth)/(spokeGirth*.5))), 0, 100) : 0.f;
+ float phase = spokeLine.getTValue(pointOnSpoke) < 0 ? basePair.colorPhase1 : basePair.colorPhase2;
+ return lx.hsb((lx.getBaseHuef() + (360*(phase / TWO_PI)))%360, 80.f, b);
+ }
+
+ void run(double deltaMs) {