Rect

A Rect is an object that contains the postion (Point) and measurements (Size) of the bounding box of a graphic or group, regardless of the graphic’s shape or appearance.

The Rect Object


[object Rect: (0.0, 0.0, 1024.0, 768.0)]

The four numeric values of a Rect represent (in order):

Functionally, you may think of a Rect as a Point and a Size combined into a single object.

Creating a Rect Object

To create a Rect, precede the Rect class name with the “new” allocator, followed by the comma-delimited sequence of the numeric values described in the previous list: (horizontal offset, vertical offset, width, height). The result will be a Rect object:

Creating a Rect Object


aRect = new Rect(0, 0, 1024, 768) //--> [object Rect: (0.0, 0.0, 1024.0, 768.0)]

The position and dimensions of every graphic are contained in a Rect that is the value of the graphic’s geometry property:

Get value of the Geometry property of a Selected Graphic


document.windows[0].selection.graphics[0].geometry //--> [object Rect: (354.0, 235.5, 316.0, 297.0)]

The geometry property is used quite often in Omni Automation scripts, and when addressing the geometry property, scripts are actually working with a Rect instance.

Rect Properties

A Rect instance has seven properties, all of which are editable, except the center property which has a read-only value:

rect properties

Editing a Rect

To change the origin (position) or size of a graphic, you extract the Rect object that is the value of the graphic’s geometry property, alter the extracted copy, and then assign the altered copy as the new value of the graphic’s geometry property. For example, here is a script that changes the origin (position) of a graphic:

omnigraffle:///omnijs-run?script=slds%20%3D%20document%2Ewindows%5B0%5D%2Eselection%2Esolids%0Aif%28slds%2Elength%20%3E%200%29%7B%0A%09geo%20%3D%20slds%5B0%5D%2Egeometry%0A%09geo%2Eorigin%20%3D%20new%20Point%280%2C0%29%0A%09slds%5B0%5D%2Egeometry%20%3D%20geo%0A%7D
Changing the Postion of a Graphic
 

slds = document.windows[0].selection.solids if(slds.length === 1){ geo = slds[0].geometry geo.origin = new Point(0,0) slds[0].geometry = geo }

Use the same technique for changing the size of a graphic:

omnigraffle:///omnijs-run?script=slds%20%3D%20document%2Ewindows%5B0%5D%2Eselection%2Esolids%0Aif%28slds%2Elength%20%3E%200%29%7B%0A%09geo%20%3D%20slds%5B0%5D%2Egeometry%0A%09geo%2Esize%20%3D%20new%20Size%28300%2C300%29%0A%09slds%5B0%5D%2Egeometry%20%3D%20geo%0A%7D
Changing the Size of a Graphic
 

slds = document.windows[0].selection.solids if(slds.length === 1){ geo = slds[0].geometry geo.size = new Size(300,300) slds[0].geometry = geo }

The “Handles” of a Rect

The visual representation of a Rect has “handles” to enable the physical manipulation of the object.

rect properties
Deriving the Postion of a Handle


