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

[SCRIPT] How to select most top/left object

Enthusiast ,
Jun 15, 2021 Jun 15, 2021

Copy link to clipboard

Copied

Hello gurus,

I need to select the most top/left object in a page.

The Y is the tiebreaker. Any suggestion?

I tried sorting by geometricBounds[0] and geometricBounds[1] but can not accomplish what I need.

 

Thanks in advance.

TOPICS
Scripting

Views

760

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 2 Correct answers

Enthusiast , Jun 15, 2021 Jun 15, 2021

I have no idea why, but I got it.

Tired of playing with this sort function, I put this absurd and it works.

If anyone understand the logic behind this function, I'd love to know.

 

var doc = app.activeDocument;
var pg = app.activeWindow.activePage;
getFirstImg(pg);

function getFirstImg(pg) {
	var gbs = [];
	for (var i=0; i<pg.rectangles.length; i++) {
		if (pg.rectangles[i].itemLayer == img && pg.rectangles[i].graphics.length) {
			var recgb = pg.rectangles[i].geometricBounds;
			gbs.push([recgb[0]
...

Votes

Translate

Translate
Community Expert , Aug 10, 2021 Aug 10, 2021

For anyone wondering, here's the solution I came up with for Luis on a Facebook thread. The yThresh accounted for objects not perfectly aligned on the top (in mm), but could be set  to whatever threshold you felt appropriate. 

 


var apis = app.activeDocument.pages[0].pageItems.everyItem().getElements();
apis.sort(function (a,b) {
var agb = a.geometricBounds;
var bgb = b.geometricBounds;
var yThresh = Math.abs(agb[0] - bgb[0]);
if (yThresh > 5) {
if (agb[0] > bgb[0]) return 1;
else if (bgb[0] > agb[0])

...

Votes

Translate

Translate
Enthusiast ,
Jun 15, 2021 Jun 15, 2021

Copy link to clipboard

Copied

I have no idea why, but I got it.

Tired of playing with this sort function, I put this absurd and it works.

If anyone understand the logic behind this function, I'd love to know.

 

var doc = app.activeDocument;
var pg = app.activeWindow.activePage;
getFirstImg(pg);

function getFirstImg(pg) {
	var gbs = [];
	for (var i=0; i<pg.rectangles.length; i++) {
		if (pg.rectangles[i].itemLayer == img && pg.rectangles[i].graphics.length) {
			var recgb = pg.rectangles[i].geometricBounds;
			gbs.push([recgb[0] , recgb[1] , pg.rectangles[i].graphics[0].itemLink.name , pg.rectangles[i]]);
			}
		}
	gbs.sort(function(a, b) { return (a[0] - b[0]) + (a[1] - b[1]); });
	app.select(gbs[0][3]);
	}

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 ,
Jun 16, 2021 Jun 16, 2021

Copy link to clipboard

Copied

You create an array of subarrays, sort the array by top and left coordinates, then take the first item, which is gbs[0]. This array item is an array itself with the rectangle as the fourth element, which you address by gbs[0][3].

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 ,
Jun 18, 2021 Jun 18, 2021

Copy link to clipboard

Copied

Hi @lfcorullon 

In fact the elements are sorted by comparing their (top+left) sum. Just note that the sort key (a[0]–b[0])+(a[1]–b[1]) is nothing but (a[0]+a[1])–(b[0]+b[1]), that is, (top+left)₀ – (top+left)₁. This is on average a good approximation when the X and Y axes have the same priority. In the below example you can see that the winner is the rectangle that reaches the minimal sum (Σ=340.)

TopLeftImage.png

However, using the sort method for this purpose is clearly useless and expensive, since the minimum value can always be found in linear time O(N)—while sort relies on a loglinear algorithm, i.e. O(N×log(N)). I think you could just do as follows:

function selectFirstImage(/*?Layer|str*/ly,/*?Document*/doc,/*?Page*/pg,  t,a,b,c,i,iBest,xyMin)
//----------------------------------
// Select and return the (top+left)most image container on a page.
// `ly`   : Target layer or layer name (opt.)
// `doc`  : Target document (default=active.)
// `pg`   : Target page (default=active.)
// ---
// => SplineItems [OK]  |  false [KO]
{
    // Checkpoint -> doc, pg
    // ---
    doc || (doc=app.properties.activeDocument||0);
    if( !doc.isValid || 'Document' != doc.constructor.name ) return false;
    
    pg || ((pg=app.properties.activeWindow)&&(pg=pg.properties.activePage)) || (pg=doc.pages[0]);
    if( !pg.isValid || 'Page' != pg.constructor.name ) return false;
    
    // Layer filter (optional.)
    // ---
    'string'==typeof ly && ly.length && (ly=doc.layers.itemByName(ly));
    ( ly && 'Layer'==ly.constructor.name && ly.isValid ) || (ly=void 0);
    
    // Browse the SplineItems collection.
    // ---
    t = pg.splineItems.everyItem();
    if( !t.isValid ) return false;
    a = t.getElements();
    b = ly ? t.itemLayer : [];
    
    // Identify the object having the minimal (x+y) sum.
    // ---
    for
    (
        i=a.length, iBest=false, xyMin=1/0 ;
        i-- ;
        ly===b[i] && (t=a[i]).graphics.length && (t=t.geometricBounds)
        && xyMin > (t=t[0]+t[1]) && (xyMin=t, iBest=i)
    );
    
    return false !== iBest && (app.select(t=a[iBest]), t);
}

// Example:
selectFirstImage('Layer 1');

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
Enthusiast ,
Jun 18, 2021 Jun 18, 2021

Copy link to clipboard

Copied

Wow, thank you @Marc Autret!!!

Your knowledge makes em feel illiterate.

I tried your code in two different documents and nothing is being selected.

I just typed the layer name in the function call...

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
Enthusiast ,
Aug 09, 2021 Aug 09, 2021

Copy link to clipboard

Copied

Now I'm having the same difficult to select elements in row order.

Any 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
Community Expert ,
Aug 10, 2021 Aug 10, 2021

Copy link to clipboard

Copied

LATEST

For anyone wondering, here's the solution I came up with for Luis on a Facebook thread. The yThresh accounted for objects not perfectly aligned on the top (in mm), but could be set  to whatever threshold you felt appropriate. 

 


var apis = app.activeDocument.pages[0].pageItems.everyItem().getElements();
apis.sort(function (a,b) {
var agb = a.geometricBounds;
var bgb = b.geometricBounds;
var yThresh = Math.abs(agb[0] - bgb[0]);
if (yThresh > 5) {
if (agb[0] > bgb[0]) return 1;
else if (bgb[0] > agb[0]) return -1;
}
return agb[1] > bgb[1];
});

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