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

[Javascript] Calculate area coverage polygon object

Contributor ,
Jan 18, 2018 Jan 18, 2018

Copy link to clipboard

Copied

Hi,

Does anyone know if it's possible to calculate the total coverage of an irregular polygon shape in Adobe Indesign?

Something like this:

Is there a way to calculate the area of a shape?

Thanks

TOPICS
Scripting

Views

5.9K

Translate

Translate

Report

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

correct answers 1 Correct answer

Guide , Jan 30, 2018 Jan 30, 2018

Hi all,

In case your splines do not auto-intersect, try this:

var pathArea = function(/*[x,y][3][]*/ep,  r,n,i,P,Q,xa,ya,xb,yb,xc,yc,xd,yd)

//----------------------------------

// Based on http://www.gust.org.pl/bachotex/2011-en/presentations/JackowskiB_3c_2011

// Return AREA x 20 ; result is signed.

{

    for( r=0, n=ep.length, i=-1 ; ++i < n ; )

    {

        3 == (P=ep).length ?

            ( xa=P[1][0], ya=P[1][1], xb=P[2][0], yb=P[2][1] ) :

            ( xa=xb=P[0], ya=yb=P[1]);

        3 == (Q=ep[(1+i

...

Votes

Translate

Translate
Community Expert ,
Jan 18, 2018 Jan 18, 2018

Copy link to clipboard

Copied

Maybe the best I can offer is cross-scripting with Illustrator.
There should be an area property, I think.

For that you would need to copy the polygon over to Illustrator.

With InDesign you would do that in a very time-consuming way. Just possible workarounds, no direct way.

One would be:

1. Do a text wrap with the shape.

2. Move a tiny text frame square with tiny contents step by step along.

3. Check after every move if the text frame is overset.

This works like a scanning mechanism and you are counting squares that add up to an area.

Regards,
Uwe

Votes

Translate

Translate

Report

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 18, 2018 Jan 18, 2018

Copy link to clipboard

Copied

Another idea: Export to a pixel format with high resolution and count drawing pixels in PhotoShop.
That should also be possible by scripting.

Search for BridgeTalk here in the Scripting forum.

Kasyan Servetsky has some nice examples for cross-scripting InDesign with PhotoShop.

Regards,
Uwe

Votes

Translate

Translate

Report

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 29, 2018 Jan 29, 2018

Copy link to clipboard

Copied

Hi,

Is this something that can be used to calculate the surface area in Indesign, without using any additional applications ?

javascript - How can I calculate the area of a bezier curve? - Stack Overflow

Thanks

Votes

Translate

Translate

Report

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
Guide ,
Jan 30, 2018 Jan 30, 2018

Copy link to clipboard

Copied

Hi all,

In case your splines do not auto-intersect, try this:

var pathArea = function(/*[x,y][3][]*/ep,  r,n,i,P,Q,xa,ya,xb,yb,xc,yc,xd,yd)

//----------------------------------

// Based on http://www.gust.org.pl/bachotex/2011-en/presentations/JackowskiB_3c_2011

// Return AREA x 20 ; result is signed.

{

    for( r=0, n=ep.length, i=-1 ; ++i < n ; )

    {

        3 == (P=ep).length ?

            ( xa=P[1][0], ya=P[1][1], xb=P[2][0], yb=P[2][1] ) :

            ( xa=xb=P[0], ya=yb=P[1]);

        3 == (Q=ep[(1+i)%n]).length ?

            ( xc=Q[0][0], yc=Q[0][1], xd=Q[1][0], yd=Q[1][1] ) :

            ( xc=xd=Q[0], yc=yd=Q[1]);

       

        r += (xb-xa)*(10*ya + 6*yb + 3*yc +    yd)

          +  (xc-xb)*( 4*ya + 6*yb + 6*yc +  4*yd)

          +  (xd-xc)*(   ya + 3*yb + 6*yc + 10*yd);

    }

    return r;

};

var splineArea = function(/*SplineItem*/o,  a,r,i,n,t)

//----------------------------------

// Visit every closed path and calculate the total area.

{

    const CLOSED = +PathType.CLOSED_PATH;

    a = o.paths.everyItem().getElements();

    for( r=0, n=a.length, i=-1 ; ++i < n && (t=a).pathType==CLOSED ; r+=pathArea(t.entirePath) );

    if( i < n ) throw "All paths must be closed.";

    return (r/=20), 0 < r ? r : -r;

};

var getArea = function(/*obj|obj[]*/a,t,mu,i,r)

//----------------------------------

// Main function. Return the area in the form "<value> <unit>²".

// This function does not address splines that auto-intersect.

{

    callee.Q||(callee.Q={

        Q:               'q',

        U:               'u',

        POINTS:          'pt',

        PIXELS:          'px',

        PICAS:           'p',

        MILS:            'mils',

        MILLIMETERS:     'mm',

        INCHES_DECIMEL:  'in',

        INCHES:          'in',

        HA:              'ha',

        CICEROS:         'c',

        CENTIMETERS:     'cm',

        BAI:             'bai',

        AMERICAN_POINTS: 'ap',

        AGATES:          'ag',

        });

    (a instanceof Array) || (a=);

    // Set consistent measurement unit.

    // ---

    while( 1 )

    {

        if( !(t=a[0]) || 'function' != typeof t.toSpecifier ) throw "Invalid input."

        t = t.toSpecifier().match(/^\/document\[@id=\d+\]/);

        if( !t || !(t=resolve(t[0])) || !(t instanceof Document) ) throw "Invalid input.";

        t = t.viewPreferences.horizontalMeasurementUnits;

        app.scriptPreferences.measurementUnit = t;

        mu = callee.Q[t.toString()]||'';

        mu && (mu = ' ' + mu + '\xB2');

        break;

    }

   

    for( r=0, i=a.length ; i-- ; (o=a)&&o.hasOwnProperty('paths')&&(r+=splineArea(o)) );

   

    return String(r) + mu;

};

// TEST. (Assuming something is selected.)

//========================================

var sel = app.selection;

alert( getArea(sel) );

Hope that helps.

Best,

Marc

Votes

Translate

Translate

Report

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 31, 2018 Jan 31, 2018

Copy link to clipboard

Copied

Hi Marc,

I've tested your code and it works great. Many thanks for sharing this script with us.

Awesome job! This is very helpful.

Votes

Translate

Translate

Report

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 31, 2018 Jan 31, 2018

Copy link to clipboard

Copied

Nice one, Marc!

Not sure though that I understand what you mean by 'In case your splines do not auto-intersect'. Could you elaborate?

P.

Votes

Translate

Translate

Report

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
Guide ,
Jan 31, 2018 Jan 31, 2018

Copy link to clipboard

Copied

Hi Peter,

The following image shall illustrate the problem:

zero-area.png

The SplineItem is made of two path points whose tangents are strictly opposed (so the shape crosses itself.) Since the algorithm relies on an algebraic calculation of area elements along a closed path, it concludes that the entire area is zero

You may think that considering the absolute value of each sub-calculation and adding all these values would solve the problem, but this would simply destroy the integration routine. In integral terms the area above is actually zero—although that's obviously not what the user expects to be returned!

Best,

Marc

Votes

Translate

Translate

Report

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 31, 2018 Jan 31, 2018

Copy link to clipboard

Copied

Thanks, Marc. The term 'auto-intersect' didn't mean much to me, but your illustration makes it clear.

P.

Votes

Translate

Translate

Report

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 ,
Feb 01, 2018 Feb 01, 2018

Copy link to clipboard

Copied

This is also why the returned surface area might be a negative number (Which Marc then negates, because computers can process that but humans cannot.)

Votes

Translate

Translate

Report

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 ,
Feb 01, 2018 Feb 01, 2018

Copy link to clipboard

Copied

Hi,

I just would like to mention that using the script on a default circle shape, the calculations seems not as accurate.

If you would like to get the area coverage of a circle, consider using pi * radius 2

For all other usages, the script Marc provided is awesome...

Votes

Translate

Translate

Report

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 ,
Feb 01, 2018 Feb 01, 2018

Copy link to clipboard

Copied

Set the circle's stroke to zero and its area is calculated correctly.

P.

Votes

Translate

Translate

Report

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 ,
Feb 01, 2018 Feb 01, 2018

Copy link to clipboard

Copied

Hi Peter,

I have created a circle, 100x100 mm. When calculating the surface area using 50 * 50 * 3,141592653, the result doesn't match with the script output. The stroke is set to zero.

Schermafbeelding 2018-02-01 om 10.18.22.png

Votes

Translate

Translate

Report

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 ,
Feb 01, 2018 Feb 01, 2018

Copy link to clipboard

Copied

And what do you get when you do (50*50)*Math.PI ?

Votes

Translate

Translate

Report

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 ,
Feb 01, 2018 Feb 01, 2018

Copy link to clipboard

Copied

Hi Peter,

The result is identical to the calculator :-), and not the output of the script... 🙂

Votes

Translate

Translate

Report

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
Guide ,
Feb 01, 2018 Feb 01, 2018

Copy link to clipboard

Copied

Hi tmmls,

Don't forget that InDesign circles are not exact circles. In fact, there is no representation of a true circle based on a cubic Bezier curve and the best we can hope is approximation. It is well known that InDesign approx is not very good, but anyway, even assuming the best cubic interpolation known to date (bezier - How to create circle with Bézier curves? - Stack Overflow ), a typical “radial error” of 0.02% is still observed along the curve. In your example (R=50) that's an order of magnitude of about 0.01 mm.

So, if you want a fair estimation of the error, you need to try the script with R = 50 ± 0.01 mm, that is, with two diameters of respectively 99.98 and 100.02 mm. Then you get the following outputs:

• For D=99.98 mm, result is 7,853.03865981908 mm²

• For D=100.02 mm, result is 7,859.3236044734 mm²

These values enclose the theoretical result, πR² ≈ 7,853.981635.

Note also that the gap between the output for D=100 and the theoretical result is 7,856.180818 – 7,853.981635 ≈ 2.199 mm². This may seem 'great' at first, but this only represents a drift of 0.028% relative to the expected result. This error has the same order of magnitude than the radial error caused by the Bezier approximation!

Not so bad, in my opinion.

Best,

Marc

Votes

Translate

Translate

Report

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 ,
Feb 01, 2018 Feb 01, 2018

Copy link to clipboard

Copied

Hi Marc,

Thank you for your detailed explanation. I was not aware of the issue regarding circles build out of bezier curves.

Your totally right. A deviation of only 0.028% is pretty awesome.

Many many thanks for all your help.

Votes

Translate

Translate

Report

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
New Here ,
Jan 23, 2020 Jan 23, 2020

Copy link to clipboard

Copied

Hello! I'm trying to test out the script, but I get an error. It seems I'm missing a value after "=" in the following line:

(a instanceof Array) || (a=);

What can I do to fix it? Thanks again!

Votes

Translate

Translate

Report

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, 2020 Jan 23, 2020

Copy link to clipboard

Copied

Hi pjleveno,

I guess another bug with moving this thread to the new InDesign forum.

Better look into Marc's original code:

 

Nice Function for Computing Polygon Areas

Marc Autret

http://www.indiscripts.com/post/2019/06/indesign-scripting-forum-roundup-13#hd2sb2

 

Regards,
Uwe Laubender

( ACP )

Votes

Translate

Translate

Report

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
New Here ,
Jan 23, 2020 Jan 23, 2020

Copy link to clipboard

Copied

LATEST

Thanks! It works perfectly. I'm trying to locate unlabeled icons. Maybe I can find them based on their area, unless someone has another way to identify a path. Thanks again for these powerful tools and also your quick responses! 

Votes

Translate

Translate

Report

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