Skip to main content
deleted 122 characters in body
Source Link
Jongware
  • 4.3k
  • 2
  • 16
  • 27

For future reference: please do not characterize such a task as "simple" until you can write it yourself.

For future reference: please do not characterize such a task as "simple" until you can write it yourself.

added 657 characters in body
Source Link
Jongware
  • 4.3k
  • 2
  • 16
  • 27

Result: above the dotted line the original, below after running the script. The leftmost object is your example. The vertical cyan lines are added manually to indicate the longest vertical distance points.

before and after running the script

Some very complicated objects defy simple path exploration – and I have no idea why. See the fish bones for an example; it did not move, because the path finding functions returned nothing at all. The underlying problem could be that it originated as a Symbol, rather than drawn, but the reason eludes me.

//DESCRIPTION:Align selected object(s) vertical on theits longest axis

if (app.documents.length == 0 || app.selection.length < 1)
    alert ("Please make sure to have something useful selected");
else
{
    for (i=0; i<app.selection.length; i++)
    {
        if (app.selection[i].constructor.name=="PathItem" || app.selection[i].constructor.name=="CompoundPathItem")
            realign (app.selection[i]);
    }
}

function realign (obj)
{
    var result, distx,disty,angle;

    result = furthestSet (obj);
    if (result.length == 3)
    {
        /* result[1] is point #1, result[2] = pt #2 */
        /* now calculate angle and rotate */
        
        disty = result[1][0] - result[2][0];
        distx = result[1][1] - result[2][1];
        
        angle = -Math.atan2 (distx, disty) - Math.PI/2;
        angle = angle*180.0/Math.PI;
        if (angle <= -180) angle += 180;
        if (angle >=  180) angle -= 180;
        
        obj.rotate (angle,true,true,true,false, Transformation.CENTER);
    }
}

function distanceFromPointToPoint (A, B)
{
/*  since we only need to know what point is furthest, the squared result is okay as well */

/*  return Math.sqrt ( ((A[0]-B[0]) * (A[0]-B[0])) + ((A[1]-B[1]) * (A[1]-B[1])) ); */

    return ((A[0]-B[0]) * (A[0]-B[0])) + ((A[1]-B[1]) * (A[1]-B[1]));
}

function pathToArray (obj)
{
    var pt;
    var flatpath = [];

    if (!obj.hasOwnProperty ("pathPoints"))
        return null;

    for (pt=0; pt<obj.pathPoints.length; pt++)
    {
        flatpath.push (obj.pathPoints[pt].anchor);
    }
    /* once more for good luck */
    flatpath.push (obj.pathPoints[0].anchor);
    return flatpath;
}

function furthestSet (obj)
{
    var flatpath = [], i,j, d, distance = -1, result = [];

    if (obj.constructor.name == "CompoundPathItem")
    {
        for (p=0; p<obj.pathItems.length; p++)
        {
            flatpath = flatpath.concat(pathToArray (obj.pathItems[p]));
        }
    } else
    {
        flatpath = pathToArray (obj);
    }
    if (flatpath == [])
        return [0, [0,0], [0,0]];

    for (i=0; i < flatpath.length-1; i++)
    {
        for (j=i+1; j < flatpath.length; j++)
        {
            d = distanceFromPointToPoint (flatpath[i], flatpath[j]);
            if (d > distance)
            {
                distance = d;
                result = [d, flatpath[i], flatpath[j]];
            }
        }
    }
    return result;
}
//DESCRIPTION:Align selected object(s) vertical on the longest axis

if (app.documents.length == 0 || app.selection.length < 1)
    alert ("Please make sure to have something useful selected");
else
{
    for (i=0; i<app.selection.length; i++)
    {
        if (app.selection[i].constructor.name=="PathItem" || app.selection[i].constructor.name=="CompoundPathItem")
            realign (app.selection[i]);
    }
}

