Exit
  • Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
  • 한국 커뮤니티
0

Expression generates correct value, yet incorrect value gets returned

Contributor ,
Jan 22, 2023 Jan 22, 2023

Here's the issue I'm having: 

 

I'm buildng out a multi-line text mogrt with background text boxes. The boxes bound individual lines and size themselves according to how long the text is + room for padding on each side. 

 

Within each line's size attribute, the expression also "checks" the adjacent text-box widths to see if they are a tiny bit bigger ( <= 5% to be exact). 

 

If the adjacent lines are <= 5% bigger then the current line will take the slightly-larger size of the adjacent line. 

 

For example:

 

Line 5's text box *would be* 920 pixels wide normally. But because line 4's is 932 pixels wide, line 5 will now also be 932 pixels. 

 

I've verified that my expression is determining these correct values with a dedicated "debugging" text layer-- basically acting as a console print. This layer shows 920 as the "original" length. And 932 as the final returned value. 

 

However,  for some reason the Line 5 remains 920. Sometimes it will show 932 for a single frame, before returning to 920. Strangely, even when it shows 932, the size of the text box never actually changes. As if the value is not "sticking" somehow.

 

Anyone have any ideas? Having a hard time troubleshooting this. 

 

Thanks

 

TOPICS
Expressions
1.3K
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Jan 22, 2023 Jan 22, 2023

What does the expression look like?

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Contributor ,
Jan 22, 2023 Jan 22, 2023

Here's the relevant portion, hopefully it's not too esoteric.

 

In this example:

lineNum = 5

conformThreshold = 0.95 (ie, within 5%, as described above)

sizeReturn = the [x,y] size of the text box, defined further up in the expression. basically the sum of the sourceRectAtTime.width + padding slider.

 

at the point at which this sample code begins, sizeReturn = [920.89,  119]

line4 size = [932.94, 119]

The text debugger layer (copy pasted from the expression istelf) indicate the final value for sizeReturn is [932.94, 119] which is the expected result.

The value in the actual size attribute however remains [920.89, 119]

No errors. 

 

// Compare and conform length. Define vars.
conformThreshhold = comp("vars").layer("primary").effect("lineSizeConformThreshold")("Slider");
nextLineNum = lineNum + 1;
nextLineName = "line" + nextLineNum;
nextLinePathName = "line" + nextLineNum + "path";
previousLineNum = lineNum - 1;
previousLineName = "line" + previousLineNum;
previousLinePathName = "line" + previousLineNum + "path";
	
if (lineNum < 5) {
	// If not the last line, conform size as needed
	thisLineSizeX = sizeReturn[0];
	nextLineSizeX = thisComp.layer("Per Line Text Box").content(nextLineName).content(nextLinePathName).size[0];
	if (thisLineSizeX < nextLineSizeX && thisLineSizeX / nextLineSizeX >= conformThreshhold) {
		sizeReturn[0] = nextLineSizeX;
	};
};
// Compare and conform length. Checking backwards.
if (lineNum > 1) {
	// If not the last line, conform size as needed
	thisLineSizeX = sizeReturn[0];
	previousLineSizeX = thisComp.layer("Per Line Text Box").content(previousLineName).content(previousLinePathName).size[0];
	if (thisLineSizeX < previousLineSizeX && thisLineSizeX / previousLineSizeX >= conformThreshhold) {
		sizeReturn[0] = previousLineSizeX;
	};
};

sizeReturn;

 

 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Jan 22, 2023 Jan 22, 2023

I'm not sure this is relevant to the problem you're seeing but I think your expression could get into an unstable/race condition. Say Line 3's length is 108, Line 4 is 100 and Line 5 is 104. The expression for Line 4 will first check Line 5's length and adopt its 104 length because it's within 5%. Then using its new length it will compare against Line 3 and adopt 108 because it's now within 5% of that. Meanwhile, Line 5's expression will notice that Line 4 is 108 and Line 5 will adopt 108. This means that when Line 4's expression next runs, it will decide that Line 5 and Line 3 are both too far away and will revert back to 100. I think the result would be unpredictable.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Contributor ,
Jan 22, 2023 Jan 22, 2023

You're right and I believe I also observed that behavior in my testing. That might be reason enough to scrap this appracoh altogether. 

 

It's just starnge to me why the size is stuck on 920 when all indications suggest that the returned result is 932.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Jan 22, 2023 Jan 22, 2023

You need to be using Math.max(text 1, text 2) instead of an if statement. Here are my expression for the shape layer size and shape layer position for a three line text box:

// Rectangle Size
//source layers 
src1 = thisComp.layer(index - 3);
src2 = thisComp.layer(index - 2);
src3 = thisComp.layer(index - 1);


// text size
tBox1 = src1.sourceRectAtTime();
tBox2 = src2.sourceRectAtTime();
tBox3 = src3.sourceRectAtTime();

// max width
tWidth = Math.max(tBox1.width, tBox2.width, tBox3.width).toFixed(2);

//  layer spacing 
lyrSpace = effect("Leading Middle")("Slider") + effect("Leading Bottom")("Slider");