slds = document.windows[0].selection.solids if(slds.length === 1){ geo = slds[0].geometry bottomRight = new Point(geo.maxX, geo.maxY) //--> [object Point: (287.5, 263.0)] {length: 389.6475971952092, negative: [object Point: (-287.5, -263.0)], normalized: [object Point: (0.7378462027470573, 0.6749688741651341)], x: 287.5, y: 263} }
derive-point-from-rect

More properties of a Rect instance:

Properties of a Rect


slds = document.windows[0].selection.solids if(slds.length === 1){ console.log(slds[0].geometry) //--> [object Rect: (87.5, 63.0, 200.0, 200.0)] console.log(slds[0].geometry.standardized) //--> [object Rect: (87.5, 63.0, 200.0, 200.0)] console.log(slds[0].geometry.integral) //--> [object Rect: (87.0, 63.0, 201.0, 200.0)] }

Rect Functions

The following functions can be called on an instance of the Rect class:

Multiple Shapes


cnvs = document.windows[0].selection.canvas shapes = cnvs.graphics redBox = shapes[2] blueBox = shapes[1] greenBox = shapes[0]
multiple-shapes-three
Union


redBox.geometry.union(greenBox.geometry) //--> [object Rect: (0.0, 0.0, 300.0, 300.0)] {center: [object Point: (150.0, 150.0)], height: 300, integral: [object Rect: (0.0, 0.0, 300.0, 300.0)], isEmpty: false, isInfinite: false, isNull: false, maxX: 300, maxY: 300, midX: 150, midY: 150, minX: 0, minY: 0, origin: [object Point: (0.0, 0.0)], size: [object Size: (300.0, 300.0)], standardized: [object Rect: (0.0, 0.0, 300.0, 300.0)], width: 300, x: 0, y: 0}
Intersect


redBox.geometry.intersect(greenBox.geometry) //--> [object Rect: (100.0, 100.0, 100.0, 100.0)] {center: [object Point: (150.0, 150.0)], height: 100, integral: [object Rect: (100.0, 100.0, 100.0, 100.0)], isEmpty: false, isInfinite: false, isNull: false, maxX: 200, maxY: 200, midX: 150, midY: 150, minX: 100, minY: 100, origin: [object Point: (100.0, 100.0)], size: [object Size: (100.0, 100.0)], standardized: [object Rect: (100.0, 100.0, 100.0, 100.0)], width: 100, x: 100, y: 100}
Contains Rect


redBox.geometry.containsRect(greenBox.geometry) //--> false redBox.geometry.containsRect(blueBox.geometry) //--> true
Contains Point


redBox.geometry.containsPoint(blueBox.geometry.origin) //--> true redBox.geometry.containsPoint(greenBox.geometry.origin) //--> true redBox.geometry.containsPoint(greenBox.geometry.center) //--> false var gBottomRight = new Point(greenBox.geometry.maxX, greenBox.geometry.maxY) redBox.geometry.containsPoint(gBottomRight) //--> false
Intersects


redBox.geometry.intersects(blueBox.geometry) //--> true redBox.geometry.intersects(greenBox.geometry) //--> true

The insetBy() function can be used to derive new geometry for a shape that decreases its size by horizontal and vertical percentages.

In the shown example, the starting width and height of the green shape are 200pt and 200pt respectively. The following example script uses the function to generate a Rect instance that is scaled down from the original shape geometry by 50% horizontally and 50% vertically. The resulting Rect instance is then assigned as the value for the shape’s geometry property, causing the shape to resize:

Inset By


newRect = greenBox.geometry.insetBy(50, 50) greenBox.geometry = newRect //--> [object Rect: (150.0, 150.0, 100.0, 100.0)] {center: [object Point: (200.0, 200.0)], height: 100, integral: [object Rect: (150.0, 150.0, 100.0, 100.0)], isEmpty: false, isInfinite: false, isNull: false, maxX: 250, maxY: 250, midX: 200, midY: 200, minX: 150, minY: 150, origin: [object Point: (150.0, 150.0)], size: [object Size: (100.0, 100.0)], standardized: [object Rect: (150.0, 150.0, 100.0, 100.0)], width: 100, x: 150, y: 150}
resized-green-box,jpg

The offsetBy() function can be used to change the postion of a shape by the provided horizontal and vertical percentages of the current shape offset.

In the shown example, the starting horizontal and vertical origins of the green shape are 100pt and 100pt respectively. The following example script uses the function to generate a Rect instance that adjusts the origin from the original shape geometry by 100% horizontally and 100% vertically. The resulting Rect instance is then assigned as the value for the shape’s geometry property, causing the shape to be repositioned with an origin point of (200pt, 200pt):

Offset By


newRect = greenBox.geometry.offsetBy(100, 100) greenBox.geometry = newRect //--> [object Rect: (200.0, 200.0, 200.0, 200.0)] {center: [object Point: (300.0, 300.0)], height: 200, integral: [object Rect: (200.0, 200.0, 200.0, 200.0)], isEmpty: false, isInfinite: false, isNull: false, maxX: 400, maxY: 400, midX: 300, midY: 300, minX: 200, minY: 200, origin: [object Point: (200.0, 200.0)], size: [object Size: (200.0, 200.0)], standardized: [object Rect: (200.0, 200.0, 200.0, 200.0)], width: 200, x: 200, y: 200}
moved-green-box

Using Rect Properties and Functions

The following example script incorporates many of the properties and functions of the Rect class to generate a “flower” from a single selected square solid in OmniGraffle:

omnigraffle://localhost/omnijs-run?script=try%7Bvar%20cnvs%20%3D%20document%2Ewindows%5B0%5D%2Eselection%2Ecanvas%0Avar%20slds%20%3D%20document%2Ewindows%5B0%5D%2Eselection%2Esolids%0Aif%28slds%2Elength%20%3D%3D%3D%201%29%7B%0A%09s%20%3D%20slds%5B0%5D%0A%09g%20%3D%20s%2Egeometry%0A%09c%20%3D%20s%2EfillColor%0A%09c1%20%3D%20Color%2ERGB%28c%2Ered%20%2A%200%2E9%2Cc%2Egreen%20%2A%200%2E9%2Cc%2Eblue%20%2A%200%2E9%29%0A%09c2%20%3D%20Color%2ERGB%28c%2Ered%20%2A%200%2E2%2Cc%2Egreen%20%2A%200%2E2%2Cc%2Eblue%20%2A%200%2E2%29%0A%09%2F%2F%201%0A%09d%20%3D%20s%2EduplicateTo%28new%20Point%28g%2EmaxX%2Cg%2EmaxY%29%2Cnull%29%0A%09d%2EfillType%20%3D%20FillType%2ELinear%0A%09d%2EgradientColor%20%3D%20c2%0A%09d%2EgradientAngle%20%3D%20225%0A%09%2F%2F%202%0A%09d%20%3D%20s%2EduplicateTo%28new%20Point%28g%2EminX%2Dg%2Ewidth%2Cg%2EmaxY%29%2Cnull%29%0A%09d%2EfillType%20%3D%20FillType%2ELinear%0A%09d%2EgradientColor%20%3D%20c2%0A%09d%2EgradientAngle%20%3D%20315%0A%09%2F%2F%203%0A%09d%20%3D%20s%2EduplicateTo%28new%20Point%28g%2EminX%2Dg%2Ewidth%2Cg%2EminY%2Dg%2Eheight%29%2Cnull%29%0A%09d%2EfillType%20%3D%20FillType%2ELinear%0A%09d%2EgradientColor%20%3D%20c2%0A%09d%2EgradientAngle%20%3D%2045%0A%09%2F%2F4%0A%09d%20%3D%20s%2EduplicateTo%28new%20Point%28g%2EmaxX%2Cg%2EminY%2Dg%2Eheight%29%2Cnull%29%0A%09d%2EfillType%20%3D%20FillType%2ELinear%0A%09d%2EgradientColor%20%3D%20c2%0A%09d%2EgradientAngle%20%3D%20135%0A%09%2F%2F%205%0A%09d%20%3D%20s%2EduplicateTo%28new%20Point%28g%2EmaxX%2Cg%2EminY%29%2Cnull%29%0A%09d%2Erotation%20%3D%2045%0A%09d%2EfillType%20%3D%20FillType%2ELinear%0A%09d%2EfillColor%20%3D%20Color%2Ewhite%0A%09d%2EgradientColor%20%3D%20c1%0A%09d%2EgradientAngle%20%3D%20135%0A%09%2F%2F%206%0A%09d%20%3D%20s%2EduplicateTo%28new%20Point%28g%2Ex%2Cg%2EmaxY%29%2Cnull%29%0A%09d%2Erotation%20%3D%2045%0A%09d%2EfillType%20%3D%20FillType%2ELinear%0A%09d%2EfillColor%20%3D%20Color%2Ewhite%0A%09d%2EgradientColor%20%3D%20c1%0A%09d%2EgradientAngle%20%3D%20225%0A%09%2F%2F%207%0A%09d%20%3D%20s%2EduplicateTo%28new%20Point%28g%2Ex%2Dg%2Ewidth%2Cg%2EminY%29%2Cnull%29%0A%09d%2Erotation%20%3D%2045%0A%09d%2EfillType%20%3D%20FillType%2ELinear%0A%09d%2EfillColor%20%3D%20Color%2Ewhite%0A%09d%2EgradientColor%20%3D%20c1%0A%09d%2EgradientAngle%20%3D%20315%0A%09%2F%2F%208%0A%09d%20%3D%20s%2EduplicateTo%28new%20Point%28g%2Ex%2Cg%2EminY%2Dg%2Eheight%29%2Cnull%29%0A%09d%2Erotation%20%3D%2045%0A%09d%2EfillType%20%3D%20FillType%2ELinear%0A%09d%2EfillColor%20%3D%20Color%2Ewhite%0A%09d%2EgradientColor%20%3D%20c1%0A%09d%2EgradientAngle%20%3D%2045%0A%09%2F%2F%20center%20circle%0A%09aRect%20%3D%20g%2EinsetBy%28g%2Ewidth%2F5%2Cg%2Eheight%2F5%29%0A%09circle%20%3D%20cnvs%2EaddShape%28%27Circle%27%2CaRect%29%0A%09circle%2EfillType%20%3D%20FillType%2ERadial%0A%09circle%2EfillColor%20%3D%20Color%2Ewhite%0A%09circle%2EgradientColor%20%3D%20c2%0A%09%2F%2F%20original%20square%0A%09s%2EfillType%20%3D%20FillType%2ERadial%0A%09s%2EfillColor%20%3D%20Color%2Ewhite%0A%09s%2EgradientColor%20%3D%20c2%0A%7D%7Dcatch%28err%29%7Bconsole%2Elog%28err%29%7D
blue-flower-before
Generate “Flower”
 

cnvs = document.windows[0].selection.canvas slds = document.windows[0].selection.solids if(slds.length === 1){ s = slds[0] g = s.geometry c = s.fillColor c1 = Color.RGB(c.red * 0.9,c.green * 0.9,c.blue * 0.9) c2 = Color.RGB(c.red * 0.2,c.green * 0.2,c.blue * 0.2) // 1 d = s.duplicateTo(new Point(g.maxX,g.maxY),null) d.fillType = FillType.Linear d.gradientColor = c2 d.gradientAngle = 225 // 2 d = s.duplicateTo(new Point(g.minX-g.width,g.maxY),null) d.fillType = FillType.Linear d.gradientColor = c2 d.gradientAngle = 315 // 3 d = s.duplicateTo(new Point(g.minX-g.width,g.minY-g.height),null) d.fillType = FillType.Linear d.gradientColor = c2 d.gradientAngle = 45 //4 d = s.duplicateTo(new Point(g.maxX,g.minY-g.height),null) d.fillType = FillType.Linear d.gradientColor = c2 d.gradientAngle = 135 // 5 d = s.duplicateTo(new Point(g.maxX,g.minY),null) d.rotation = 45 d.fillType = FillType.Linear d.fillColor = Color.white d.gradientColor = c1 d.gradientAngle = 135 // 6 d = s.duplicateTo(new Point(g.x,g.maxY),null) d.rotation = 45 d.fillType = FillType.Linear d.fillColor = Color.white d.gradientColor = c1 d.gradientAngle = 225 // 7 d = s.duplicateTo(new Point(g.x-g.width,g.minY),null) d.rotation = 45 d.fillType = FillType.Linear d.fillColor = Color.white d.gradientColor = c1 d.gradientAngle = 315 // 8 d = s.duplicateTo(new Point(g.x,g.minY-g.height),null) d.rotation = 45 d.fillType = FillType.Linear d.fillColor = Color.white d.gradientColor = c1 d.gradientAngle = 45 // center circle aRect = g.insetBy(g.width/5,g.height/5) circle = cnvs.addShape('Circle',aRect) circle.fillType = FillType.Radial circle.fillColor = Color.white circle.gradientColor = c2 // original square s.fillType = FillType.Radial s.fillColor = Color.white s.gradientColor = c2 }
blue-flower-before

And here is a similar script written as an Omni Automation plug-in:

Replicate Square in Flower Pattern
  

/*{ "type": "action", "targets": ["omnigraffle"], "author": "Otto Automator", "identifier": "com.omni-automation.og.flower-replication", "version": "1.1", "description": "Will replicate the selected single-color filled square in a flower-like pattern.", "label": "Replicate in Flower Pattern", "shortLabel": "Replicate as Flower", "paletteLabel": "Replicate as Flower", "image": "rectangle.grid.2x2" }*/ (() => { const action = new PlugIn.Action(async function(selection, sender){ // action code // selection options: canvas, document, graphics, lines, solids, view try { /* To use with Browse tool, selection reference must be explicit */ var s = document.windows[0].selection.solids[0] var cnvs = document.windows[0].selection.canvas var docView = document.windows[0].selection.view g = s.geometry c = s.fillColor c1 = Color.RGB(c.red * 0.9,c.green * 0.9,c.blue * 0.9) c2 = Color.RGB(c.red * 0.2,c.green * 0.2,c.blue * 0.2) // 1 d = s.duplicateTo(new Point(g.maxX,g.maxY),null) d.fillType = FillType.Linear d.gradientColor = c2 d.gradientAngle = 225 // 2 d = s.duplicateTo(new Point(g.minX-g.width,g.maxY),null) d.fillType = FillType.Linear d.gradientColor = c2 d.gradientAngle = 315 // 3 d = s.duplicateTo(new Point(g.minX-g.width,g.minY-g.height),null) d.fillType = FillType.Linear d.gradientColor = c2 d.gradientAngle = 45 //4 d = s.duplicateTo(new Point(g.maxX,g.minY-g.height),null) d.fillType = FillType.Linear d.gradientColor = c2 d.gradientAngle = 135 // 5 d = s.duplicateTo(new Point(g.maxX,g.minY),null) d.rotation = 45 d.fillType = FillType.Linear d.fillColor = Color.white d.gradientColor = c1 d.gradientAngle = 135 // 6 d = s.duplicateTo(new Point(g.x,g.maxY),null) d.rotation = 45 d.fillType = FillType.Linear d.fillColor = Color.white d.gradientColor = c1 d.gradientAngle = 225 // 7 d = s.duplicateTo(new Point(g.x-g.width,g.minY),null) d.rotation = 45 d.fillType = FillType.Linear d.fillColor = Color.white d.gradientColor = c1 d.gradientAngle = 315 // 8 d = s.duplicateTo(new Point(g.x,g.minY-g.height),null) d.rotation = 45 d.fillType = FillType.Linear d.fillColor = Color.white d.gradientColor = c1 d.gradientAngle = 45 // center circle aRect = g.insetBy(g.width/5,g.height/5) circle = cnvs.addShape('Circle',aRect) circle.fillType = FillType.Radial circle.fillColor = Color.white circle.gradientColor = c2 // original square s.fillType = FillType.Radial s.fillColor = Color.white s.gradientColor = c2 // deselect docView.select([]) } catch(err){ if(!err.causedByUserCancelling){ new Alert(err.name, err.message).show() } } }); action.validate = function(selection, sender){ // validation code // selection options: canvas, document, graphics, lines, solids, view // square filled with a solid color if (selection.solids.length === 1){ solid = selection.solids[0] rect = solid.geometry return ( rect.width === rect.height && solid.fillColor !== null && solid.fillType === FillType.Solid ) } else {return false} }; return action; })();