function realign (obj)
{
    var result, distx,disty,angle;

    result = furthestSet (obj);

    /* result[1] is point #1, result[2] = pt #2 */
    /* now calculate angle and rotate */

    disty = result[1][0] - result[2][0];
    distx = result[1][1] - result[2][1];

    angle = -Math.atan2 (distx, disty) - Math.PI/2;
    angle = angle*180.0/Math.PI;
    if (angle <= -180) angle += 180;
    if (angle >=  180) angle -= 180;

    obj.rotate (angle,true,true,true,false, Transformation.CENTER);
}

function distanceFromPointToPoint (A, B)
{
/*  since we only need to know what point is furthest, the squared result is okay as well */

/*  return Math.sqrt ( ((A[0]-B[0]) * (A[0]-B[0])) + ((A[1]-B[1]) * (A[1]-B[1])) ); */

    return ((A[0]-B[0]) * (A[0]-B[0])) + ((A[1]-B[1]) * (A[1]-B[1]));
}

function pathToArray (obj)
{
    var pt;
    var flatpath = [];

    if (!obj.hasOwnProperty ("pathPoints"))
        return null;

    for (pt=0; pt<obj.pathPoints.length; pt++)
    {
        flatpath.push (obj.pathPoints[pt].anchor);
    }
    /* once more for good luck */
    flatpath.push (obj.pathPoints[0].anchor);
    return flatpath;
}

function furthestSet (obj)
{
    var flatpath = [], i,j, d, distance = -1, result = [];

    if (obj.constructor.name == "CompoundPathItem")
    {
        for (p=0; p<obj.pathItems.length; p++)
        {
            flatpath = flatpath.concat(pathToArray (obj.pathItems[p]));
        }
    } else
    {
        flatpath = pathToArray (obj);
    }
    if (flatpath == [])
        return [0, [0,0], [0,0]];

    for (i=0; i < flatpath.length-1; i++)
    {
        for (j=i+1; j < flatpath.length; j++)
        {
            d = distanceFromPointToPoint (flatpath[i], flatpath[j]);
            if (d > distance)
            {
                distance = d;
                result = [d, flatpath[i], flatpath[j]];
            }
        }
    }
    return result;
}

Result: above the dotted line the original, below after running the script. The leftmost object is your example. The vertical cyan lines are added manually to indicate the longest vertical distance points.

before and after running the script

Some very complicated objects defy simple path exploration – and I have no idea why. See the fish bones for an example; it did not move, because the path finding functions returned nothing at all. The underlying problem could be that it originated as a Symbol, rather than drawn, but the reason eludes me.

//DESCRIPTION:Align object(s) on its longest axis

if (app.documents.length == 0 || app.selection.length < 1)
    alert ("Please make sure to have something useful selected");
else
{
    for (i=0; i<app.selection.length; i++)
    {
        if (app.selection[i].constructor.name=="PathItem" || app.selection[i].constructor.name=="CompoundPathItem")
            realign (app.selection[i]);
    }
}

function realign (obj)
{
    var result, distx,disty,angle;

    result = furthestSet (obj);
    if (result.length == 3)
    {
        /* result[1] is point #1, result[2] = pt #2 */
        /* now calculate angle and rotate */
        
        disty = result[1][0] - result[2][0];
        distx = result[1][1] - result[2][1];
        
        angle = -Math.atan2 (distx, disty) - Math.PI/2;
        angle = angle*180.0/Math.PI;
        if (angle <= -180) angle += 180;
        if (angle >=  180) angle -= 180;
        
        obj.rotate (angle,true,true,true,false, Transformation.CENTER);
    }
}

function distanceFromPointToPoint (A, B)
{
/*  since we only need to know what point is furthest, the squared result is okay as well */

/*  return Math.sqrt ( ((A[0]-B[0]) * (A[0]-B[0])) + ((A[1]-B[1]) * (A[1]-B[1])) ); */

    return ((A[0]-B[0]) * (A[0]-B[0])) + ((A[1]-B[1]) * (A[1]-B[1]));
}

function pathToArray (obj)
{
    var pt;
    var flatpath = [];

    if (!obj.hasOwnProperty ("pathPoints"))
        return null;

    for (pt=0; pt<obj.pathPoints.length; pt++)
    {
        flatpath.push (obj.pathPoints[pt].anchor);
    }
    /* once more for good luck */
    flatpath.push (obj.pathPoints[0].anchor);
    return flatpath;
}

