Ok, it's relatively straightforward using some expressions. But then again isn't everything?
Assuming you've got your original rotating beam layer, your epicycle layer which is parented to the original beam, and your Venus layer parented to that. You need to find the co-ordinates of the center of the Venus layer, relative to the Composition, in order to draw a beam to it.
Well you could work it out trigonometrically I'm sure, but it's way too late and I've been into the Irish Single Malt, so I'm not going to go there. Luckily there's a handy expression that does the job: toComp(point)
. What it does is find the composition co-ordinates of a point on a layer.
First we apply a Point Control effect Effects>Expression Controls>Point Control to the Venus layer, we'll use the toComp
expression to set its value. But before that, make sure the Anchor Point property of the Venus layer is showing – we'll need it in a second.
Now to apply an expression to the point control alt/opt-click the stopwatch on the Point property of that effect. In the expressions editor that opens up type toComp(
and then drag the expression pick-whip to the Anchor Point property to fill in the value Transfrom.AnchorPoint
. You can type it, but it's case sensitive and not at all forgiving of typos. Then close the brackets: )
it should now read toComp(transform.anchorPoint)
.
So now you have a point that tells you where exactly the Venus Layer's anchor point is in the comp. Using an expression you could plug this straight into the End Point property of the Beam effect, but I'm allergic to the beam effect, I prefer to use shape layers, because vectors.
So I make a new rectangular shape layer with the stroke I want, and no fill, and I set all the transforms to 0. The size of the rectangle path is going to be the length between the start of the original beam, and the value of the Point Control point, AKA the position of Venus. You can do this by getting the square root of the sum of the squares of the X and Y offsets, but that's a bit 6th century BC, instead we'll use the handy expression length(point1, point2)
. And we'll set the height to 0, so that it draws a line.
So on the rectangle shape layer, in the Contents>Rectangle 1>Rectangle Path 1 Property we'll use this expression:
origin=thisComp.layer("origin");
venus=thisComp.layer("venus")
beamlength=length(origin.transform.position, venus.effect("Point Control")("Point"));
[beamlength,0]
layer origin is the original beam. You could do it all on one line, but it would be hella ugly:
[length(thisComp.layer("origin").transform.position,thisComp.layer("venus").effect("Point Control")("Point")),0]
Beauty is truth.
Since by default the rectangle tool draws rectangles around a central point we need to offset it. In the Contents>Rectangle 1>Rectangle Path 1>Position Property (not the layer's position property, that should be the same as the original beam, or the shape's Contents>Rectangle 1>Transform: Rectangle 1>position property, that should be 0,0) we offset it by half the width, so that the rectangle's left edge is always at the origin, thus : content("Rectangle 1").content("Rectangle Path 1").size/2
(did you notice that we're dividing a vector by a scalar? 100 Nerd points to you if you did.)
Now we've got a beam that is the right length, but we need to rotate it. Thank you and good night Pythagoras, hello Mr Aryabhata. Since we know the rise and the run, we can find the angle using Atan(rise/run). But there's some problems: when the run is negative Atan will return a positive value, and whenever the run is 0 the expression will crash. And lastly Math.atan
returns a result in Radians, so we need to convert it to degrees. So we have to turn a relatively simple expression into this monster, which goes on the Contents>Rectangle 1>Transform: Rectangle 1>Rotation Property:
s=thisComp.layer("venus").effect("Point Control")("Point");
o=thisComp.layer("origin").transform.position;
run=s[0]-o[0];
rise=s[1]-o[1];
if (run==0){
if (rise>0) //pointing straight up
{-90;}
else //pointing straight down
{90;}
} else{
if (run>0){
radiansToDegrees(Math.atan(rise/run));
} else {
180+radiansToDegrees(Math.atan(rise/run));
}
}
this is how my beam layer looks:
and below is the whole comp. I've used shape layers for everything and driven them all by expressions as is my wont, if you want to have a look at it, it's here.