4 Replies Latest reply on Nov 20, 2010 11:53 AM by Kasyan Servetsky

    How to move the ends of skewed lines to the bleed bounds

    Kasyan Servetsky Level 5

       

      Hi all,

       

      I am developing a script that trims page items to the bleed. To achieve this I collect all page items (except text frames) located partially on the pasteboard, create a temporary mask and 'crop' them with Pathfinder's Subtract feature. However this approach doesn't work with graphic lines so I am attempting to move ends of lines to the bounds of bleed box. (I'm assuming that these are simple straight lines consisting of two end points.)

      screengrab.png

      I've figured out how to deal with orthogonal lines -- it's quite easy:

       

       

      if (theItem.constructor.name == "GraphicLine" && theItem.paths.length === 1) {
           path = theItem.paths[0];
           if (path.pathPoints.length === 2) {
                ep = path.entirePath;
                w = ep[1][0]-ep[0][0];
                h = ep[1][1]-ep[0 ][1];
                
                if (w > h) {
                     newEp = [ [ spreadWithBleedBounds[1], ep[0][1] ], [ spreadWithBleedBounds[3], ep[1][1] ] ];
                     path.entirePath = newEp;
                }
                else if (h > w) {
                     newEp = [ [ ep[0][0], spreadWithBleedBounds[0] ], [ ep[1][0], spreadWithBleedBounds[2] ] ];
                     path.entirePath = newEp;
                }
           }
      }
      

       

       

      This moves A1 to A2, B1 to B2, C1 to C2, D1 to D2.

       

      But how to deal with skewed lines? How to calculate coordinates for points E2 and F2? Is there some magic formula? Or can anybody point me to the right direction: e.g. some book to read?

       

      I guess this has something to do with geometry/trigonometry, but I haven't studied this stuff at school. (I graduated an art school -- studied to draw nude models instead.)

       

      If someone is going to answer to my question, please do it on elementary level since I am a total noob in this.

       

      Below is the whole script:

      if (Number(String(app.version).split(".")[0]) == 7) ErrorExit("This script can't work with InDesign CS5 so far.", true);
      
      var doc = app.activeDocument;
      var spreadBounds, spreadWithBleedBounds, gPartiallyOutOfSpreadItems;
      var ungroupErrors = 0;
      
      var originalHorUnits =  doc.viewPreferences.horizontalMeasurementUnits;
      var originalVerUnits =  doc.viewPreferences.verticalMeasurementUnits;
      doc.viewPreferences.horizontalMeasurementUnits = doc.viewPreferences.verticalMeasurementUnits = MeasurementUnits.INCHES;
      doc.viewPreferences.rulerOrigin = RulerOrigin.spreadOrigin;
      doc.zeroPoint = [0, 0];
      
      if (doc.layers.itemByName("Temporary Layer") == null ) {
           var tempLayer = doc.layers.add({name:"Temporary Layer"});
      }
      else {
           var tempLayer = doc.layers.itemByName("Temporary Layer");
      }
      
      UngroupAllGroups(doc.groups);
      
      DeleteObjectsOnPasteboard();
      ProcessSpreads(doc.spreads);
      ProcessSpreads(doc.masterSpreads);
      
      tempLayer.remove();
      
      doc.viewPreferences.horizontalMeasurementUnits = originalHorUnits;
      doc.viewPreferences.verticalMeasurementUnits = originalVerUnits;
      
      var msg = (ungroupErrors > 0) ? " Failed to ungroup " + ungroupErrors + " groups since they are too large." : "";
      alert("Done." + msg, "Trim Pages Script");
      
      //================================== FUNCTONS ===========================================
      function ProcessSpreads(spreads) {
           var spread, path, ep, w, h;
           for (var s = 0; s < spreads.length; s++) {
                spread = spreads[s];
                spreadBounds = GetSpreadBound(spread, false);
                spreadWithBleedBounds = GetSpreadBound(spread, true);
                
                gPartiallyOutOfSpreadItems = GetPartiallyOutOfSpreadItems(spread);
                
                var theItem, theMask, newItem;
                for (var i = gPartiallyOutOfSpreadItems.length-1; i >= 0; i--) {
                     theItem = gPartiallyOutOfSpreadItems[i];
                     if (theItem.constructor.name == "GraphicLine" && theItem.paths.length === 1) {
                          path = theItem.paths[0];
                          if (path.pathPoints.length === 2) {
                               ep = path.entirePath;
                               w = ep[1][0]-ep[0][0];
                               h = ep[1][1]-ep[0 ][1];
                               
                               if (w > h) {
                                    newEp = [ [ spreadWithBleedBounds[1], ep[0][1] ], [ spreadWithBleedBounds[3], ep[1][1] ] ];
                                    path.entirePath = newEp;
                               }
                               else if (h > w) {
                                    newEp = [ [ ep[0][0], spreadWithBleedBounds[0] ], [ ep[1][0], spreadWithBleedBounds[2] ] ];
                                    path.entirePath = newEp;
                               }
                          }
                     }
                     else {
                          theMask = CreateMask(spread);
                          try {
                               newItem = theMask.subtractPath(theItem);
                          }
                          catch (err) {
                               $.writeln("2 - " + err);
                               theMask.remove();
                          }
                     }
                }
           }
      }
      //--------------------------------------------------------------------------------------------------------------
      function IsPartiallyOutOfSpread(pageItem) {
           var result = false;
           if (pageItem.constructor.name == "TextFrame" ||
                pageItem.constructor.name == "Group" ||
                pageItem.parent.constructor.name == "Group")
           {
                return result;
           }
      
           var visBounds = pageItem.visibleBounds;
           if (visBounds[0] < spreadBounds[0] && visBounds[2] > spreadBounds[0] ||
                visBounds[1] < spreadBounds[1] && visBounds[3] > spreadBounds[1] ||
                visBounds[2] > spreadBounds[2] && visBounds[0] < spreadBounds[2] ||
                visBounds[3] > spreadBounds[3] && visBounds[1] < spreadBounds[3]  ) {
                result = true;
           }
           return result;
      }
      //--------------------------------------------------------------------------------------------------------------
      function GetSpreadBound(spread, bleed) { // including bleed -boolean
           if (bleed == undefined) bleed = false;
           
           with (doc.documentPreferences) {
                var topBleed = documentBleedTopOffset
                var leftBleed = documentBleedInsideOrLeftOffset;
                var bottomBleed = documentBleedBottomOffset;
                var rightBleed = documentBleedOutsideOrRightOffset;
           }
      
           var bFirst = spread.pages.item(0).bounds; // bounds of the first page
           var bLast = spread.pages.item(-1).bounds; // bounds of the last page
           return [     ((bleed) ? bFirst[0]-topBleed : bFirst[0]), 
                          ((bleed) ? bFirst[1]-leftBleed : bFirst[1]), 
                          ((bleed) ? bLast[2]+bottomBleed : bFirst[2]), 
                          ((bleed) ? bLast[3]+rightBleed : bLast[3])
                          ];
      }
      //--------------------------------------------------------------------------------------------------------------
      function CreateMask(spread) {
           var unitValue = new UnitValue (app.pasteboardPreferences.minimumSpaceAboveAndBelow, "mm");
           var unitValueAsInch = unitValue.as("in");
           var outerRectangleBounds = [spreadWithBleedBounds[0]-unitValueAsInch, 
                                                                  spreadWithBleedBounds[1]-8.07, 
                                                                  spreadWithBleedBounds[2]+unitValueAsInch, 
                                                                  spreadWithBleedBounds[3]+8.07
                                                                  ]; 
      
           var outerRectangle = spread.rectangles.add(tempLayer, undefined, undefined, {geometricBounds:outerRectangleBounds});
           var innerRectangle = spread.rectangles.add(tempLayer, undefined, undefined, {geometricBounds:spreadWithBleedBounds, fillColor:doc.swatches.item("Black"), fillTint:30});
           var mask = outerRectangle.excludeOverlapPath(innerRectangle);
           return mask;
      }
      //--------------------------------------------------------------------------------------------------------------
      function GetPartiallyOutOfSpreadItems(spread) {
           var allPageItems = spread.allPageItems;
           var partiallyOutOfSpreadItems = [];
           var currentItem;
           
           for (var i = 0; i < allPageItems.length; i++) {
                currentItem = allPageItems[i];
                if (IsPartiallyOutOfSpread(currentItem)) partiallyOutOfSpreadItems.push(currentItem);
           }
           
           return partiallyOutOfSpreadItems;
      }
      //--------------------------------------------------------------------------------------------------------------
      function DeleteObjectsOnPasteboard() {
           var objs = app.documents[0].pageItems.everyItem().getElements();
           while (obj=objs.pop()) {
                try {
                     if(obj.parent instanceof Spread || obj.parent instanceof MasterSpread){ obj.remove() }
                }
                catch(err) {
                     //$.writeln("2 - " + err);
                }
           }
      }
      //--------------------------------------------------------------------------------------------------------------
      function ErrorExit(myMessage, myIcon) {
           alert(myMessage, "Trim Pages Script", myIcon);
           exit();
      }
      //--------------------------------------------------------------------------------------------------------------
      function UngroupAllGroups(groups) {
           for (var i = groups.length-1; i >= 0; i--) {
                var gr = groups[i];
                if (gr.groups.length > 0) {
                     var subGroups = [];
                     for (var j = gr.groups.length-1; j >= 0; j--) {
                          subGroups.push(gr.groups[j].id);
                     }                    
                     try {
                          gr.ungroup();
                     }
                     catch(err) {
                          //$.writeln("1 - " + err);
                          ungroupErrors++;
                     }
                
                     for (var k = subGroups.length-1; k >= 0; k--) {
                          try {
                               doc.groups.itemByID(subGroups[k]).ungroup();
                          }
                          catch(err) {
                               //$.writeln("2 - " + err);
                               ungroupErrors++;
                          }
                     }
                }
                else {
                     try {
                          gr.ungroup();
                     }
                     catch(err) {
                          //$.writeln("1 - " + err);
                          ungroupErrors++;
                     }
                }
           }     
      }
      //--------------------------------------------------------------------------------------------------------------

       

       

      Thanks in advance.

      Kasyan

        • 2. Re: How to move the ends of skewed lines to the bleed bounds
          [Jongware] Most Valuable Participant

          Hi Kasyan!

           

          I didn't try to integrate this into your script, so you might have to adjust it a little bit. The trick is to define a function that finds the intersection point of two lines --- and, obviously, you should only call it for the lines that are sure to cross the page border! (Otherwise, it would simply extend *any* line up and over the border.)

           

          I think it would be wise to allow for a tiny error for lines that appear to run "up to" the page edge -- I tested a line for "x <= 0" on a line that appeared to start on 0; the control panel told me so. However, I didn't type that 0 in; I dragged the line to the edge. Apparently, it was *NOT* at precisely "0mm", but something like "0.001mm", because the script simply didn't "see" the line.

           

          My function comes from this page: http://local.wasp.uwa.edu.au/~pbourke/geometry/lineline2d/ and I didn't test what it does to orthogonal lines

          (but of course you could add this as an exception), and this is my line-extending script, with a little wrapper to set things up.

          The function tests *any* line against *any* other line, so if one crosses the page bounding box, I get the intersection with the bleed box on the side where it crosses the page bbox.

           

          line = app.selection[0];
          // pg size in "regular" [y1,x1, y2,x2] format
          pagebbox = [0,0, app.activeDocument.documentPreferences.pageHeight,app.activeDocument.documentPreferences.pageWidth ];
          bleedDist = 5; // 
          bleedbbox = [ pagebbox[0] - bleedDist, pagebbox[1] - bleedDist, pagebbox[2] + bleedDist, pagebbox[3] + bleedDist ];
          pt1 = line.paths[0].pathPoints[0].anchor;
          pt2 = line.paths[0].pathPoints.lastItem().anchor;
          // Start point:
          if (pt1[0] <= pagebbox[1] || pt1[0] >= pagebbox[3] ||
           pt1[1] <= pagebbox[0] || pt1[1] >= pagebbox[2])
          {
           if (pt1[0] <= pagebbox[1])
            intersectPt = IntersectionPt ( [pt1, pt2], [ [ bleedbbox[1], bleedbbox[0]], [bleedbbox[1], bleedbbox[2] ] ] );
           
           if (pt1[0] >= pagebbox[3])
            intersectPt = IntersectionPt ( [pt1, pt2], [ [ bleedbbox[3], bleedbbox[0]], [bleedbbox[3], bleedbbox[2] ] ] );
           
           if (pt1[1] <= pagebbox[0])
            intersectPt = IntersectionPt ( [pt1, pt2], [ [ bleedbbox[1], bleedbbox[0]], [bleedbbox[3], bleedbbox[0] ] ] );
           if (pt1[1] >= pagebbox[2])
            intersectPt = IntersectionPt ( [pt1, pt2], [ [ bleedbbox[1], bleedbbox[2]], [bleedbbox[3], bleedbbox[2] ] ] );
           line.paths[0].pathPoints[0].anchor = intersectPt;
          }
          // End point:
          if (pt2[0] <= pagebbox[1] || pt2[0] >= pagebbox[3] ||
           pt2[1] <= pagebbox[0] || pt2[1] >= pagebbox[2])
          {
           if (pt2[0] <= pagebbox[1])
            intersectPt = IntersectionPt ( [pt1, pt2], [ [ bleedbbox[1], bleedbbox[0]], [bleedbbox[1], bleedbbox[2] ] ] );
           
           if (pt2[0] >= pagebbox[3])
            intersectPt = IntersectionPt ( [pt1, pt2], [ [ bleedbbox[3], bleedbbox[0]], [bleedbbox[3], bleedbbox[2] ] ] );
           
           if (pt2[1] <= pagebbox[0])
            intersectPt = IntersectionPt ( [pt1, pt2], [ [ bleedbbox[1], bleedbbox[0]], [bleedbbox[3], bleedbbox[0] ] ] );
           if (pt2[1] >= pagebbox[2])
            intersectPt = IntersectionPt ( [pt1, pt2], [ [ bleedbbox[1], bleedbbox[2]], [bleedbbox[3], bleedbbox[2] ] ] );
           line.paths[0].pathPoints.lastItem().anchor = intersectPt;
          }
          
          function IntersectionPt (ln1, ln2)
          {
           var ua;
           var x1 = ln1[0][0], x2 = ln1[1][0], x3 = ln2[0][0], x4 = ln2[1][0];
           var y1 = ln1[0][1], y2 = ln1[1][1], y3 = ln2[0][1], y4 = ln2[1][1];
           ua = ((x4 - x3)*(y1 - y3) - (y4 - y3)*(x1 - x3))/((y4 - y3)*(x2 - x1) - (x4 - x3)*(y2 - y1));
           
           return [ x1 + ua*(x2-x1), y1 + ua*(y2-y1) ];
          }
          
          • 3. Re: How to move the ends of skewed lines to the bleed bounds
            [Jongware] Most Valuable Participant

            Further reflections:

             

            You can use the same code for straight paths with more points, but in that case you should not test the first and last point, but rather the first and second point (*) for the start case, and the last and second-to-last point for the end.

             

            (*) You might want to make sure these points don't fall on top of each other...

             

            A similar construction *might* even work for curved lines. It's fairly easy to deconstruct a bezier curve into straight line segments, so you could do that first, then use the same 'straight line' path algorithm above to extend the final line segment.

             

            But you might have to do that with a circle! Ideally, it should work something like in this picture -- but it makes stuff *much* harder

            -- possibly above & beyond what's practical.

             

            edgeclip.PNG

            1 person found this helpful
            • 4. Re: How to move the ends of skewed lines to the bleed bounds
              Kasyan Servetsky Level 5

               

              Hi Jongware and Marijan,

               

              Thank you both for your quick responses.

              Jongware's answer is exactly what I was looking for. After a little tweaking it does what I want: moves the ends of lines to the spread's bleed box.

              Thank you very much again, Jongware.

               

              Regards,

              Kasyan