function furthestSet (obj)
{
    var flatpath = [], i,j, d, distance = -1, result = [];

    if (obj.constructor.name == "CompoundPathItem")
    {
        for (p=0; p<obj.pathItems.length; p++)
        {
            flatpath = flatpath.concat(pathToArray (obj.pathItems[p]));
        }
    } else
    {
        flatpath = pathToArray (obj);
    }
    if (flatpath == [])
        return [0, [0,0], [0,0]];

    for (i=0; i < flatpath.length-1; i++)
    {
        for (j=i+1; j < flatpath.length; j++)
        {
            d = distanceFromPointToPoint (flatpath[i], flatpath[j]);
            if (d > distance)
            {
                distance = d;
                result = [d, flatpath[i], flatpath[j]];
            }
        }
    }
    return result;
}
Source Link
Jongware
  • 4.3k
  • 2
  • 16
  • 27

This took about an hour to write, one step at a time:

  1. Handle either one single item, or a selection of items.
  2. Loop through the single path (for a simple object) or through all component paths (for a compound object) and gather all anchor points into a single array.
  3. Test every point against every other. I've thought about it and I don't think there is clever solution that may avoid this.
  4. Calculate the angle between the 2 most distant points.
  5. If the angle exceeds ±180°, clip it to avoid rotating too much.
  6. Rotate the selected object(s).
//DESCRIPTION:Align selected object(s) vertical on the longest axis

if (app.documents.length == 0 || app.selection.length < 1)
    alert ("Please make sure to have something useful selected");
else
{
    for (i=0; i<app.selection.length; i++)
    {
        if (app.selection[i].constructor.name=="PathItem" || app.selection[i].constructor.name=="CompoundPathItem")
            realign (app.selection[i]);
    }
}

function realign (obj)
{
    var result, distx,disty,angle;

    result = furthestSet (obj);

    /* result[1] is point #1, result[2] = pt #2 */
    /* now calculate angle and rotate */

    disty = result[1][0] - result[2][0];
    distx = result[1][1] - result[2][1];

    angle = -Math.atan2 (distx, disty) - Math.PI/2;
    angle = angle*180.0/Math.PI;
    if (angle <= -180) angle += 180;
    if (angle >=  180) angle -= 180;

    obj.rotate (angle,true,true,true,false, Transformation.CENTER);
}

function distanceFromPointToPoint (A, B)
{
/*  since we only need to know what point is furthest, the squared result is okay as well */

/*  return Math.sqrt ( ((A[0]-B[0]) * (A[0]-B[0])) + ((A[1]-B[1]) * (A[1]-B[1])) ); */

    return ((A[0]-B[0]) * (A[0]-B[0])) + ((A[1]-B[1]) * (A[1]-B[1]));
}

function pathToArray (obj)
{
    var pt;
    var flatpath = [];

    if (!obj.hasOwnProperty ("pathPoints"))
        return null;

    for (pt=0; pt<obj.pathPoints.length; pt++)
    {
        flatpath.push (obj.pathPoints[pt].anchor);
    }
    /* once more for good luck */
    flatpath.push (obj.pathPoints[0].anchor);
    return flatpath;
}

function furthestSet (obj)
{
    var flatpath = [], i,j, d, distance = -1, result = [];

    if (obj.constructor.name == "CompoundPathItem")
    {
        for (p=0; p<obj.pathItems.length; p++)
        {
            flatpath = flatpath.concat(pathToArray (obj.pathItems[p]));
        }
    } else
    {
        flatpath = pathToArray (obj);
    }
    if (flatpath == [])
        return [0, [0,0], [0,0]];

    for (i=0; i < flatpath.length-1; i++)
    {
        for (j=i+1; j < flatpath.length; j++)
        {
            d = distanceFromPointToPoint (flatpath[i], flatpath[j]);
            if (d > distance)
            {
                distance = d;
                result = [d, flatpath[i], flatpath[j]];
            }
        }
    }
    return result;
}

For future reference: please do not characterize such a task as "simple" until you can write it yourself.