From 92382ee1b8151426d87782bfcb6bbc13a7f25efd Mon Sep 17 00:00:00 2001 From: Sergey Osokin Date: Tue, 31 Aug 2021 20:42:19 +0500 Subject: [PATCH] Update SelectPointsByType.jsx Added Ortho points. Minor improvements --- README.md | 70 ++++--- README.ru.md | 68 +++--- jsx/SelectPointsByType.jsx | 409 ++++++++++++++++++++++++------------- 3 files changed, 336 insertions(+), 211 deletions(-) diff --git a/README.md b/README.md index 9e3761f..6923079 100755 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ -![header](https://i.ibb.co/4YFZbBm/header.png) -![illustrator-scripts](https://i.ibb.co/Pm60cLC/cover.gif) +![header](https://i.ibb.co/mF018gV/emblem.png) +# Adobe Illustrator Scripts [![Behance](https://img.shields.io/badge/Behance-%40creold-0055FF.svg)](https://behance.net/creold) [![Instagram](https://img.shields.io/badge/Instagram-%40serg_osokin-8034B2.svg)](https://www.instagram.com/serg_osokin/) [![Yotube](https://img.shields.io/badge/-YouTube%20Channel-FF0000.svg)](https://www.youtube.com/c/SergOsokinArt/videos) *Instructions in other languages: [English](README.md), [Русский](README.ru.md)* -# 👨‍💻 Hi -This is a collection of JSX scripts for Adobe Illustrator. All scripts created by me, sometimes used part of the code of other authors. +### 👨‍💻 Hi +This is a collection of JS scripts for Adobe Illustrator. All scripts created by me, sometimes used part of the code of other authors. The descriptions for each file can be found in the file's header text. Test environment: Illustrator CS6, CC 2021 (Windows), CC 2018-2021 (Mac OS). @@ -26,7 +26,7 @@ The descriptions for each file can be found in the file's header text. Test envi * [Rescale.jsx] `(upd, 24.03.2021)` * [ResizeToSize.jsx] `(upd, 22.03.2021)` * [SelectOnlyPoints.jsx] `(upd, 14.11.2020)` -* [SelectPointsByType.jsx] `(upd, 20.03.2021)` +* [SelectPointsByType.jsx] `(upd, 31.08.2021)` * [SplitPath.jsx] `(upd, 30.08.2020)` * [StrokeColorFromFill.jsx] `(upd, 30.03.2021)` * [TrimMasks.jsx] `(upd, 30.03.2021)` @@ -79,19 +79,20 @@ I recommend the [Scripshon Trees] or [LAScripts] panel. In it you can specify wh ### 💸 Donate (optional) If you find this script helpful, you can buy me a coffee ☕️ via [PayPal], [ЮMoney] or [Donatty] 🙂 -[PayPal]: https://paypal.me/osokin/2usd +[PayPal]: https://paypal.me/osokin/3usd [ЮMoney]: https://yoomoney.ru/to/410011149615582 [Donatty]: https://donatty.com/sergosokin + - + - + - + ## ArtboardsRotateWithObjects 1.2 @@ -108,7 +109,7 @@ Script to rotate 90 degrees an document artboards with all the objects on it. ![ArtboardsRotateWithObjects](https://i.ibb.co/YtV4nc6/demo-Artboards-Rotate-With-Objects.gif) - + ## ConvertToGradient @@ -126,7 +127,7 @@ What's new: The script now works with the RGB and CMYK document profile, Spot & ![ConvertToGradient](https://i.ibb.co/44tG9JP/demo-Convert-To-Gradient.gif) - + ## DuplicateArtboardsLight @@ -145,7 +146,7 @@ Script for copying the selected Artboard with his artwork. The Pro version with ![ConvertToGradient](https://i.ibb.co/rF92HpV/demo-Duplicate-Artboards-Light.gif) - + @@ -163,7 +164,7 @@ Exports all selected objects to AI files. ![Export-selection-as-AI](https://i.ibb.co/CPSRxq8/demo-Export-selection-as-AI.gif) - + ## ExtUngroup v.1.2 @@ -180,7 +181,7 @@ This script is сan be easily custom ungrouping to all group items & releasing c ![Zoom-And-Center](https://i.ibb.co/QngnpZL/demo-Ext-Ungroup.gif) - + ## FileVersionInformer @@ -199,7 +200,7 @@ Script for collecting information about the program version of .ai & .eps files ![FileVersionInformer](https://i.ibb.co/mz94Tn0/demo-File-Version-Informer.gif) - + ## GradientToFlat @@ -215,7 +216,7 @@ Convert a gradient to an interpolated solid color. ![GradientToFlat](https://i.ibb.co/yn1j852/demo-Gradient-To-Flat.gif) - + ## InlineSVGToAI @@ -232,7 +233,7 @@ The script inserts the SVG code as an object from the clipboard into the Adobe I ![InlineSVGToAI](https://i.ibb.co/xSzT8z4/demo-Inline-SVGTo-AI.gif) - + ## Named Items Finder @@ -253,7 +254,7 @@ Search items in the document by name and zoom to them contents. Inspired by Phot ![NamedItemsFinder](https://i.ibb.co/QDVtnXP/demo-Named-Items-Finder.gif) - + ## Points Move Random @@ -274,7 +275,7 @@ The script moves randomly in numeric ranges horizontally and vertically selected ![PointsMoveRandom](https://i.ibb.co/9ZsRQJk/demo-Points-Move-Random.gif) - + ## RandomScribble @@ -290,7 +291,7 @@ Creates random paths with a specified number of points. These can be random stra ![RandomScribble](https://i.ibb.co/b6FftPk/Random-Scribble.gif) - + ## RenameItems @@ -306,7 +307,7 @@ Script to batch rename selected items with many options or simple rename one sel ![Rescale](https://i.ibb.co/Gkcqt8D/demo-Rename-Items.gif) - + ## Rescale @@ -322,7 +323,7 @@ Automatic scaling of objects to the desired size. If you draw a line on top with ![Rescale](https://i.ibb.co/gDj142f/demo-Rescale.gif) - + ## ResizeToSize @@ -343,7 +344,7 @@ Adobe Illustrator has a Transform panel, but you cannot use it to transform seve ![ResizeToSize](https://i.ibb.co/FxPGDM2/demo-Resize-To-Size.gif) - + ## SelectOnlyPoints @@ -359,7 +360,7 @@ After using the Lasso tool or Direct Selection Tool, both Points and Path segmen ![SelectOnlyPoints](https://i.ibb.co/NF7bbpQ/demo-Select-Only-Points.gif) - + ## SelectPointsByType @@ -378,15 +379,16 @@ Select `View → Hide Bounding Box` to see active points in real time. 3. Click the button or use keyboard shortcuts: * Bezier Alt+1 -* Flush Alt+2 -* Corner Alt+3 -* Broken Alt+4 -* Flat Alt+5 +* Ortho Alt+2 +* Flush Alt+3 +* Corner Alt+4 +* Broken Alt+5 +* Flat Alt+6 -![SelectPointsType](https://i.ibb.co/8X0SFNc/demo-Select-Points-By-Type.gif) +![SelectPointsType](https://i.ibb.co/1MTyHx8/Select-Points-By-Type.gif) - + ## SplitPath @@ -408,7 +410,7 @@ Powerfull script for subtract shapes from paths. Pathfinder panel in Adobe Illus ![SplitPath](https://i.ibb.co/55fmqgY/demo-Split-Path.gif) - + ## StrokeColorFromFill @@ -425,7 +427,7 @@ Setting the Stroke color of object based on an his solid or gradient fill. The o ![SplitPath](https://i.ibb.co/8dtK1V3/demo-Stroke-Color-From-Fill.gif) - + ## TrimMasks @@ -445,7 +447,7 @@ If you want to save the filled mask after trimming, open the script file in a te ![TrimMasks](https://i.ibb.co/prkQGyt/demo-Trim-Masks.gif) - + ## Zoom and center @@ -463,7 +465,7 @@ Zooms active view to selection or to all object(s) in a document. ![Zoom-And-Center](https://i.ibb.co/4Kqx7J1/demo-Zoom-And-Center.gif) - + ## 🗣 Testimonials diff --git a/README.ru.md b/README.ru.md index c266f19..ee24465 100755 --- a/README.ru.md +++ b/README.ru.md @@ -1,11 +1,11 @@ -![header](https://i.ibb.co/4YFZbBm/header.png) -![illustrator-scripts](https://i.ibb.co/Pm60cLC/cover.gif) +![header](https://i.ibb.co/mF018gV/emblem.png) +# Adobe Illustrator Scripts [![Behance](https://img.shields.io/badge/Behance-%40creold-0055FF.svg)](https://behance.net/creold) [![Instagram](https://img.shields.io/badge/Instagram-%40serg_osokin-8034B2.svg)](https://www.instagram.com/serg_osokin/) [![Yotube](https://img.shields.io/badge/-YouTube%20Channel-FF0000.svg)](https://www.youtube.com/c/SergOsokinArt/videos) *Инструкция на других языках: [English](README.md), [Русский](README.ru.md)* -# 👨‍💻 Привет +### 👨‍💻 Привет Это коллекция авторских скриптов для Adobe Illustrator. Описание каждого скрипта также находится внутри его файла. Тестировалось в Illustrator CS6, CC 2021 (Windows), CC 2018-2021 (Mac OS). @@ -26,7 +26,7 @@ * [Rescale.jsx] `(upd, 24.03.2021)` * [ResizeToSize.jsx] `(upd, 22.03.2021)` * [SelectOnlyPoints.jsx] `(upd, 14.11.2020)` -* [SelectPointsByType.jsx] `(upd, 20.03.2021)` +* [SelectPointsByType.jsx] `(upd, 31.08.2021)` * [SplitPath.jsx] `(upd, 30.08.2020)` * [StrokeColorFromFill.jsx] `(upd, 30.03.2021)` * [TrimMasks.jsx] `(upd, 30.03.2021)` @@ -79,19 +79,20 @@ ### 💸 Поддержка (по желанию) Вы можете поддержать мою работу над новыми скриптами и их распространение любой суммой через [PayPal], [ЮMoney] или [Donatty] 🙂 -[PayPal]: https://paypal.me/osokin/2usd +[PayPal]: https://paypal.me/osokin/3usd [ЮMoney]: https://yoomoney.ru/to/410011149615582 [Donatty]: https://donatty.com/sergosokin + - + - + - + ## ArtboardsRotateWithObjects 1.2 @@ -108,7 +109,7 @@ ![ArtboardsRotateWithObjects](https://i.ibb.co/YtV4nc6/demo-Artboards-Rotate-With-Objects.gif) - + ## ConvertToGradient @@ -126,7 +127,7 @@ ![ConvertToGradient](https://i.ibb.co/44tG9JP/demo-Convert-To-Gradient.gif) - + ## DuplicateArtboardsLight @@ -145,7 +146,7 @@ ![ConvertToGradient](https://i.ibb.co/rF92HpV/demo-Duplicate-Artboards-Light.gif) - + @@ -163,7 +164,7 @@ ![Export-selection-as-AI](https://i.ibb.co/CPSRxq8/demo-Export-selection-as-AI.gif) - + ## ExtUngroup v.1.2 @@ -180,7 +181,7 @@ ![Zoom-And-Center](https://i.ibb.co/QngnpZL/demo-Ext-Ungroup.gif) - + ## FileVersionInformer @@ -199,7 +200,7 @@ ![FileVersionInformer](https://i.ibb.co/mz94Tn0/demo-File-Version-Informer.gif) - + ## GradientToFlat @@ -214,7 +215,7 @@ ![GradientToFlat](https://i.ibb.co/yn1j852/demo-Gradient-To-Flat.gif) - + ## InlineSVGToAI @@ -231,7 +232,7 @@ ![InlineSVGToAI](https://i.ibb.co/xSzT8z4/demo-Inline-SVGTo-AI.gif) - + ## Named Items Finder @@ -252,7 +253,7 @@ ![NamedItemsFinder](https://i.ibb.co/QDVtnXP/demo-Named-Items-Finder.gif) - + ## Points Move Random @@ -273,7 +274,7 @@ ![PointsMoveRandom](https://i.ibb.co/9ZsRQJk/demo-Points-Move-Random.gif) - + ## RandomScribble @@ -289,7 +290,7 @@ ![RandomScribble](https://i.ibb.co/b6FftPk/Random-Scribble.gif) - + ## RenameItems @@ -305,7 +306,7 @@ ![Rescale](https://i.ibb.co/Gkcqt8D/demo-Rename-Items.gif) - + ## Rescale @@ -321,7 +322,7 @@ ![Rescale](https://i.ibb.co/gDj142f/demo-Rescale.gif) - + ## ResizeToSize @@ -342,7 +343,7 @@ ![ResizeToSize](https://i.ibb.co/FxPGDM2/demo-Resize-To-Size.gif) - + ## SelectOnlyPoints @@ -358,7 +359,7 @@ ![SelectOnlyPoints](https://i.ibb.co/NF7bbpQ/demo-Select-Only-Points.gif) - + ## SelectPointsByType @@ -377,15 +378,16 @@ 3. Выберите любой тип точек, нажав на кнопку или горячими клавишами: * Bezier Alt+1 -* Flush Alt+2 -* Corner Alt+3 -* Broken Alt+4 -* Flat Alt+5 +* Ortho Alt+2 +* Flush Alt+3 +* Corner Alt+4 +* Broken Alt+5 +* Flat Alt+6 -![SelectPointsType](https://i.ibb.co/8X0SFNc/demo-Select-Points-By-Type.gif) +![SelectPointsType](https://i.ibb.co/1MTyHx8/Select-Points-By-Type.gif) - + ## SplitPath @@ -407,7 +409,7 @@ ![SplitPath](https://i.ibb.co/55fmqgY/demo-Split-Path.gif) - + ## StrokeColorFromFill @@ -424,7 +426,7 @@ ![SplitPath](https://i.ibb.co/8dtK1V3/demo-Stroke-Color-From-Fill.gif) - + ## TrimMasks @@ -444,7 +446,7 @@ ![TrimMasks](https://i.ibb.co/prkQGyt/demo-Trim-Masks.gif) - + ## Zoom and center @@ -463,7 +465,7 @@ ![Zoom-And-Center](https://i.ibb.co/4Kqx7J1/demo-Zoom-And-Center.gif) - + ## 🗣 Отзывы diff --git a/jsx/SelectPointsByType.jsx b/jsx/SelectPointsByType.jsx index 5385a47..6235f17 100644 --- a/jsx/SelectPointsByType.jsx +++ b/jsx/SelectPointsByType.jsx @@ -1,6 +1,6 @@ /* SelectPointsByType.jsx for Adobe Illustrator - Description: Selects points on the selected paths according to their type. + Description: Selects points on the selected paths according to their type Date: May, 2020 Author: Sergey Osokin, email: hi@sergosokin.ru @@ -10,141 +10,154 @@ 1.0 Initial version. Tolerance for broken points handles 0..180 degrees 1.1 Changed points type algorithm. Broken points 0..15 degrees. Corner points > 15 degrees 2.0 Added more points type. Minor improvements + 2.1 Added Ortho points. Minor improvements Donate (optional): If you find this script helpful, you can buy me a coffee + - via YooMoney https://yoomoney.ru/to/410011149615582 + - via QIWI https://qiwi.com/n/OSOKIN + - via Donatty https://donatty.com/sergosokin - via PayPal http://www.paypal.me/osokin/usd - - via QIWI https://qiwi.com/n/OSOKIN​ - - via YooMoney https://yoomoney.ru/to/410011149615582​ NOTICE: Tested with Adobe Illustrator CC 2018-2021 (Mac), 2021 (Win). This script is provided "as is" without warranty of any kind. - Free to use, not for sale. + Free to use, not for sale - Released under the MIT license. + Released under the MIT license http://opensource.org/licenses/mit-license.php Check other author's scripts: https://github.com/creold */ //@target illustrator -var SCRIPT_NAME = 'SelectPointsByType', - SCRIPT_VERSION = 'v.2.0', - MIN_ANGLE = 0, // Degrees range for the Tolerance - MAX_ANGLE = 180, // Degrees range for the Tolerance - COS_INACCURACY = -0.999999, // Correction of coordinate inaccuracy - COS_180 = -1; - -// Binary icons data -var BIN_BEZIER_N = "\u0089PNG\r\n\x1A\n\x00\x00\x00\rIHDR\x00\x00\x00!\x00\x00\x00$\b\x06\x00\x00\x00\x07)S\u00DC\x00\x00\x00\tpHYs\x00\x00\x10\u009B\x00\x00\x10\u009B\x01t\u0089\u009CK\x00\x00\x02\u00AEIDATX\u0085\u00ED\u0097_HSQ\x1C\u00C7?\u00B7?lT\u008CY\u009A\t\u0091\u00B9^4\x04\u0087E\x1A\x14\u00CC\u0097\u00E8\x1F\x14\x04\u00BD\u00F8\u00E0 \u00B0\u0082J\t_/\u0099#\u00E8)*\u0082,\u00C8\u00F4\u00C1\u00A7\x10\f\u00B2\u00A4\u0097\u0084z\u00A8\u0088\u00B5Q\u00E0C`3\u00A4U&MM\u009B\u0096\u009D8\u00D7\u00DDy\u00B6\u00DD9k\x0F\u00F6p\u00BFp\u00E1\u009C\u00DF\u00FD\u009D\u00EF\u00F9\u00EC\u00FC\u00BD\u00D3\u0084\x10,\u00B7V,;\u0081\r\u00A1\u00C8\u00860eC\u0098\u00B2!L\u00FD\x17\x10\u00AB,\u00A3\x01m+ \u009F\x18\u00BA\b-\u00EA\x10\u00D0\u00DC\u00807Q\x0B\u00A1\u008BX\u008E|\u0099+\u00DBD\u00D0ED\u00862\u00EF\u008E\u009B\x15\u00ED8\x0B\x1A\u00F0\u00ECs\x12}\u00F5\u0093\u0089\u0091\u00974\u0086\u00F6X\x1A\u00DE\u00A9\u00D9Kl\u00E8!\u0095\u00F5\u00EB\u008C\u00FA\u00DB\u00EE\u00EF\u00B8=\x079\u00F1\u00E2\u00A9e\u00FEm\u00EF3\\\u009BwQ\u00B2s5C\u008F\u00E3\u00C4\u00BFuqz\u00F0\x14\x12\"\u00F9\u00B4\u00E1\x15\x1D\u00BB\x7F\bU\u00FDMB\u00B4W\u00B6\u00A4\u00E5\u00B9E\x1B~q\u00BDl\\D_/$\u00CB\u00B2\u008C\u00C9w2Gm#=\u00A4\u0097*\u00D9W\x1B\u00DE\u00D4\u00E9(\u00A9\u00AE\u00A7\u00BA\u00D1\u0099\x12+?\n\u00EF\x1E\u00B4\x10\u00D0\x0E\x03\u00CE\u00C44\x15\x1B\u00EF\x1C.\u00D8\u00E4]\u00C8\u0095e\u0087\u00CB\x05\u00DC5\u009E\u0080\u00F6\u00D9\x18v\u0088S\u00B0\u00AD\u00DC\u00F0R\u00B5\u00FD\u00B8\u0093\u00B9\u0099\u00FA\u00D4\u0085\x19\r\u00F6\u00F1)m\t\u00C4\"\u00E0t\u00F7\x03\u00BD@M\x12@jb\x04\u00E2\u00CA\x12\u0090\u00E5\u00C9\u008Fj\u00EB\u00E2D\u009B^\u00C3#\x16\u00C9\u00F4\u009E\x1E\x0Be\u00AE\u0089k[F\u00A9=_H\u0095\x1F\u0086\x07\u00A0\u00EF\u00E44S_\x1E\x01\u00C7\u00D2fx\x18\u00B7g\u008C\u00A2\u008A*\u00F6\u00DFXiD\u00FA\u00CF\u00CC1:\x18&6\u00B4\x01(M\u00CB\u00EFa\u00ED\u00C6\x03\x1C\u00BA\u00B5\u0086R\x1F\u0084;\u00E1\u00F9\u0095\u00AF4}(\u00CA\u0084\u0090\u00AB\u00BDd\u00C7Uf\u00C6}8\\o\u0088\x06g\u00D2\x00\u0086\u0081Vt\u00D1i\u00D4:j\x1B\u0099\u009D\u00B2A(g1K\u00DB\u008EK\u0093\u00EA\u0095\u00EC\u00C3\u00FA*W\u00D7D\u00AE\u00AB\u00FCo$\u00BD\x02Z]z\x0B\u00FBo\u00A0)\x1B\u00C2\u0094\ra\u00CA\u00860\u00B5\u00FC\x10\u00C0\x1F\u00C1c-8\u00DA\x1D\u00C2\u00CF\x00\x00\x00\x00IEND\u00AEB`\u0082", - BIN_BEZIER_D = "\u0089PNG\r\n\x1A\n\x00\x00\x00\rIHDR\x00\x00\x00!\x00\x00\x00$\b\x06\x00\x00\x00\x07)S\u00DC\x00\x00\x00\tpHYs\x00\x00\x10\u009B\x00\x00\x10\u009B\x01t\u0089\u009CK\x00\x00\x03\x00IDATX\u0085\u00ED\u00971L\x13Q\x18\u00C7\u00FFEI^\x1As\x11SJ\x17(\u0096E\u0098:\x10\x1B\x13\u009B\u00C0f\u008CD\x12\x13\x16b`\u00F2u\u00D0\u0088\t\u00860\u0090\u00B6!\u00D2\x12\x1Dt\u00EB\u009B\u00944\x0E`Lp\u00D0\u00B8iPbp*\x18`\u00C1J\x0F\x16\u00C9\x11Z#w\u00B5\"\u0098g\u00EE.\u00AFpW\u00D0\x0E8\u00DC?\u00B9\u00E4\u00DD\u00D7\u00F7\u00FE\u00DF\u00EF\u00BE\u00F7\u00DDk\u00EB\u00DA\u00DB\u00DB\u00C3q\u00AB\u00E6\u00D8\t\x1C\bA\x0E\u0084!\x07\u00C2\u0090\x03a\u00E8\u00BF\u00808i\x15\u00A4\u00946\x03\u00E0W\u009E1\u0096\u00A9d@)=\r \u00A8\u00DFf\x18c\u00F9C\u00E6\u00F3\u00B9|\u00CD*cl\u0095\u00C7\x0E|wD\u00A3\u00D1\u0094\u00DB\u00ED\u00EEkkk#\u00B9\\\u00EE\u00E7\u00D6\u00D6\u00D6\u00C7\u0091\u0091\u0091\u008BV\u0086\u0089D\"\u00AC(\u00CA\u00ABP(t\u008A\u00DF\u00CF\u00CD\u00CD}\u00F7x<\u0097\u0087\u0087\u0087\u00DFY\u00CD\x1F\x1D\x1D}_WWw\u00DE\u00EF\u00F7\u00D7.--\x15UU\u009D\u0088\u00C7\u00E3\u00912\bN\x19\b\x04>\f\r\r\x11#655\u0085\u00E5\u00E5\u00E5\u00BB\u00D1h\u00F4\u00C1\u00BE\u00A7\u00EF\u00F6x<\u008F\"\u0091\u0088\u00D4\u00D8\u00D8\u00F8'\u00BE\u00B6\u00B6\u0086T*\u00F5MQ\u0094\u00DB\x00\u00A6\u00C5\u00AA\u00C4\u00E3\u00F1\u00C1\u00D6\u00D6\u00D6\u00FB===f\u00BE\u00F1\u00F1\u00F1b6\u009B\u00BDP\u00B6\x1DMMM\u00BD\u00E1p\u0098\u0088\u00B1`0\u0088\u0085\u0085\u0085AJ\u00E9\x15\x00D\u00DF\u00A6\x06\u00FE\x19!\x04\x06\x00\x17\x1F\x13B$\x00\u008F\u00F9E)\u00FD\u00CA\u00CB\x0E\u00A0X__\x7F\u008E{\u0089joo';;;\u00BDe\u008D)\u00CB\u00F2\u00CB\u00F5\u00F5\u00F5\u00B2\u0089\u008A\u00A2\u00C0\u00EDv\u00BF\u00E6O\x06 d\x00p\u00E5\u00F3y\u00A8\u00AAj\u00CE\u00E5\u00E3B\u00A1 .o\u00D0\u00D7Ls\x0F\u00EE%jss\x13\u00DB\u00DB\u00DB\u0099\x13\u00B1X\u00CC\fwuu\u00AD\u00A6\u00D3\u00E9\u009B.\u0097\u00CB\u00ED\u00F3\u00F9\u00B0\u00B8\u00B8\u0088\u00C9\u00C9IuccC\x06pg\u00DF\x16\u00E7$I\u00CA\u00AE\u00AC\u00ACx[ZZj4MC:\u009D\u00FE\u00A5iZFU\u00D5\u0092\u00DE|\u0086.\x15\n\u0085\u00CF\u00D9l\u00B6\u00D9\u00EB\u00F5\u00D6J\u0092\u0084\u0099\u0099\x19\u00CC\u00CE\u00CE*\u0089D\u00E2\u00FA\u0081\u00C6\u00E4\u00FB\u00ED\u00F7\u00FB\x1Fj\u009A\u00D6A\b\u00F9$\u00CB\u00F2\x0F\x00\u00D7\u00C4\u00E4\x00b\u008C\u00B1'\u00FC&\u0099L\u00DE(\x16\u008B\u00B7\u00F8\u00B8T*%\u00C7\u00C6\u00C6\u009E\u00EA>\u00FD|\x1E\x00\u00BF\u00B0\u00F6\u00B9\u00CF\u00E7;\u00B3\u00BB\u00BB\x1B \u0084<\u0093e\u00F9\x1E\u00EF\u009B\u008A\u00BF\u00AC(\u00A5\u00DC$*\u0084^\x00\u00E8?\u00EC5\x14\x1F\b\x00\u0087\u00BD*\u0084\u00E3\u008C\u00B1\u00988\u00CF\x16B?+\u00BE\b\u00A1\t\u00C6X\u00FFQ\u0092[xq\u0090>!t\u00D68#p\u00C8\u0089)\u00D2\u00F2-\x18\u00F8\x17\x00]\x03\u00BA\u0087\u0095\u00B7u%,\u00AA\u00D0\u00C9\x18{[\x05\x04\u00F7\u00EC\x00\u00F0F\b\u0099\u00D5\u00B0\u00ABD\u00B70\u009E\u00AF\x16\u0080K\u00F7\u0098\u00B7\u00CAa\x07\u00D1!\u008C\u00A7\u00AB\x05\u00B0\u00F12s\u00D8A\u0088\u00EFx\u00D5U\u00B0\u00F12s\u00D8A\u0088\u00E7\u00EB\u0091^\u00C7#J\u00F42sT\u00EA\u0089N\u00BD!+~\u0095\u00FF\u008Dt\u00AFN\u00FD2{\u00C2\u00F9\x1Bh\u00C8\u00810\u00E4@\x18r \f\x1D?\x04\u0080\u00DF\u00D6\x06/t\u00D4\x0BO\u00DA\x00\x00\x00\x00IEND\u00AEB`\u0082", - BIN_FLUSH_N = "\u0089PNG\r\n\x1A\n\x00\x00\x00\rIHDR\x00\x00\x00!\x00\x00\x00$\b\x06\x00\x00\x00\x07)S\u00DC\x00\x00\x00\tpHYs\x00\x00\x10\u009B\x00\x00\x10\u009B\x01t\u0089\u009CK\x00\x00\x01\u008FIDATX\u0085\u00ED\u0097O(DA\x1C\u0080\u00BF\u00DD\u00A5$\u00B2\"R\u008Ap\u00E0\u00A0=qS{P('\u00E5\u00BC+G\u00C2a\u0085\u00C3+\u00DA\u0083\u00DC6))\u00EA\u00DD\u00DC\u00B4\u00C7=#\u00B5\u00EDe\u00DD(j\u00DDV)\u00C4\u00C1\u00E6\u00CF\u00D3zf\u009B5\u00FB\u00C7\u00C6\u00EE^\u00E6;\u00CD\u00FB\u00CD\u00BCy\u00DF\u00F4\u00FB\u00BD\u0099\u00C6aY\x16\u00D5\u00C6Yu\x03-!\u00A1%\x04ZB\u00A0%\x04ZBP\u00A3DJ!\u00E8p\u00D3\u00DA\x7F\u00C4\u00C7\u00FB\u00D0\u00D7[NW\u008C\u00BB\u008B)\f\u00EB!\u00E7,{\u0083\x01ROk\u00D4\u00B78yN\u00A6h\u00EC\u009Cf6z\u0092\u00FF\x00\x0B:\u00BC\u0080W\u0089\u00CB4\u00F7\u00F8\x181\u00BA\u00F1\u00F8\u00ED\u00E0\u00B9\t\u00A7\u009B1\u00E6.\u0087\u0095\u00B1\u00BB\x03\u00938k\u00C3\u00F8\u008E]\u00D4\u00B9!\x19\u0087\u00C3\u0089\x17\u009E\u0093\x1D\u0085$B\u00C0\u00A2\x12\u00CF\u0092\u00E8\u0085\u00F9\u00AB\u00EC\u00D8N\x1F\u00DC_\u00DF\x02&\x10\u00C9\u00C4\u00DB\x06W\x19\u00DF\x1E\u00A3KZW4\x04\u00F1\u0083\u00E5r\u00D5D;\u00B0\x02\u00A4\x17\u00D2\u00A0\u00F4\u00FE\u00A0PM\u0084\u0081\u00DC\u00B9\u00CD`\u00F987\u00B3\u00D3\u00F1\u00F1\u00FA&\u00CD\u00EB\x01\x02\x18\u0096\u0097\u00DD\u0081\x06\"\x0B\u00A3Y\u00E98\u00DBJ\u00A7c?\x7F:~C\u00EE\u00C2\u009C\x016\x00\u009F4\u00C3\x06\u0086\u00B5^za\u00FE\u0095\u00A0\u00C3\u0094D\x1E\u0081\u00EE|\x7FM9\u00F7\u0089\u00A5\u00EF\u008F\u00A7i\x02\u00FC\u00CA\u0088\u00B2K\u00D8\u00AB\x0EI\u0091*H\u00D8\u0098R\u00DB\u00A3\u00F4VD\u00C2\u00B0\x12\u00C0M\u00E6\u00D9\u00DE\x00\x15*qv$\u00A4\u00B6[\u00E9-\u00B2O\u00FC\x17\u00E1b\x12\u00FA\u00F2#\u00D0\x12\x02-!\u00D0\x12\x02-!\u00A8\u00BE\x04\u00F0\t3\u00E3|\u00ABJ\u0092\x0EH\x00\x00\x00\x00IEND\u00AEB`\u0082", - BIN_FLUSH_D = "\u0089PNG\r\n\x1A\n\x00\x00\x00\rIHDR\x00\x00\x00!\x00\x00\x00$\b\x06\x00\x00\x00\x07)S\u00DC\x00\x00\x00\tpHYs\x00\x00\x10\u009B\x00\x00\x10\u009B\x01t\u0089\u009CK\x00\x00\x01\u009BIDATX\u0085\u00ED\u00971k\u00C2@\x18\u0086\u00DF&\x1D\u008A\n\u00CD\"\u00B5\u0088\u00E0?p\u00B2\u0083\u0093C\x07\u0091\x0E\u00A5Pp\u00B3\u0085\u00C2-\u0085v\b\u0094Li\u00FC\x05\u00E2v\u00D0\u00C1\u00D1\u00A98\u00C9\u00ED\u0095,\u00FE\t\u008BKF\u009B\u00A9\u0081\u00AA%\u0092\u0083\u00ABg\u00B4\u00D2\u00AA\u00CB=\u00D3\u00E5\u00BE\u00CB\u00E5\u00C9}_\u00EE\u00C8\u00C1l6\u00C3\u00BE\u00D1\u00F6n\u00A0$\x04\u0094\x04GIp\u0094\x04GIp\x0E\u00A5\u009E\r \u0084\x18\u0099L\u00E6u:\u009D\x16\u00C3\u00BB4M\x1Bx\u009EwE)\x1D/\u009B\u00C5q\x1C3\b\x02+\u0099Lj\u00BE\u00EF\x07\u0086a\\[\u0096\u00F5\x16{\u0080\x11B\u00CA\x00\u00CAR@ \u009DN\u00D7\u00AB\u00D5j\u00BET*\u00CD;]\u00D7\x05cl\u00D0h4\u00CE\x16\u00C7\u00DA\u00B6}\u00A1\u00EBz\u00D74M=\u0091H`4\x1A\u00A1\u00D5j}\u00FA\u00BE\x7F\u00BAj%.\x01\n\u0099\u008C8\x00Xq\u00CE\u00DF\x07{\u0096\x00\u00DEd!\u0093fB\x06@\u00E9\u00D7\u00ABA\u0089\u00F6o\x0F\u00CD\u00884B\x160\x07\"\u0085\u0098\n\u0098\n\x19E\u00CC\x05L\u0081\x1CE\u00A8\x02d!cwb\u00A3\n\x18\u0081ld\x10\u008F\u00FD\u00DFK\tp\x00\u00B2\u00EB\u00FB\u00A3{\u00D2\x1D;\x18c\x0B\u00C6\u00D8rl\u00DF\u0094\u0083\u00FAQ_q\u008E~\x03\x13\u00D1\b\x11\u008D\x10\u00D1\b\x11\u008D\u00E8\x02\u00E0\x17\u00C3'\x02!\u00E0\x11\u00BBV\x00\x00\x00\x00IEND\u00AEB`\u0082", - BIN_BROKEN_N = "\u0089PNG\r\n\x1A\n\x00\x00\x00\rIHDR\x00\x00\x00!\x00\x00\x00$\b\x06\x00\x00\x00\x07)S\u00DC\x00\x00\x00\tpHYs\x00\x00\x10\u009B\x00\x00\x10\u009B\x01t\u0089\u009CK\x00\x00\x02IIDATX\u0085\u00EDW\u00BFO\x14A\x18}sR\x001\u00E1\x14-\u00AC8b\x026\u00863\u00C6J\x12\u008E\u00F8\x07@hi\u00AE\u00B1UCE\u00B3\u00F1p\x1A+sj\u00AC,\u00BC\u0086\x16\u00AE\u00B23z\u0089\u009D1@GB\u00C1u\x14p\b\u00CD\x1E\u0089rc\u00BE\u0099\u009B\u00BDqng\x7F\x1C\u00C5Y\u00ECK6\u0099\u00F9\u00BEo\u00DE\u00BE\u00F9\u00E6\u00ED\u00DE\x1E\x13B`\u00D8\u00C8\r]A&\u00C2@&B\u00E3\u00BF\x101\x12\u0099\u00E5\u00AC\u0080;\x0F+r|\u00F4\u00B3\x02O4\x07\u00BAK\x1C\x0F\u00BD'B\u00AF\u00B7S\u00AB\u00E2\u00C3\u00AC/\u00F6\u00B7\u0085\u00BChL1W\u00FD\x15x\u00A2\x16\u00B7D\u00FB\u0097\b@c\u008A\u00A5\x17\x11\u00CB\u00E3\u00F6\u00C4\u00F8d\x0E\u00A3\u00F9\u00DE\u009C\u00C6\x14K\u008B\x04cr\u00E6\x06\u0084\u00B8\u00DF\u009D\x1F\u00E0\u00F4\u00C0\x07\u00F0\u00D8\u00AA#\u008F\u0094\u00E1\u0089\u00DD\u00C1DpF\u00AE\u00FB\x14B\u00FA\"0^\u00FF\x1A2n\u00CD\x12}\x0E`9lM\u00DC\u00D3\u00B1\f`\u00DB\u008An\u00C0\x13\u00B1-\u0096\u00C7\u00A7\x1E\u00D3\u00E7V\u00E6\u0081\u00DD\x11\u00B7\be**\u009E0vRr\u00B54f#5\u008B\u00A7h>\u00A6Q\u00C6\u00B4\x17\u00A6\x17@\u00F0D]\u00AEU\x1C\u00E8rV\u00CD\u0092\u00F0N(#\u00EE\x18\u0091E\u00E7\u00F9'E\u00FF\u00D1N\u00EBn\u00B8:Q6\u00C6\u008D+\x0B@\u00D0\u0091F\u00D8=\\\"\u008A\u00C6\u00B8\u00EA\u00A8\x19\x04&W\u00F0C\u00E8\x12a\u00BE\u00E9\u00D2\u00FB\u00C0\r\u0093+\u00B8\u0087\u00EB\u00F3\u00AEw\x1C\u0083~\u00D2\u0085\u0081\u00B88[\u00B43\u00D9\u00DF@\u008DL\u0084F&B#\x13\u00A11|\x11\x00\u00FE\x02\u00BBf\u00F1\u00FER\\>\u008B\x00\x00\x00\x00IEND\u00AEB`\u0082", - BIN_BROKEN_D = "\u0089PNG\r\n\x1A\n\x00\x00\x00\rIHDR\x00\x00\x00!\x00\x00\x00$\b\x06\x00\x00\x00\x07)S\u00DC\x00\x00\x00\tpHYs\x00\x00\x10\u009B\x00\x00\x10\u009B\x01t\u0089\u009CK\x00\x00\x02MIDATX\u0085\u00EDW\u00BF\u008F\x12A\x18}\x12\x1A\x17\u0089g(\u00A0\u00E3\u00FC\x03\u008CX\u00D8\u00A0\u0089\u00D0\u0093x\u00A1\u00B5\u00A1\u0091\u00AF\u00F4b\x074\u00D8P\x1A\u00DA\u0089\u0085\u00D7\u00D8\u00A2&\u00C4V/\u00B9\u00D0X\u00DCY[(\x1D!!\u00D1\u00C0\u00AE\r\u00B0\u00E6#3\u00EBd\u00B3\u00B3?\u00B8\x02\u008B}\u00C9&\u00DF\u00CC|\u00F3\u00E6\u00ED7of\u00E1\u0086\u00EB\u00BA842\x07W\u0090\u008A\u00D0\u0090\u008AP\u00F8/Dd\u00C3\x06\u0089\u00E8\u00B8\\.\u00F79\u009EN\u00A7}!\u00C4\u00CF}\x16\u0089\u00E21\u00DE\x13\u00DDn\u00F7Y6\u009B}\u00D3l6or{4\x1A\u00FDY\u00AF\u00D7\u00CF\x07\u0083\u00C1\u00BB$\x02b\u00F1\u00B0\u0088\u00A0\u00A7\u00D3\u00E9,l\u00DBv\x158\u00E6>S\u00FEux\u008C\u009E\u00C8\u00E5r\x19\u00CB\u00B2\u00BC6\u00C7\u00DC\u0097\u00A4\nqy\u008C\u00A4\u00B6mo\x1D\u00C7\u00F1\u00DA\x1C\u00AFV\u00AB[DT\u008B+\u0080sy\u008E\u009F\u0087\u00B9\u00F5\u00BCD\u009Ep\x1C\u00E7\u00F5r\u00B9|,S\u00D8hW\u00A5Ri\u00B4\u00DDn\x1F\u00EE\u00DE(\u0093\u00F9:\u009B\u00CD\u009A\x00*r\x1C\u00F9|\u00FE\u00C2\u00B2\u00AC\u0097a\u009E\b\u00FD\u0080\u0099\\-\u00AB\u00D1/\x14\n\u00F7\x1B\u008D\u00C6Q\u00B5Z\u00DD\u00E5O&\x13\u008C\u00C7\u00E3_\u008B\u00C5\u00E2\x1B\u008F\x0B!\u00BE\u0084\u00F1xHj4\u00F5\u00B4\u00DB\u00EDZ\u00AF\u00D7\u00DB\u00B8>p\x1F\u008F%\u00E1\n\u00BD'\f\u00D5\u00E1R\x0F\x01<1\u00A4\u00B0\u00CF>\x13\u00D1G\x00\u00A7q\u00EE\u0096\u00D8n'\u00A2#\"\u00E2\u00C5/\u0095\u0080\u00CDf\u00B3\u00DB\x02\x05\u008E\u00B9O\u00E2)\u0080\x1FD\u00D4\u008F\u00E2\u008E\u00F5\u00A3F\u00BE\u00FD\x07\x00e\u00DF\u00D0\u00A7b\u00B1x\u00C7u\u00DD{\u00B2\u00FD}>\u009F\u00F3Qx\u00E4\u00CBc\u008F\u00B4\u0084\x10W{\u0089 \u00A2\x16\u0080\u00B7\x01\u00A4\u00A7\u00CAx\x01s\u00D8\u00B8g>\u00D1\u00BF\x01\u009C\x04\u00CD\u0089:\x1D'\x00\u00DE\u00FB\u00BA_\t!\"K\u00CC\u00DB'\u008F\u00E9\x0B\u00DF\u00D0\x03\x7FE\u008C\"\u00F8X\u00F1=\x00\u00E0\u00B6\u00F6&5SI#^\u00E4\u00CC\u00C7S\u00D1\r\x1BfL\u00FF\u00C4\u00C4\x02\x18B\b\u00F6RMr@r\x0E\u00F5\u009C\u00C0JH#^j]u\u00D3\u00FE\u00C7E\u00C0\u00D6\u00DEU\u00D50U\u00A2\u00A5\u00C5\u00E7\u00D7\x15\u0080\x7F\x159\x0FZ\u00C3$\u00A2\u00A2\u00C5CC\u00CE>\u00D0\u00B9\u00BC\x0F\u00A1I\u00C4\u00B1\x16'\u00F6A\bt.o\u008D\u00B0\u00ED\u00A8K/\u00EC\u00F5\u0093.\b\u0092\u00AB.\x1Fo;\u00D2\u00BF\u0081\n\u00A9\b\u0085T\u0084B*B\u00E1\u00F0\"\x00\u00FC\x05\u00C3y\u00DE9\u0083\u00DD$\u00D7\x00\x00\x00\x00IEND\u00AEB`\u0082", - BIN_FLAT_N = "\u0089PNG\r\n\x1A\n\x00\x00\x00\rIHDR\x00\x00\x00!\x00\x00\x00$\b\x06\x00\x00\x00\x07)S\u00DC\x00\x00\x00\tpHYs\x00\x00\x10\u009B\x00\x00\x10\u009B\x01t\u0089\u009CK\x00\x00\x00\u00D2IDATX\u0085\u00ED\u00D61\n\u0082`\x18\u00C6\u00F1\u00E7\u00B3\x0EP\u00D0\x01\u00A4\u00A9\u00AD\u00A91\u00F0\f]\u00C0.\"\rv\x10\u00BB@g\x10\x1C\u009B\u00DC\u009A\u00C2\x03\x04u\u0081zC\u00E3\x15\u00E5C\u00D4\u00A1tx~\u0093\u00BC\u00A8\u00FC\u00F5\u00FB\x10\u008D\u0088`h\u00CE\u00E0\x05\u008C\u00A8`\u0084b\u0084b\u0084b\u0084b\u0084\x1AE\u00C4\u00D4\u009A\u00F4\x11\u009A\x19\x16\u00AB3\u00DE\u00AFMq\u00953\u00B9\u00E0~\u00DD!\u0090g\u009F\u00DB4\u00FFO\u0084\u00C6\x03\u00E0Y\u00F3\u00AA\u00F9\u00D2\u00C76p\u00B1\u00DE\x7F\u0087i\x04$a\u0086\u00C7\u00EDd\u009D[\x17#\u0090\u00B8\u00CB\u009B\u00C8\x03\x0E\u00D6\u00B4\u00FE\f(\x03r\u00F9qrt\u00DB\u00AF+\u0094\x11\u00A3\u00DF\x13\u00B15\u00B1\u0088\u008F4\u00AA/\x07$\x03\u00D0\u00BE\x1C\x15\u00CD{\u00A2\u008B\u009Fo\u00CC?\u00E2\u00C7J1B1B1B1B1B1\u00A2\x00\u00E0\x03\u009B\u00C37\u00B2\x01}r6\x00\x00\x00\x00IEND\u00AEB`\u0082", - BIN_FLAT_D = "\u0089PNG\r\n\x1A\n\x00\x00\x00\rIHDR\x00\x00\x00!\x00\x00\x00$\b\x06\x00\x00\x00\x07)S\u00DC\x00\x00\x00\tpHYs\x00\x00\x10\u009B\x00\x00\x10\u009B\x01t\u0089\u009CK\x00\x00\x00\u00D3IDATX\u0085\u00ED\u00D6/\x0E\u00830\x1C\u0086\u00E1o\u00CD\x0E0C\u0082\u00E4\x123(t\u00E5.\u0080\u00EC1v\u008E\u00CA]`\u00B2\u00BA\u00AAf\u0097@\u0092`v\x02X \u00FB%\u00B0\u0086\f\u00C4\x06\u00E2{T)\x7F\u00F2\u00866\u0084C\u00D7u\u00D8\u009A\u00DA\u00BC\u0080\x11#\u008C\x10\u008C\x10\u008C\x10\u008C\x10\u008C\x10\u00BB\u00888F3+\x18cNi\u009A\u00DE\u00DB\u00B6=\u00F7w)\u00A5\x1Eu]_\u00AC\u00B5\u00CF5\u00CF\u0099\u00FD\u009F0\u00C6\x14\x00\u008A\u00E8\u00C4H\u0092$\u00A5\u00D6:\u00CB\u00F3|\u0098\f!\u00C09W5Ms\u008B.\u009E\u00F2\u00D6Z\u00BF\u00E4M\u00F4\x01\u00D7h\u00F6\u0083\x04\u00E0=v\u00CEeK\u00EE\u00EBCd\u00B0\u00FB=\u00E1\u00A3\u0099X\x19B\u0098,\x07\u0080\n\u00C0\u00D7\u00E5\x18\x1F\u00CC\u00EE\u0089%~\u00BE1\u00FF\u0089\x1F+\u00C1\b\u00C1\b\u00C1\b\u00C1\b\u00C1\b\u00C1\u0088\x01\u0080\x17\u0086\tB\u00AD7\u00CDR\x16\x00\x00\x00\x00IEND\u00AEB`\u0082"; // Main function function main() { - if (documents.length == 0) { - alert('Open a document and try again.'); + var SCRIPT = { + name: 'SelectPointsByType', + version: 'v.2.1' + }, + CFG = { + aiVers: parseInt(app.version), + minAngle: 0, // Degrees range for the Tolerance + maxAngle: 180, // Degrees range for the Tolerance + cosTolerance: -0.999999, // Correction of coordinate inaccuracy + uiOpacity: .96 // UI window opacity. Range 0-1 + }, + ICNS = { // Binary icons data + bezierNormal: "\u0089PNG\r\n\x1A\n\x00\x00\x00\rIHDR\x00\x00\x00!\x00\x00\x00$\b\x06\x00\x00\x00\x07)S\u00DC\x00\x00\x00\x19tEXtSoftware\x00Adobe ImageReadyq\u00C9e<\x00\x00\x02\x0BIDATx\u00DA\u00ECV\u00BDR\u00C2@\x10^\x18g\u00A4\u00D2he\u00C7\u00D9h\x1B\u009F\x00\x1C{\u00C4'@\u009E@}\x01DZ\x0B\u00C0\x07P\x18\x1F\x00\u00B0\u00B4!tZ\x11;\u00C7\u00C6X\u00D2H\u00AC(\u00E3n\u00B2@\u0092\u00E1\u009F\u00CBU\u00EC\u00CC\u00CE\u00E5\u0092K\u00EE\u00CB\u00EE\u00B7\u00DF-\u00C0\u00C66\x16\u00B4\u00D82\u008B\u009D\x12\x14qH\u00F1\u00B4\x1E+@M)Z\x04PvZ\u0097\u008E3\u00E8{N\u00D7%\u00B8V\x0B\u00E2A8\x01# \u00F7\u00FB\u00DF2\u00BE\x1D_x\u00E5\u00AE\b\u00CE\x13\x1A\u00C0\u00F6\u008EP\x0B\u00E2\u00C70\u00A0g\u008E\u00E7\x1FH\x07\u00DB\u0092\u00C2\u0089\u00AD%\u00D6\u00DE\u00C0\u00F3Y\x03\u008E2\u0082A\u0098\u00EE=\u00D5\u00D5\u00C1\x04\u00D5q WX\x1D\u00A7\u0091\u0082\u00C0\u00CD\u00D2\u00BC\x19\u00B9\u008DN\x7Fn\u00E2\u00C66?o\u00E0p\u0087sS*\b\u00DE\u00B8\u008C\u00AE\u00CFx\u00A7\u0089^\u00E5\u00EB\x1C\u0082\u00C8\u00CB&\u00A6\u0098\x03\u0080,\u008B\u00DE\u00A6t\u00D05\x02\u00D7dG\u0082>\u00D8\u00E7\u00A9\u00C5\u00DEAO2\u00B8I\x00+\u00E8-Z\u008BQ\u00B1\u00A4p\x02\u0081d9\u00F7\u00D6\x14\u009E\u00DC\u00A2\u00A7G7\u008Fq\u00F9\x01b\u00FB\u00C4,\u00F5\u00CC\u00BC2)'\u00B9Fw\u009CN1\u00A8\u00A2\u00F54I\u00B9\u0088N\u00AC\u00FC\u00E1+\u00B8)\u00A8@2\x15b\u0094\x1B ]\t\b\u00B6?T\u00CC\u00E0\x1Do\u009E[\u0096\u00AC\u00B15R\" \u00B1\u00D7\u0085\u00CC\u00A3\x06\u00C9\u00B4'\u00E3\u00AF#\x01\u00B5\u00B9\u008CkS\u00B8E\u00D1\u00D2\u00F0\u0099\u00B1\x16\u0088\x11\x10\u00AFTu\u009F\u00B0\u0085mXeC\x1B\u0092\u009A\u00C8\x7F\u00B26\u00880Yq8g@\u008B\u00A6\u00E3\u0090\"\x15\u0097X45\u008E\u00C4!:\u00A9\u00A81c\u00AD\u00CD\u00CA\x0BR#\u00C1\u00D1x\"\u00E1\u00C2\u00BFk\u0086\u00B4%\u0090\u009EUEm\u00E1\x13\u0096\x0F6PR\x1DS@\x10\x17\u00BA>\"V\u00FDQQ\u00A5\u00A4m\u00E7\u00AD<\u00EEA=\x05\u00CD\u00AA\x04 \u00DCM\u00C3\u00CDp\u00C9=q#S\u00CC\u00B0i\u00A0Mh\u0086#\u0096\u00ED\u00F0yb\u00C2\u00D7\u008B\x15h\u0086\u00DF\u00E9\u0088q[\x01i\u008D\u00EE|\x1B\u00FC^\u008C\u009Aa:G\u00A8C\u00F7\u00FA\r\u00F5\u00C6\u00A5*`c\x1B[\u00D1\u00FE\x05\x18\x00C.\u0097{\u00ADV\u00AB~*\t\x01\u00A5`\u00C5b\u0091\u00BC\u00CE\u00E7\beevT\x124/TUm\u00A4R)\u00F3\u00BE\u00DB\u00ED2]?h\x07jT+8\u00DE\u00FF\u00C1\u00DA\u0089]\x02J\u0093\u0080K\u00EFI\\u\u00FA,H\u00B8\u0084\u0090\u00F8@]$\u00F1\x0E\u00EC\u008A7\u00F2\u0097$\u00DC\"IP\u00FDA\u0084z\u00E1\u00DCR\bW\u0095\u009FgI\u0091\u00B9\u00B7\u00BC\u00F0\u008F\x1F_\x1D_\u00CC\x14\u008DOS\u00C232\u00D3\u00FE\u00EDV\u00FE](\x18`j:\u009DVI\u00BE\u00BD^\u008F\u009A\u00F7\x02D\u00F2R\u00CB\u0081C\u00CF\u00BB!V(\x14\u00B6\u00BF:Y}\x17\u00F8\u00F7\u008A5\u00C0,\x04\x02\x01&\u0095\x04&\u00E6\u00BB\u00E3\u00E0r\u00B9d\u008B\u00C5b&\u00BB'\u00F2\u00CDfS\u0089D\"fO\u00E0LJ\u00BBkR\u00AA:l\u00E7\u0093\x1F\u009F3N8\u00E1O\u00F1&\u00C0\x00\u00E6:\u00F1%\u00AC+\u00E1\u0098\x00\x00\x00\x00IEND\u00AEB`\u0082", + orthoNormal: "\u0089PNG\r\n\x1A\n\x00\x00\x00\rIHDR\x00\x00\x00!\x00\x00\x00$\b\x06\x00\x00\x00\x07)S\u00DC\x00\x00\x00\tpHYs\x00\x00\x10\u009B\x00\x00\x10\u009B\x01t\u0089\u009CK\x00\x00\x02\u00AEIDATX\u0085\u00ED\u0097_HSQ\x1C\u00C7?\u00B7?lT\u008CY\u009A\t\u0091\u00B9^4\x04\u0087E\x1A\x14\u00CC\u0097\u00E8\x1F\x14\x04\u00BD\u00F8\u00E0 \u00B0\u0082J\t_/\u0099#\u00E8)*\u0082,\u00C8\u00F4\u00C1\u00A7\x10\f\u00B2\u00A4\u0097\u0084z\u00A8\u0088\u00B5Q\u00E0C`3\u00A4U&MM\u009B\u0096\u009D8\u00D7\u00DDy\u00B6\u00DD9k\x0F\u00F6p\u00BFp\u00E1\u009C\u00DF\u00FD\u009D\u00EF\u00F9\u00EC\u00FC\u00BD\u00D3\u0084\x10,\u00B7V,;\u0081\r\u00A1\u00C8\u00860eC\u0098\u00B2!L\u00FD\x17\x10\u00AB,\u00A3\x01m+ \u009F\x18\u00BA\b-\u00EA\x10\u00D0\u00DC\u00807Q\x0B\u00A1\u008BX\u008E|\u0099+\u00DBD\u00D0ED\u00862\u00EF\u008E\u009B\x15\u00ED8\x0B\x1A\u00F0\u00ECs\x12}\u00F5\u0093\u0089\u0091\u00974\u0086\u00F6X\x1A\u00DE\u00A9\u00D9Kl\u00E8!\u0095\u00F5\u00EB\u008C\u00FA\u00DB\u00EE\u00EF\u00B8=\x079\u00F1\u00E2\u00A9e\u00FEm\u00EF3\\\u009BwQ\u00B2s5C\u008F\u00E3\u00C4\u00BFuqz\u00F0\x14\x12\"\u00F9\u00B4\u00E1\x15\x1D\u00BB\x7F\bU\u00FDMB\u00B4W\u00B6\u00A4\u00E5\u00B9E\x1B~q\u00BDl\\D_/$\u00CB\u00B2\u008C\u00C9w2Gm#=\u00A4\u0097*\u00D9W\x1B\u00DE\u00D4\u00E9(\u00A9\u00AE\u00A7\u00BA\u00D1\u0099\x12+?\n\u00EF\x1E\u00B4\x10\u00D0\x0E\x03\u00CE\u00C44\x15\x1B\u00EF\x1C.\u00D8\u00E4]\u00C8\u0095e\u0087\u00CB\x05\u00DC5\u009E\u0080\u00F6\u00D9\x18v\u0088S\u00B0\u00AD\u00DC\u00F0R\u00B5\u00FD\u00B8\u0093\u00B9\u0099\u00FA\u00D4\u0085\x19\r\u00F6\u00F1)m\t\u00C4\"\u00E0t\u00F7\x03\u00BD@M\x12@jb\x04\u00E2\u00CA\x12\u0090\u00E5\u00C9\u008Fj\u00EB\u00E2D\u009B^\u00C3#\x16\u00C9\u00F4\u009E\x1E\x0Be\u00AE\u0089k[F\u00A9=_H\u0095\x1F\u0086\x07\u00A0\u00EF\u00E44S_\x1E\x01\u00C7\u00D2fx\x18\u00B7g\u008C\u00A2\u008A*\u00F6\u00DFXiD\u00FA\u00CF\u00CC1:\x18&6\u00B4\x01(M\u00CB\u00EFa\u00ED\u00C6\x03\x1C\u00BA\u00B5\u0086R\x1F\u0084;\u00E1\u00F9\u0095\u00AF4}(\u00CA\u0084\u0090\u00AB\u00BDd\u00C7Uf\u00C6}8\\o\u0088\x06g\u00D2\x00\u0086\u0081Vt\u00D1i\u00D4:j\x1B\u0099\u009D\u00B2A(g1K\u00DB\u008EK\u0093\u00EA\u0095\u00EC\u00C3\u00FA*W\u00D7D\u00AE\u00AB\u00FCo$\u00BD\x02Z]z\x0B\u00FBo\u00A0)\x1B\u00C2\u0094\ra\u00CA\u00860\u00B5\u00FC\x10\u00C0\x1F\u00C1c-8\u00DA\x1D\u00C2\u00CF\x00\x00\x00\x00IEND\u00AEB`\u0082", + orthoDisabled: "\u0089PNG\r\n\x1A\n\x00\x00\x00\rIHDR\x00\x00\x00!\x00\x00\x00$\b\x06\x00\x00\x00\x07)S\u00DC\x00\x00\x00\tpHYs\x00\x00\x10\u009B\x00\x00\x10\u009B\x01t\u0089\u009CK\x00\x00\x03\x00IDATX\u0085\u00ED\u00971L\x13Q\x18\u00C7\u00FFEI^\x1As\x11SJ\x17(\u0096E\u0098:\x10\x1B\x13\u009B\u00C0f\u008CD\x12\x13\x16b`\u00F2u\u00D0\u0088\t\u00860\u0090\u00B6!\u00D2\x12\x1Dt\u00EB\u009B\u00944\x0E`Lp\u00D0\u00B8iPbp*\x18`\u00C1J\x0F\x16\u00C9\x11Z#w\u00B5\"\u0098g\u00EE.\u00AFpW\u00D0\x0E8\u00DC?\u00B9\u00E4\u00DD\u00D7\u00F7\u00FE\u00DF\u00EF\u00BE\u00F7\u00DDk\u00EB\u00DA\u00DB\u00DB\u00C3q\u00AB\u00E6\u00D8\t\x1C\bA\x0E\u0084!\x07\u00C2\u0090\x03a\u00E8\u00BF\u00808i\x15\u00A4\u00946\x03\u00E0W\u009E1\u0096\u00A9d@)=\r \u00A8\u00DFf\x18c\u00F9C\u00E6\u00F3\u00B9|\u00CD*cl\u0095\u00C7\x0E|wD\u00A3\u00D1\u0094\u00DB\u00ED\u00EEkkk#\u00B9\\\u00EE\u00E7\u00D6\u00D6\u00D6\u00C7\u0091\u0091\u0091\u008BV\u0086\u0089D\"\u00AC(\u00CA\u00ABP(t\u008A\u00DF\u00CF\u00CD\u00CD}\u00F7x<\u0097\u0087\u0087\u0087\u00DFY\u00CD\x1F\x1D\x1D}_WWw\u00DE\u00EF\u00F7\u00D7.--\x15UU\u009D\u0088\u00C7\u00E3\u00912\bN\x19\b\x04>\f\r\r\x11#655\u0085\u00E5\u00E5\u00E5\u00BB\u00D1h\u00F4\u00C1\u00BE\u00A7\u00EF\u00F6x<\u008F\"\u0091\u0088\u00D4\u00D8\u00D8\u00F8'\u00BE\u00B6\u00B6\u0086T*\u00F5MQ\u0094\u00DB\x00\u00A6\u00C5\u00AA\u00C4\u00E3\u00F1\u00C1\u00D6\u00D6\u00D6\u00FB===f\u00BE\u00F1\u00F1\u00F1b6\u009B\u00BDP\u00B6\x1DMMM\u00BD\u00E1p\u0098\u0088\u00B1`0\u0088\u0085\u0085\u0085AJ\u00E9\x15\x00D\u00DF\u00A6\x06\u00FE\x19!\x04\x06\x00\x17\x1F\x13B$\x00\u008F\u00F9E)\u00FD\u00CA\u00CB\x0E\u00A0X__\x7F\u008E{\u0089joo';;;\u00BDe\u008D)\u00CB\u00F2\u00CB\u00F5\u00F5\u00F5\u00B2\u0089\u008A\u00A2\u00C0\u00EDv\u00BF\u00E6O\x06 d\x00p\u00E5\u00F3y\u00A8\u00AAj\u00CE\u00E5\u00E3B\u00A1 .o\u00D0\u00D7Ls\x0F\u00EE%jss\x13\u00DB\u00DB\u00DB\u0099\x13\u00B1X\u00CC\fwuu\u00AD\u00A6\u00D3\u00E9\u009B.\u0097\u00CB\u00ED\u00F3\u00F9\u00B0\u00B8\u00B8\u0088\u00C9\u00C9IuccC\x06pg\u00DF\x16\u00E7$I\u00CA\u00AE\u00AC\u00ACx[ZZj4MC:\u009D\u00FE\u00A5iZFU\u00D5\u0092\u00DE|\u0086.\x15\n\u0085\u00CF\u00D9l\u00B6\u00D9\u00EB\u00F5\u00D6J\u0092\u0084\u0099\u0099\x19\u00CC\u00CE\u00CE*\u0089D\u00E2\u00FA\u0081\u00C6\u00E4\u00FB\u00ED\u00F7\u00FB\x1Fj\u009A\u00D6A\b\u00F9$\u00CB\u00F2\x0F\x00\u00D7\u00C4\u00E4\x00b\u008C\u00B1'\u00FC&\u0099L\u00DE(\x16\u008B\u00B7\u00F8\u00B8T*%\u00C7\u00C6\u00C6\u009E\u00EA>\u00FD|\x1E\x00\u00BF\u00B0\u00F6\u00B9\u00CF\u00E7;\u00B3\u00BB\u00BB\x1B \u0084<\u0093e\u00F9\x1E\u00EF\u009B\u008A\u00BF\u00AC(\u00A5\u00DC$*\u0084^\x00\u00E8?\u00EC5\x14\x1F\b\x00\u0087\u00BD*\u0084\u00E3\u008C\u00B1\u00988\u00CF\x16B?+\u00BE\b\u00A1\t\u00C6X\u00FFQ\u0092[xq\u0090>!t\u00D68#p\u00C8\u0089)\u00D2\u00F2-\x18\u00F8\x17\x00]\x03\u00BA\u0087\u0095\u00B7u%,\u00AA\u00D0\u00C9\x18{[\x05\x04\u00F7\u00EC\x00\u00F0F\b\u0099\u00D5\u00B0\u00ABD\u00B70\u009E\u00AF\x16\u0080K\u00F7\u0098\u00B7\u00CAa\x07\u00D1!\u008C\u00A7\u00AB\x05\u00B0\u00F12s\u00D8A\u0088\u00EFx\u00D5U\u00B0\u00F12s\u00D8A\u0088\u00E7\u00EB\u0091^\u00C7#J\u00F42sT\u00EA\u0089N\u00BD!+~\u0095\u00FF\u008Dt\u00AFN\u00FD2{\u00C2\u00F9\x1Bh\u00C8\u00810\u00E4@\x18r \f\x1D?\x04\u0080\u00DF\u00D6\x06/t\u00D4\x0BO\u00DA\x00\x00\x00\x00IEND\u00AEB`\u0082", + flushNormal: "\u0089PNG\r\n\x1A\n\x00\x00\x00\rIHDR\x00\x00\x00!\x00\x00\x00$\b\x06\x00\x00\x00\x07)S\u00DC\x00\x00\x00\tpHYs\x00\x00\x10\u009B\x00\x00\x10\u009B\x01t\u0089\u009CK\x00\x00\x01\u008FIDATX\u0085\u00ED\u0097O(DA\x1C\u0080\u00BF\u00DD\u00A5$\u00B2\"R\u008Ap\u00E0\u00A0=qS{P('\u00E5\u00BC+G\u00C2a\u0085\u00C3+\u00DA\u0083\u00DC6))\u00EA\u00DD\u00DC\u00B4\u00C7=#\u00B5\u00EDe\u00DD(j\u00DDV)\u00C4\u00C1\u00E6\u00CF\u00D3zf\u009B5\u00FB\u00C7\u00C6\u00EE^\u00E6;\u00CD\u00FB\u00CD\u00BCy\u00DF\u00F4\u00FB\u00BD\u0099\u00C6aY\x16\u00D5\u00C6Yu\x03-!\u00A1%\x04ZB\u00A0%\x04ZBP\u00A3DJ!\u00E8p\u00D3\u00DA\x7F\u00C4\u00C7\u00FB\u00D0\u00D7[NW\u008C\u00BB\u008B)\f\u00EB!\u00E7,{\u0083\x01ROk\u00D4\u00B78yN\u00A6h\u00EC\u009Cf6z\u0092\u00FF\x00\x0B:\u00BC\u0080W\u0089\u00CB4\u00F7\u00F8\x181\u00BA\u00F1\u00F8\u00ED\u00E0\u00B9\t\u00A7\u009B1\u00E6.\u0087\u0095\u00B1\u00BB\x03\u00938k\u00C3\u00F8\u008E]\u00D4\u00B9!\x19\u0087\u00C3\u0089\x17\u009E\u0093\x1D\u0085$B\u00C0\u00A2\x12\u00CF\u0092\u00E8\u0085\u00F9\u00AB\u00EC\u00D8N\x1F\u00DC_\u00DF\x02&\x10\u00C9\u00C4\u00DB\x06W\x19\u00DF\x1E\u00A3KZW4\x04\u00F1\u0083\u00E5r\u00D5D;\u00B0\x02\u00A4\x17\u00D2\u00A0\u00F4\u00FE\u00A0PM\u0084\u0081\u00DC\u00B9\u00CD`\u00F987\u00B3\u00D3\u00F1\u00F1\u00FA&\u00CD\u00EB\x01\x02\x18\u0096\u0097\u00DD\u0081\x06\"\x0B\u00A3Y\u00E98\u00DBJ\u00A7c?\x7F:~C\u00EE\u00C2\u009C\x016\x00\u009F4\u00C3\x06\u0086\u00B5^za\u00FE\u0095\u00A0\u00C3\u0094D\x1E\u0081\u00EE|\x7FM9\u00F7\u0089\u00A5\u00EF\u008F\u00A7i\x02\u00FC\u00CA\u0088\u00B2K\u00D8\u00AB\x0EI\u0091*H\u00D8\u0098R\u00DB\u00A3\u00F4VD\u00C2\u00B0\x12\u00C0M\u00E6\u00D9\u00DE\x00\x15*qv$\u00A4\u00B6[\u00E9-\u00B2O\u00FC\x17\u00E1b\x12\u00FA\u00F2#\u00D0\x12\x02-!\u00D0\x12\x02-!\u00A8\u00BE\x04\u00F0\t3\u00E3|\u00ABJ\u0092\x0EH\x00\x00\x00\x00IEND\u00AEB`\u0082", + flushDisabled: "\u0089PNG\r\n\x1A\n\x00\x00\x00\rIHDR\x00\x00\x00!\x00\x00\x00$\b\x06\x00\x00\x00\x07)S\u00DC\x00\x00\x00\tpHYs\x00\x00\x10\u009B\x00\x00\x10\u009B\x01t\u0089\u009CK\x00\x00\x01\u009BIDATX\u0085\u00ED\u00971k\u00C2@\x18\u0086\u00DF&\x1D\u008A\n\u00CD\"\u00B5\u0088\u00E0?p\u00B2\u0083\u0093C\x07\u0091\x0E\u00A5Pp\u00B3\u0085\u00C2-\u0085v\b\u0094Li\u00FC\x05\u00E2v\u00D0\u00C1\u00D1\u00A98\u00C9\u00ED\u0095,\u00FE\t\u008BKF\u009B\u00A9\u0081\u00AA%\u0092\u0083\u00ABg\u00B4\u00D2\u00AA\u00CB=\u00D3\u00E5\u00BE\u00CB\u00E5\u00C9}_\u00EE\u00C8\u00C1l6\u00C3\u00BE\u00D1\u00F6n\u00A0$\x04\u0094\x04GIp\u0094\x04GIp\x0E\u00A5\u009E\r \u0084\x18\u0099L\u00E6u:\u009D\x16\u00C3\u00BB4M\x1Bx\u009EwE)\x1D/\u009B\u00C5q\x1C3\b\x02+\u0099Lj\u00BE\u00EF\x07\u0086a\\[\u0096\u00F5\x16{\u0080\x11B\u00CA\x00\u00CAR@ \u009DN\u00D7\u00AB\u00D5j\u00BET*\u00CD;]\u00D7\x05cl\u00D0h4\u00CE\x16\u00C7\u00DA\u00B6}\u00A1\u00EBz\u00D74M=\u0091H`4\x1A\u00A1\u00D5j}\u00FA\u00BE\x7F\u00BAj%.\x01\u00DC\u0085\u0098\u009D\u00DD'\u00A4y\x1F\u00840\u0093\u00DD\u00C9\u008F0\u00C9#\u0091\u0088\u00B0\u00EA4V.\b\u0088\\\x02\u00C2% \\\x02\u00C2\u00A5\u00F9/SN\u00A2.\u009D\u00ADk\u0090\x0ED\x13&\u00CF\u0087\fdl\u00BE_\x7F\u00B6\u00BD\x1E\tm9\u00DF\u00F8\u0092\u00D7[I\u00A3\u00CFZk\u00DF8\u00DB\x1Fq\u00D5;\u0095\u00F1P\n\u00D1Z\u00FB\u00C6\x19\u00FE;1\u00FB\u00DEf\u00AD]\u00ECi\u00AD}c\u00FC\x10\u00BA\x0B\u00EF\u008F{\u00DC\u009F\x15\u00FBZ\x7F\u00BC\u00EC\u00A7\u00AF\x1BR\u00FF(\u009F\u00BF\u00C1\x1D\u00D0b}\x13d\x06\u00BD#x\u00B8\u0084F\x13>\u00DF\u00F4\u00AA)\u00B0[\u00B6\u00A4\u00F5\x10y\u00C0o\u008E\u0081'`\x07\u00B8\u00C8\u00F5K!\u00D5\x11\u008B\x01}\x06r\u0093\u00BB&\x06\u0086VH\u00B5\u009D\u00B0\x004\u00F3\u00BA\u009F\u00EB\u00B4\u00D2\u00FB\u00FE\u00D8\x11;\u00C2\n\u00A8\x01\u00B1!\u00AA\x02*B\u00CA\x11u\x01\x15 \u00CB\x11\u00BE\x00#\u00A4\u00EC\u0093\x18y\x03\u0096CF\x16\u00C4A\u00F6\u00F5\u00F2\x03,\u0086L\u00B3\u00F9\u0086\x03,\u00A1+\t\u00B1\u00F7AW\u009C\x19\u00A7s\u00B3:\u00FC\x03s\t\b\u0097\u0080p\t\b\u0097\u0080H\x03\u00FC\x00l\t\u0098\u00FF\x1D\u00DA\u008E\u00B1\x00\x00\x00\x00IEND\u00AEB`\u0082", + cornerDisabled: "\u0089PNG\r\n\x1A\n\x00\x00\x00\rIHDR\x00\x00\x00!\x00\x00\x00$\b\x06\x00\x00\x00\x07)S\u00DC\x00\x00\x00\tpHYs\x00\x00\x10\u009B\x00\x00\x10\u009B\x01t\u0089\u009CK\x00\x00\x01bIDATX\u0085\u00ED\u00D7\u00B1j\u0083@\x18\x07\u00F0\x7F\u00A5Cq\u00B0\u00D2A\u00E8\u00E2h\u00A1S^@(\u00ED\x0B\u00D47H\n\u009EC\x1F\u00A1\u00CF\u0091\u00E1\x10\u00DA>Bv\u0097\u00E0\x13t\u00EA\u00E0,\x14\x14\u008Aq\u00EA\u00A4\u00E5\x13\x0F\u00CC\u0090xz\u00A5Y\u00EE\x0F\x12\u00EE\u00CB\u00F9\u00F9\u00C3|\x11\n\u0099\u008C8\x00Xq\u00CE\u00DF\x07{\u0096\x00\u00DEd!\u0093fB\x06@\u00E9\u00D7\u00ABA\u0089\u00F6o\x0F\u00CD\u00884B\x160\x07\"\u0085\u0098\n\u0098\n\x19E\u00CC\x05L\u0081\x1CE\u00A8\x02d!cwb\u00A3\n\x18\u0081ld\x10\u008F\u00FD\u00DFK\tp\x00\u00B2\u00EB\u00FB\u00A3{\u00D2\x1D;\x18c\x0B\u00C6\u00D8rl\u00DF\u0094\u0083\u00FAQ_q\u008E~\x03\x13\u00D1\b\x11\u008D\x10\u00D1\b\x11\u008D\u00E8\x02\u00E0\x17\u00C3'\x02!\u00E0\x11\u00BBV\x00\x00\x00\x00IEND\u00AEB`\u0082", + brokenNormal: "\u0089PNG\r\n\x1A\n\x00\x00\x00\rIHDR\x00\x00\x00!\x00\x00\x00$\b\x06\x00\x00\x00\x07)S\u00DC\x00\x00\x00\tpHYs\x00\x00\x10\u009B\x00\x00\x10\u009B\x01t\u0089\u009CK\x00\x00\x02IIDATX\u0085\u00EDW\u00BFO\x14A\x18}sR\x001\u00E1\x14-\u00AC8b\x026\u00863\u00C6J\x12\u008E\u00F8\x07@hi\u00AE\u00B1UCE\u00B3\u00F1p\x1A+sj\u00AC,\u00BC\u0086\x16\u00AE\u00B23z\u0089\u009D1@GB\u00C1u\x14p\b\u00CD\x1E\u0089rc\u00BE\u0099\u009B\u00BDqng\x7F\x1C\u00C5Y\u00ECK6\u0099\u00F9\u00BEo\u00DE\u00BE\u00F9\u00E6\u00ED\u00DE\x1E\x13B`\u00D8\u00C8\r]A&\u00C2@&B\u00E3\u00BF\x101\x12\u0099\u00E5\u00AC\u0080;\x0F+r|\u00F4\u00B3\x02O4\x07\u00BAK\x1C\x0F\u00BD'B\u00AF\u00B7S\u00AB\u00E2\u00C3\u00AC/\u00F6\u00B7\u0085\u00BChL1W\u00FD\x15x\u00A2\x16\u00B7D\u00FB\u0097\b@c\u008A\u00A5\x17\x11\u00CB\u00E3\u00F6\u00C4\u00F8d\x0E\u00A3\u00F9\u00DE\u009C\u00C6\x14K\u008B\x04cr\u00E6\x06\u0084\u00B8\u00DF\u009D\x1F\u00E0\u00F4\u00C0\x07\u00F0\u00D8\u00AA#\u008F\u0094\u00E1\u0089\u00DD\u00C1DpF\u00AE\u00FB\x14B\u00FA\"0^\u00FF\x1A2n\u00CD\x12}\x0E`9lM\u00DC\u00D3\u00B1\f`\u00DB\u008An\u00C0\x13\u00B1-\u0096\u00C7\u00A7\x1E\u00D3\u00E7V\u00E6\u0081\u00DD\x11\u00B7\be**\u009E0vRr\u00B54f#5\u008B\u00A7h>\u00A6Q\u00C6\u00B4\x17\u00A6\x17@\u00F0D]\u00AEU\x1C\u00E8rV\u00CD\u0092\u00F0N(#\u00EE\x18\u0091E\u00E7\u00F9'E\u00FF\u00D1N\u00EBn\u00B8:Q6\u00C6\u008D+\x0B@\u00D0\u0091F\u00D8=\\\"\u008A\u00C6\u00B8\u00EA\u00A8\x19\x04&W\u00F0C\u00E8\x12a\u00BE\u00E9\u00D2\u00FB\u00C0\r\u0093+\u00B8\u0087\u00EB\u00F3\u00AEw\x1C\u0083~\u00D2\u0085\u0081\u00B88[\u00B43\u00D9\u00DF@\u008DL\u0084F&B#\x13\u00A11|\x11\x00\u00FE\x02\u00BBf\u00F1\u00FER\\>\u008B\x00\x00\x00\x00IEND\u00AEB`\u0082", + brokenDisabled: "\u0089PNG\r\n\x1A\n\x00\x00\x00\rIHDR\x00\x00\x00!\x00\x00\x00$\b\x06\x00\x00\x00\x07)S\u00DC\x00\x00\x00\tpHYs\x00\x00\x10\u009B\x00\x00\x10\u009B\x01t\u0089\u009CK\x00\x00\x02MIDATX\u0085\u00EDW\u00BF\u008F\x12A\x18}\x12\x1A\x17\u0089g(\u00A0\u00E3\u00FC\x03\u008CX\u00D8\u00A0\u0089\u00D0\u0093x\u00A1\u00B5\u00A1\u0091\u00AF\u00F4b\x074\u00D8P\x1A\u00DA\u0089\u0085\u00D7\u00D8\u00A2&\u00C4V/\u00B9\u00D0X\u00DCY[(\x1D!!\u00D1\u00C0\u00AE\r\u00B0\u00E6#3\u00EBd\u00B3\u00B3?\u00B8\x02\u008B}\u00C9&\u00DF\u00CC|\u00F3\u00E6\u00ED7of\u00E1\u0086\u00EB\u00BA842\x07W\u0090\u008A\u00D0\u0090\u008AP\u00F8/Dd\u00C3\x06\u0089\u00E8\u00B8\\.\u00F79\u009EN\u00A7}!\u00C4\u00CF}\x16\u0089\u00E21\u00DE\x13\u00DDn\u00F7Y6\u009B}\u00D3l6or{4\x1A\u00FDY\u00AF\u00D7\u00CF\x07\u0083\u00C1\u00BB$\x02b\u00F1\u00B0\u0088\u00A0\u00A7\u00D3\u00E9,l\u00DBv\x158\u00E6>S\u00FEux\u008C\u009E\u00C8\u00E5r\x19\u00CB\u00B2\u00BC6\u00C7\u00DC\u0097\u00A4\nqy\u008C\u00A4\u00B6mo\x1D\u00C7\u00F1\u00DA\x1C\u00AFV\u00AB[DT\u008B+\u0080sy\u008E\u009F\u0087\u00B9\u00F5\u00BCD\u009Ep\x1C\u00E7\u00F5r\u00B9|,S\u00D8hW\u00A5Ri\u00B4\u00DDn\x1F\u00EE\u00DE(\u0093\u00F9:\u009B\u00CD\u009A\x00*r\x1C\u00F9|\u00FE\u00C2\u00B2\u00AC\u0097a\u009E\b\u00FD\u0080\u0099\\-\u00AB\u00D1/\x14\n\u00F7\x1B\u008D\u00C6Q\u00B5Z\u00DD\u00E5O&\x13\u008C\u00C7\u00E3_\u008B\u00C5\u00E2\x1B\u008F\x0B!\u00BE\u0084\u00F1xHj4\u00F5\u00B4\u00DB\u00EDZ\u00AF\u00D7\u00DB\u00B8>p\x1F\u008F%\u00E1\n\u00BD'\f\u00D5\u00E1R\x0F\x01<1\u00A4\u00B0\u00CF>\x13\u00D1G\x00\u00A7q\u00EE\u0096\u00D8n'\u00A2#\"\u00E2\u00C5/\u0095\u0080\u00CDf\u00B3\u00DB\x02\x05\u008E\u00B9O\u00E2)\u0080\x1FD\u00D4\u008F\u00E2\u008E\u00F5\u00A3F\u00BE\u00FD\x07\x00e\u00DF\u00D0\u00A7b\u00B1x\u00C7u\u00DD{\u00B2\u00FD}>\u009F\u00F3Qx\u00E4\u00CBc\u008F\u00B4\u0084\x10W{\u0089 \u00A2\x16\u0080\u00B7\x01\u00A4\u00A7\u00CAx\x01s\u00D8\u00B8g>\u00D1\u00BF\x01\u009C\x04\u00CD\u0089:\x1D'\x00\u00DE\u00FB\u00BA_\t!\"K\u00CC\u00DB'\u008F\u00E9\x0B\u00DF\u00D0\x03\x7FE\u008C\"\u00F8X\u00F1=\x00\u00E0\u00B6\u00F6&5SI#^\u00E4\u00CC\u00C7S\u00D1\r\x1BfL\u00FF\u00C4\u00C4\x02\x18B\b\u00F6RMr@r\x0E\u00F5\u009C\u00C0JH#^j]u\u00D3\u00FE\u00C7E\u00C0\u00D6\u00DEU\u00D50U\u00A2\u00A5\u00C5\u00E7\u00D7\x15\u0080\x7F\x159\x0FZ\u00C3$\u00A2\u00A2\u00C5CC\u00CE>\u00D0\u00B9\u00BC\x0F\u00A1I\u00C4\u00B1\x16'\u00F6A\bt.o\u008D\u00B0\u00ED\u00A8K/\u00EC\u00F5\u0093.\b\u0092\u00AB.\x1Fo;\u00D2\u00BF\u0081\n\u00A9\b\u0085T\u0084B*B\u00E1\u00F0\"\x00\u00FC\x05\u00C3y\u00DE9\u0083\u00DD$\u00D7\x00\x00\x00\x00IEND\u00AEB`\u0082", + flatNormal: "\u0089PNG\r\n\x1A\n\x00\x00\x00\rIHDR\x00\x00\x00!\x00\x00\x00$\b\x06\x00\x00\x00\x07)S\u00DC\x00\x00\x00\tpHYs\x00\x00\x10\u009B\x00\x00\x10\u009B\x01t\u0089\u009CK\x00\x00\x00\u00D2IDATX\u0085\u00ED\u00D61\n\u0082`\x18\u00C6\u00F1\u00E7\u00B3\x0EP\u00D0\x01\u00A4\u00A9\u00AD\u00A91\u00F0\f]\u00C0.\"\rv\x10\u00BB@g\x10\x1C\u009B\u00DC\u009A\u00C2\x03\x04u\u0081zC\u00E3\x15\u00E5C\u00D4\u00A1tx~\u0093\u00BC\u00A8\u00FC\u00F5\u00FB\x10\u008D\u0088`h\u00CE\u00E0\x05\u008C\u00A8`\u0084b\u0084b\u0084b\u0084b\u0084\x1AE\u00C4\u00D4\u009A\u00F4\x11\u009A\x19\x16\u00AB3\u00DE\u00AFMq\u00953\u00B9\u00E0~\u00DD!\u0090g\u009F\u00DB4\u00FFO\u0084\u00C6\x03\u00E0Y\u00F3\u00AA\u00F9\u00D2\u00C76p\u00B1\u00DE\x7F\u0087i\x04$a\u0086\u00C7\u00EDd\u009D[\x17#\u0090\u00B8\u00CB\u009B\u00C8\x03\x0E\u00D6\u00B4\u00FE\f(\x03r\u00F9qrt\u00DB\u00AF+\u0094\x11\u00A3\u00DF\x13\u00B15\u00B1\u0088\u008F4\u00AA/\x07$\x03\u00D0\u00BE\x1C\x15\u00CD{\u00A2\u008B\u009Fo\u00CC?\u00E2\u00C7J1B1B1B1B1B1\u00A2\x00\u00E0\x03\u009B\u00C37\u00B2\x01}r6\x00\x00\x00\x00IEND\u00AEB`\u0082", + flatDisabled: "\u0089PNG\r\n\x1A\n\x00\x00\x00\rIHDR\x00\x00\x00!\x00\x00\x00$\b\x06\x00\x00\x00\x07)S\u00DC\x00\x00\x00\tpHYs\x00\x00\x10\u009B\x00\x00\x10\u009B\x01t\u0089\u009CK\x00\x00\x00\u00D3IDATX\u0085\u00ED\u00D6/\x0E\u00830\x1C\u0086\u00E1o\u00CD\x0E0C\u0082\u00E4\x123(t\u00E5.\u0080\u00EC1v\u008E\u00CA]`\u00B2\u00BA\u00AAf\u0097@\u0092`v\x02X \u00FB%\u00B0\u0086\f\u00C4\x06\u00E2{T)\x7F\u00F2\u00866\u0084C\u00D7u\u00D8\u009A\u00DA\u00BC\u0080\x11#\u008C\x10\u008C\x10\u008C\x10\u008C\x10\u008C\x10\u00BB\u00888F3+\x18cNi\u009A\u00DE\u00DB\u00B6=\u00F7w)\u00A5\x1Eu]_\u00AC\u00B5\u00CF5\u00CF\u0099\u00FD\u009F0\u00C6\x14\x00\u008A\u00E8\u00C4H\u0092$\u00A5\u00D6:\u00CB\u00F3|\u0098\f!\u00C09W5Ms\u008B.\u009E\u00F2\u00D6Z\u00BF\u00E4M\u00F4\x01\u00D7h\u00F6\u0083\x04\u00E0=v\u00CEeK\u00EE\u00EBCd\u00B0\u00FB=\u00E1\u00A3\u0099X\x19B\u0098,\x07\u0080\n\u00C0\u00D7\u00E5\x18\x1F\u00CC\u00EE\u0089%~\u00BE1\u00FF\u0089\x1F+\u00C1\b\u00C1\b\u00C1\b\u00C1\b\u00C1\b\u00C1\u0088\x01\u0080\x17\u0086\tB\u00AD7\u00CDR\x16\x00\x00\x00\x00IEND\u00AEB`\u0082" + }; + + if (CFG.aiVers < 16) { + alert('Error\nSorry, script only works in Illustrator CS6 and later'); return; } - if (selection.length == 0 || selection.typename == 'TextRange') { - alert('Please select at least 1 object and try again.'); + if (!documents.length) { + alert('Error\nOpen a document and try again'); return; } - var selPaths = [], - btnsState = []; + if (!selection.length || selection.typename == 'TextRange') { + alert('Error\nPlease select at least one object and try again'); + return; + } + + var selPaths = []; getPaths(selection, selPaths); // START DIALOG - var dialog = new Window('dialog', SCRIPT_NAME + ' ' + SCRIPT_VERSION); - dialog.orientation = 'column'; + var dialog = new Window('dialog', SCRIPT.name + ' ' + SCRIPT.version); + dialog.orientation = 'column'; dialog.alignChildren = ['fill','center']; - dialog.opacity = .95; // Range 0-1 - - var icoBezier = ScriptUI.newImage(BIN_BEZIER_N, BIN_BEZIER_D, BIN_BEZIER_N, BIN_BEZIER_N), - icoFlush = ScriptUI.newImage(BIN_FLUSH_N, BIN_FLUSH_D, BIN_FLUSH_N, BIN_FLUSH_N), - icoCorner = ScriptUI.newImage(BIN_CORNER_N, BIN_CORNER_D, BIN_CORNER_N, BIN_CORNER_N), - icoBroken = ScriptUI.newImage(BIN_BROKEN_N, BIN_BROKEN_D, BIN_BROKEN_N, BIN_BROKEN_N), - icoFlat = ScriptUI.newImage(BIN_FLAT_N, BIN_FLAT_D, BIN_FLAT_N, BIN_FLAT_N); - - var btns = dialog.add('group'); - btns.orientation = 'column'; - btns.alignChildren = ['fill','center']; - - var bezierBtn = btns.add('iconbutton', undefined, icoBezier, {style:'button', toggle:true}); - bezierBtn.text = 'Bezier '; + dialog.opacity = CFG.uiOpacity; + + var icoBezier = ScriptUI.newImage(ICNS.bezierNormal, ICNS.bezierDisabled, ICNS.bezierNormal, ICNS.bezierNormal), + icoOrtho = ScriptUI.newImage(ICNS.orthoNormal, ICNS.orthoDisabled, ICNS.orthoNormal, ICNS.orthoNormal), + icoFlush = ScriptUI.newImage(ICNS.flushNormal, ICNS.flushDisabled, ICNS.flushNormal, ICNS.flushNormal), + icoCorner = ScriptUI.newImage(ICNS.cornerNormal, ICNS.cornerDisabled, ICNS.cornerNormal, ICNS.cornerNormal), + icoBroken = ScriptUI.newImage(ICNS.brokenNormal, ICNS.brokenDisabled, ICNS.brokenNormal, ICNS.brokenNormal), + icoFlat = ScriptUI.newImage(ICNS.flatNormal, ICNS.flatDisabled, ICNS.flatNormal, ICNS.flatNormal); + + var btns = dialog.add('group'); + btns.orientation = 'column'; + btns.alignChildren = ['fill','center']; + + var bezierBtn = btns.add('iconbutton', undefined, icoBezier, {style:'button', toggle:true}); + bezierBtn.text = 'Bezier '; bezierBtn.helpTip = 'Select Bezier (Smooth) \npoints (with handles).\nShortcut Alt + 1'; + var orthoBtn = btns.add('iconbutton', undefined, icoOrtho, {style:'button', toggle:true}); + orthoBtn.text = 'Ortho '; + orthoBtn.helpTip = 'Select Ortho (Smooth) \npoints (with handles along axis).\nShortcut Alt + 2'; + var flushBtn = btns.add('iconbutton', undefined, icoFlush, {style:'button', toggle:true}); - flushBtn.text = 'Flush '; - flushBtn.helpTip = 'Select Flush points\n(with 1 handle along the straight \nsegment). Shorcut Alt + 2'; + flushBtn.text = 'Flush '; + flushBtn.helpTip = 'Select Flush points\n(with 1 handle along the straight \nsegment). Shorcut Alt + 3'; var cornerBtn = btns.add ('iconbutton', undefined, icoCorner, {style:'button', toggle:true}); cornerBtn.text = 'Corner '; - cornerBtn.helpTip = 'Select Corner points (without\none or both handles or with\nhandles at the angle).\nShortcut Alt + 3'; + cornerBtn.helpTip = 'Select Corner points (without\none or both handles or with\nhandles at the angle).\nShortcut Alt + 4'; var brokenBtn = btns.add ('iconbutton', undefined, icoBroken, {style:'button', toggle:true}); brokenBtn.text = 'Broken '; - brokenBtn.helpTip = 'Select Broken (Pseudo-Smooth) points\n(with handles at the angle).\nShorcut Alt + 4'; + brokenBtn.helpTip = 'Select Broken (Pseudo-Smooth) points\n(with handles at the angle).\nShorcut Alt + 5'; var flatBtn = btns.add('iconbutton', undefined, icoFlat, {style:'button', toggle:true}); flatBtn.text = 'Flat '; - flatBtn.helpTip = 'Select Flat points on straight paths\n(without handles).\nShorcut Alt + 5'; + flatBtn.helpTip = 'Select Flat points on straight paths\n(without handles).\nShorcut Alt + 6'; // TOLERANCE - var tolerance = dialog.add('group'); - tolerance.orientation = 'row'; - tolerance.alignChildren = ['left','center']; + var tolerance = dialog.add('group'); + tolerance.orientation = 'row'; + tolerance.alignChildren = ['left','center']; - var tolTitle = tolerance.add('statictext', undefined, 'Angle Tolerance, \u00b0'); + var tolTitle = tolerance.add('statictext', undefined, 'Angle Tolerance, \u00b0'); var tolValue = tolerance.add('edittext', undefined, '180'); tolValue.characters = 4; tolValue.helpTip = 'Tolerance angle in degrees\nbetween handles\nfor Corner & Broken points'; - - var sPoints = dialog.add('statictext', undefined); - sPoints.text = 'Selected Points: ' + getSelectedPoints(selPaths); - sPoints.justify = 'center'; - - var copyright = dialog.add('statictext', undefined, 'www.github.com/creold'); - copyright.justify = 'center'; - copyright.enabled = false; - - // Update selection after change tolerance angle - tolValue.onChange = function() { - this.text = convertToNum(this.text, MAX_ANGLE); - if (this.text * 1 > MAX_ANGLE) this.text = MAX_ANGLE; - if (brokenBtn.value || cornerBtn.value) run(); - } - // Use Up / Down arrow keys (+ Shift) for change tolerance angle - shiftInputNumValue(tolValue); + var isShowBox = dialog.add('checkbox', undefined, 'Hide Bounding Box'); + isShowBox.value = !app.preferences.getBooleanPreference('showBoundingBox'); + isShowBox.helpTip = 'Hide Bounding Box to see\nthe selected points'; + + var selPoints = dialog.add('statictext', undefined); + selPoints.text = 'Selected Points: ' + calcSelectedPoints(selPaths); + selPoints.justify = 'center'; + + var copyright = dialog.add('statictext', undefined, 'Visit Github'); + copyright.justify = 'center'; + // Dialog shortcuts Alt key + digits tolValue.addEventListener('keydown', function(kd) { if (kd.altKey) kd.preventDefault(); }); - // Dialog shortcuts Alt key + digits dialog.addEventListener('keydown', function(kd) { if (kd.keyName === 'Enter' && (brokenBtn.value || cornerBtn.value)) { run(); } if (kd.altKey) { if (kd.keyName.match(/1/)) bezierBtn.notify(); - if (kd.keyName.match(/2/)) flushBtn.notify(); - if (kd.keyName.match(/3/)) cornerBtn.notify(); - if (kd.keyName.match(/4/)) brokenBtn.notify(); - if (kd.keyName.match(/5/)) flatBtn.notify(); + if (kd.keyName.match(/2/)) orthoBtn.notify(); + if (kd.keyName.match(/3/)) flushBtn.notify(); + if (kd.keyName.match(/4/)) cornerBtn.notify(); + if (kd.keyName.match(/5/)) brokenBtn.notify(); + if (kd.keyName.match(/6/)) flatBtn.notify(); } }); @@ -160,41 +173,76 @@ function main() { } } + // Update selection after change tolerance angle + tolValue.onChange = function() { + this.text = convertToNum(this.text, CFG.maxAngle); + if (this.text * 1 > CFG.maxAngle) this.text = CFG.maxAngle; + if (brokenBtn.value || cornerBtn.value) run(); + } + + shiftInputNumValue(tolValue, CFG.minAngle, CFG.maxAngle); + + isShowBox.onClick = function () { + app.executeMenuCommand('AI Bounding Box Toggle'); + } + + copyright.addEventListener('mousedown', function () { + openURL('https://github.com/creold/'); + }); + // Apply selection at event function run() { - app.selection = null; - btnsState = [bezierBtn.value, flushBtn.value, cornerBtn.value, brokenBtn.value, flatBtn.value]; - processPoints(btnsState, selPaths, tolValue.text * 1); - sPoints.text = 'Selected Points: ' + getSelectedPoints(selPaths); + var btnsState = []; + selection = null; + + for (var i = 0; i < btns.children.length; i++) { + btnsState.push(btns.children[i].value); + } + + processPoints(btnsState, selPaths, tolValue.text * 1, CFG.cosTolerance); + + selPoints.text = 'Selected Points: ' + calcSelectedPoints(selPaths); } - function shiftInputNumValue(item) { + /** + * Use Up / Down arrow keys (+ Shift) for change value + * @param {object} item - input text field + * @param {number} min - minimal input value + * @param {number} min - maximum input value + */ + function shiftInputNumValue(item, min, max) { item.addEventListener('keydown', function (e) { var step; ScriptUI.environment.keyboardState['shiftKey'] ? step = 10 : step = 1; + if (e.keyName == 'Down') { if (Number(this.text) >= step) { this.text = Number(this.text) - step; e.preventDefault(); } else { - this.text = MIN_ANGLE; + this.text = min; } } + if (e.keyName == 'Up') { - if (Number(this.text) <= MAX_ANGLE - step) { + if (Number(this.text) <= max - step) { this.text = Number(this.text) + step; e.preventDefault(); } else { - this.text = MAX_ANGLE; + this.text = max; } } }); } - dialog.show(); + dialog.show(); } -// Get paths from selection +/** + * Get single items from selection + * @param {object} collection - set of items + * @param {array} arr - output array + */ function getPaths(item, arr) { for (var i = 0, iLen = item.length; i < iLen; i++) { var currItem = item[i]; @@ -216,7 +264,31 @@ function getPaths(item, arr) { } catch (e) {} } } - + +/** + * Calculate the number of selected points + * @param {array} paths - array of selected paths + * @return {number} the number of selected points + */ +function calcSelectedPoints(paths) { + var count = 0; + for (var i = 0, iLen = paths.length; i < iLen; i++) { + if (paths[i].pathPoints.length > 1) { + var points = paths[i].pathPoints; + for (var j = 0, pLen = points.length; j < pLen; j++) { + if (points[j].selected == PathPointSelection.ANCHORPOINT) count++; + } + } + } + return count; +} + +/** + * Convert any input data to a number + * @param {string} str - input data + * @param {number} def - default value if the input data don't contain numbers + * @return {number} + */ function convertToNum(str, def) { // Remove unnecessary characters str = str.replace(/,/g, '.').replace(/[^\d.]/g, ''); @@ -227,7 +299,13 @@ function convertToNum(str, def) { return parseFloat(str); } -function getPointType(point, tolerance) { +/** + * Get the type of point by her anchor and handles + * @param {object} point - point on the path + * @param {number} tolerance - angle tolerance between handles + * @return {string} point type conditional name + */ +function getPointType(point, tolerance, types) { var xArr = [], yArr = []; @@ -241,36 +319,63 @@ function getPointType(point, tolerance) { } var isZeroLHandle = (xArr[0] == xArr[1]) && (yArr[0] == yArr[1]), - isZeroRHandle = (xArr[1] == xArr[2]) && (yArr[1] == yArr[2]); + isZeroRHandle = (xArr[1] == xArr[2]) && (yArr[1] == yArr[2]), + isHorizHandle = (xArr[0] == xArr[1]) && (yArr[0] != yArr[1]), + isVertHandle = (xArr[0] != xArr[1]) && (yArr[0] == yArr[1]); var handlesCos = calcAngleCos(xArr, yArr); // Convert Degrees to Radians var radians = tolerance * (Math.PI / 180); - // If cos of angle is -1, then angle is 180 degrees - if (isZeroLHandle && isZeroRHandle) return 'flat'; - if (isZeroLHandle) return 'l_zero'; - if (isZeroRHandle) return 'r_zero'; - if (point.pointType === PointType.SMOOTH && Math.round(handlesCos) == COS_180) return 'bezier'; - if (handlesCos > Math.cos(radians)) return 'corner'; - if (point.pointType === PointType.CORNER && handlesCos <= Math.cos(radians)) return 'broken'; + // If cos of angle is -1, then angle is 180 degrees + if (isZeroLHandle && isZeroRHandle) return types.flat; + if (isZeroLHandle) return types.lZero; + if (isZeroRHandle) return types.rZero; + if (point.pointType === PointType.SMOOTH && Math.round(handlesCos) == -1 && (isHorizHandle || isVertHandle)) return types.ortho; + if (point.pointType === PointType.SMOOTH && Math.round(handlesCos) == -1) return types.bezier; + if (handlesCos > Math.cos(radians)) return types.corner; + if (point.pointType === PointType.CORNER && handlesCos <= Math.cos(radians)) return types.broken; } -// Get coordinates anchor & hangles -function getCoordinates(p1, p2, p3, answer) { +/** + * Calculate Cos of angle between vectors + * @param {array} xArr - X-axis coordinates + * @param {array} yArr - Y-axis coordinates + * @return {number} the cosine of the angle between the points + */ +function calcAngleCos(xArr, yArr) { + var leftEdge = Math.sqrt(Math.pow((xArr[0] - xArr[1]), 2) + Math.pow((yArr[0] - yArr[1]), 2)), + rightEdge = Math.sqrt(Math.pow((xArr[2] - xArr[1]), 2) + Math.pow((yArr[2] - yArr[1]), 2)), + farEdge = Math.sqrt(Math.pow((xArr[0] - xArr[2]), 2) + Math.pow((yArr[0] - yArr[2]), 2)), + angleCos = (Math.pow(leftEdge, 2) + Math.pow(rightEdge, 2) - Math.pow(farEdge, 2)) / (2 * leftEdge * rightEdge); + return angleCos; +} + +/** + * Get coordinates anchor & handles + * @param {object} p1 - point to the left of the current + * @param {object} p2 - current point + * @param {object} p3 - point to the right of the current + * @param {string} answer - current point type + * @param {object} types - point type names + * @return {object} X & Y-axis coordinates + */ +function getCoordinates(p1, p2, p3, answer, types) { var xArr = [], yArr = []; - if (answer == 'flat') { + + if (answer == types.flat) { xArr.push(p1.anchor[0]); xArr.push(p2.anchor[0]); xArr.push(p3.anchor[0]); - + yArr.push(p1.anchor[1]); yArr.push(p2.anchor[1]); yArr.push(p3.anchor[1]); } - if (answer == 'l_zero') { + + if (answer == types.lZero) { xArr.push(p3.anchor[0]); xArr.push(p2.anchor[0]); xArr.push(p2.rightDirection[0]); @@ -280,7 +385,7 @@ function getCoordinates(p1, p2, p3, answer) { yArr.push(p2.rightDirection[1]); } - if (answer == 'r_zero') { + if (answer == types.rZero) { xArr.push(p2.leftDirection[0]); xArr.push(p2.anchor[0]); xArr.push(p1.anchor[0]); @@ -292,93 +397,109 @@ function getCoordinates(p1, p2, p3, answer) { return { 'x': xArr, 'y': yArr }; } -// Calculate Cos of angle between vectors -function calcAngleCos(xArr, yArr) { - var leftEdge = Math.sqrt(Math.pow((xArr[0] - xArr[1]), 2) + Math.pow((yArr[0] - yArr[1]), 2)); - var rightEdge = Math.sqrt(Math.pow((xArr[2] - xArr[1]), 2) + Math.pow((yArr[2] - yArr[1]), 2)); - var farEdge = Math.sqrt(Math.pow((xArr[0] - xArr[2]), 2) + Math.pow((yArr[0] - yArr[2]), 2)); - var angleCos = (Math.pow(leftEdge, 2) + Math.pow(rightEdge, 2) - Math.pow(farEdge, 2)) / (2 * leftEdge * rightEdge); - return angleCos; -} +/** + * Point types detection and selection + * @param {boolean} btns - button status + * @param {array} paths - array of selected paths + * @param {number} tolerance - angle tolerance + * @param {number} cosTolerance - cosine angle tolerance + */ +function processPoints(btns, paths, tolerance, cosTolerance) { + var pTypes = { + bezier: 'bezier', + ortho: 'ortho', + lZero: 'left_zero', + rZero: 'right_zero', + corner: 'corner', + broken: 'broken', + flat: 'flat' + }; -function selector(point) { - point.selected = PathPointSelection.ANCHORPOINT; -} - -function processPoints(btnsVal, paths, tolerance) { for (var i = 0, iLen = paths.length; i < iLen; i++) { if (paths[i].pathPoints.length > 1) { var points = paths[i].pathPoints; for (var j = 0, pLen = points.length; j < pLen; j++) { var currPoint = points[j], - answer = getPointType(currPoint, tolerance), + answer = getPointType(currPoint, tolerance, pTypes), pointCos = 0, pointCosRound = 0, coordArr = {}, xArr = [], yArr = []; - + if (paths[i].closed) { if (j == 0) { - coordArr = getCoordinates(points[1], currPoint, points[points.length - 1], answer); + coordArr = getCoordinates(points[1], currPoint, points[points.length - 1], answer, pTypes); xArr = coordArr.x; yArr = coordArr.y; } if (j == points.length - 1) { - coordArr = getCoordinates(points[0], currPoint, points[points.length - 2], answer); + coordArr = getCoordinates(points[0], currPoint, points[points.length - 2], answer, pTypes); xArr = coordArr.x; yArr = coordArr.y; } } if (j > 0 && j < points.length - 1) { - coordArr = getCoordinates(points[j + 1], currPoint, points[j - 1], answer); + coordArr = getCoordinates(points[j + 1], currPoint, points[j - 1], answer, pTypes); xArr = coordArr.x; yArr = coordArr.y; }; pointCos = calcAngleCos(xArr, yArr); pointCosRound = Math.ceil(pointCos); - + // Bezier Points - if (btnsVal[0] && answer == 'bezier') { - selector(currPoint); + if (btns[0] && (answer == pTypes.bezier || answer == pTypes.ortho)) { + selectPoint(currPoint); + } + // Ortho Points + if (btns[1] && answer == pTypes.ortho) { + selectPoint(currPoint); } // Flush Points - if (btnsVal[1] && (answer == 'l_zero' || answer == 'r_zero') && (pointCosRound == COS_180 || pointCos < COS_INACCURACY)) { - selector(currPoint); + if (btns[2] && (answer == pTypes.lZero || answer == pTypes.rZero) && (pointCosRound == -1 || pointCos < cosTolerance)) { + selectPoint(currPoint); } // Corner Points - if (btnsVal[2] && (answer == 'flat' || answer == 'r_zero' || answer == 'l_zero' || answer == 'corner') - && pointCosRound !== COS_180 && (isNaN(pointCos) || pointCos > COS_INACCURACY)) { - selector(currPoint); + if (btns[3] && (answer == pTypes.flat || answer == pTypes.rZero || answer == pTypes.lZero || answer == pTypes.corner) && + pointCosRound !== -1 && (isNaN(pointCos) || pointCos > cosTolerance)) { + selectPoint(currPoint); } // Broken Points - if (btnsVal[3] && answer == 'broken') { - selector(currPoint); + if (btns[4] && answer == pTypes.broken) { + selectPoint(currPoint); } // Flat Points - if (btnsVal[4] && answer == 'flat' && (pointCosRound == COS_180 || pointCos < COS_INACCURACY)) { - selector(currPoint); + if (btns[5] && answer == pTypes.flat && (pointCosRound == -1 || pointCos < cosTolerance)) { + selectPoint(currPoint); } } } } - app.redraw(); + redraw(); }; -function getSelectedPoints(paths) { - var count = 0; - for (var i = 0, iLen = paths.length; i < iLen; i++) { - if (paths[i].pathPoints.length > 1) { - var points = paths[i].pathPoints; - for (var j = 0, pLen = points.length; j < pLen; j++) { - if (points[j].selected == PathPointSelection.ANCHORPOINT) count++; - } - } - } - return count; +/** + * Select the point + * @param {object} point - point on the path + */ +function selectPoint(point) { + point.selected = PathPointSelection.ANCHORPOINT; +} + +/** + * Open link in browser + * @param {string} url - website adress + */ +function openURL(url) { + var html = new File(Folder.temp.absoluteURI + '/aisLink.html'); + html.open('w'); + var htmlBody = '

'; + html.write(htmlBody); + html.close(); + html.execute(); } // Run script