// total height
srcHeight = Math.ceil(tBox1.height + tBox2.height + tBox3.height);
tHeight = srcHeight + lyrSpace;

// box size
txtBase = [tWidth, tHeight];

// padding control
cornerPad = content("Rectangle 1").content("Rectangle Path 1").roundness;
hPad = tWidth * effect("H Padding")("Slider") * .01;
vPad = tHeight * effect("V Padding")("Slider") * .01;


// wipe
wipe = linear(effect("Wipe On")("Slider"), 100, 0, 0, 1);


box = [(hPad + cornerPad), vPad] + [txtBase[0], txtBase[1]];
[box[0] * wipe, box[1]]

//Rectangle/Position
//source layers 
src1 = thisComp.layer(index - 3);
src2 = thisComp.layer(index - 2);
src3 = thisComp.layer(index - 1);

// text size
tBox1 = src1.sourceRectAtTime();
tBox2 = src2.sourceRectAtTime();
tBox3 = src3.sourceRectAtTime();

// max width
tWidth = Math.max(tBox1.width, tBox2.width, tBox3.width).toFixed(2);

lyrSpace = src3.position[1] + src1.position[1] - thisComp.height;

boxHeight = tBox1.height + tBox2.height + tBox3.height;
refScale = thisComp.layer(index - 3).scale * .01;
x = tWidth / 2;
y = boxHeight / 2;
lineSp = effect("Leading Middle")("Slider")/2 + effect("Leading Bottom")("Slider")/2;
t = tBox1.top + lineSp;

// max width
maxWidth = Math.max(tBox1.width, tBox2.width, tBox3.width).toFixed(2);

// wipe
wipe = linear(effect("Wipe On")("Slider"), 100, 0, 0, 1);
lftPad = effect("H Padding")("Slider") * .01 * maxWidth;
lftOfst = (maxWidth + lftPad) / 2;

// set position
if (tBox1.width.toFixed(2) == maxWidth)
	l = tBox1.left;
if (tBox2.width.toFixed(2) == maxWidth)
	l = tBox2.left;
if (tBox3.width.toFixed(2) == maxWidth)
	l = tBox3.left;

newBox = [(x + l) * refScale[0], (y + t) * refScale[1]];

[newBox[0] * wipe, newBox[1]]

// Shape layer position:
thisComp.layer(index - 3).transform.position

I've added sliders and an expression for roundness to the mix. You should be able to modify the approach to your project.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Contributor ,
Jan 22, 2023 Jan 22, 2023

Thanks, I like this approach. However, the difference with mine is that I'm effectively stacking 5 different one-line text boxes to make a 5 line polygonal text box, each conforming to the width + padding of their corresponding text.

 

I have that working already-- this issue here is about equalizing sizes between adjacent lines. So you don't have adjacent lines that are *almost* the same width. They're either exactly the same, or  >5% different.

 

I have a new idea for how to do that, it's just odd to me that the returned result I'm getting in this example is not the result I'm seeing in the actual size attribute. 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Jan 22, 2023 Jan 22, 2023

If you use Math.max(layer1, 2, 3, 4, 5)  to look for the widest layer using sourceRectAtTime().width for the five layers you want to compare, you will always find the widest layer in the stack. The math is a lot easier than all those if statements. 

 

If you have a separate background behind each line of text, you can just write a simple expression for each shape that says something like this:

t1 = thisComp.layer(index - 4).sourceRectAtTime().width;
t2 = thisComp.layer(index - 3).sourceRectAtTime().width;
t3 = thisComp.layer(index - 2).sourceRectAtTime().width;
t4 = thisComp.layer(index - 1).sourceRectAtTime().width;
maxWidth = Math.max(t1, t2, t3, t4);
if (maxWidth / 1.2 < t1){
	[maxWidth, 20]
}
else{
	[t1, 20];
}

I have attached a project file. If you scale in X using the character Panel or change the text on the 4 layers in the project, they snap to the widest layer when the difference becomes 20%

 

Maybe that will help. 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Contributor ,
Jan 23, 2023 Jan 23, 2023

Thanks Rick, appreacite your help. 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Jan 22, 2023 Jan 22, 2023

This won't work. The problem here is that you never have a persistent value anywhere and AE keeps re-evaluating the expression over and over. It's a limitation in how AE expressions work and a design flaw in your setup. You need to calculate all the values independently and sort them in some form e.g. in an array in a text layer, then simply fetch the values from there with simple expressions. That way things don't jump around and when a value changes all layers update correctly.

 

Mylenium 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Contributor ,
Jan 23, 2023 Jan 23, 2023

Yeah agreed. I have a null that is loaded with saved variables, but was hoping to avoid doing that for each line. Thus far, each line has the same code for generating the size. From a refactoring perspective this is certainly preferable than hard coding references to specific lines numbers, but if statements may be code smell, and a signal to redesign. 

 

To be hoenst, I'm more confused by the returned value of the size layer being different from the "console" text layer, even though they both use the same code... 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Jan 23, 2023 Jan 23, 2023
LATEST

It might be because the debug layer isn't in the feedback loop created by the shape layer expressions that feed into each other. The debug layer is just a non-participating observer.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines