[
  {
    "path": ".gitignore",
    "content": "# Built application files\n*.apk\n*.ap_\n\n# Files for the Dalvik VM\n*.dex\n\n# Java class files\n*.class\n\n# Generated files\nbin/\ngen/\n\n# Gradle files\n.gradle/\nbuild/\n\n# Local configuration file (sdk path, etc)\nlocal.properties\n\n# Proguard folder generated by Eclipse\nproguard/\n\n# IntelliJ files\n.idea\n*.iml\n\n# Maven output folder\ntarget\n\n# Misc\n.DS_Store\nThumbs.db\n*.swp\n*.bak\n"
  },
  {
    "path": ".project",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<projectDescription>\n\t<name>trianglify</name>\n\t<comment>Project trianglify created by Buildship.</comment>\n\t<projects>\n\t</projects>\n\t<buildSpec>\n\t\t<buildCommand>\n\t\t\t<name>org.eclipse.buildship.core.gradleprojectbuilder</name>\n\t\t\t<arguments>\n\t\t\t</arguments>\n\t\t</buildCommand>\n\t</buildSpec>\n\t<natures>\n\t\t<nature>org.eclipse.buildship.core.gradleprojectnature</nature>\n\t</natures>\n</projectDescription>\n"
  },
  {
    "path": ".settings/org.eclipse.buildship.core.prefs",
    "content": "connection.gradle.distribution=GRADLE_DISTRIBUTION(WRAPPER)\nconnection.project.dir=\neclipse.preferences.version=1\n"
  },
  {
    "path": ".travis.yml",
    "content": "language: android\njdk: oraclejdk8\nsudo: required\n\nandroid:\n  components:\n    - tools\n    - platform-tools\n    - tools\n    - build-tools-26.0.2\n    - android-27\n    - extra-google-m2repository\n    - extra-android-m2repository\n\nscript:\n - ./gradlew build\n - ./gradlew test\n \nbefore_install:\n  - python <(curl -s https://raw.githubusercontent.com/TouK/sputnik-ci/master/sputnik-ci.py)\n\nenv:\n  global:\n  - secure: PIbHGVr+Bv0HbK6qOE6C0FrVqcsm/Q6kzFCOa4y9ixT8+2i82DDP4kyyy2ymKevmps+7+SCeJiW8KQkZa7gztSG0h1BoHJo0C6f0xiMYG4kY/7Gq4ZX3mehOVFUymxqhVED/NMK4a7JJxqcSH7JIkBLkuEaueqxc3CmHjI7LCqTr9yMdu/8ulhOeEL/Drg0zsNK9424K6BtxnTh6nNmbNfRnvxCgFc3mLuZ4J6/YN7lBagNiBhpr3XsXdvUC/W89UCcQCIkl/xBKPTxoUGxD6YG+IhapEJrQvqsFkvwFcsUUa9iL7+23QDlK7VGXeKZxwcMYWjRSVai3np94cHZwqivL1okoMFnIjqcAAzX5NOgd0VvM1dUqIwkXQDhp9IPGqDe/H1BiuRb8rmbJyRsxx5YjwksuPugDcG/B24qhyz4NM+gupMx0UE1DXS20xtE1kItEMzCyOJGXDwD9VR13ED0kYkcZoovPFdGFUOpAyAE9UYe1wDpDbmxF8o24tM5ICTcaATpiowWvBmS3i2qsEg8akpxmOqwWK//aOg2aNRiiX5we1H8QK8QNT0MoRf7B9bh59BHL6aOJ/jCeiYXb1jjWGQCGO9Vh3lzJWw2V9f2CvnUaZfeJOCzLgVPqtrI9E1LoPLiVT0Izx9DZ+aINrBxhNfndz5UZ4VQPHF8DDe4=\n\nnotifications:\n  slack: sdsmdg:hvFSzqFNHm3t6NDR2H2Twiio\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Trianglify Releases\n\n## Latest\n* [Version 1.0.0](https://bintray.com/suyashmahar/trianglify/trianglify/1.0.0)\n | [Google Play](http://bit.ly/trianglifyDemo)  \n**First stable release of Trianglify**\n    * Updated documents so that Trianglify can be seamlessly integrated anywhere\n    * Fixed bugs in demo app\n    \n## Previous\n* [Version 0.9 beta](https://bintray.com/suyashmahar/trianglify/trianglify/0.9-beta)\n | [demo apk](https://drive.google.com/open?id=0Bz_2jvdEtUlrWEpxQ2Y2RnJGc1U)\n    * Added custom palette demonstration to demo app\n    * Added method `fillViewCompletely` to check if view is incompletely filled \n    * Fixes many bugs - [#23](https://github.com/sdsmdg/trianglify/issues/23), [#33](https://github.com/sdsmdg/trianglify/issues/33), [#34](https://github.com/sdsmdg/trianglify/issues/34), [#35](https://github.com/sdsmdg/trianglify/issues/35) & [#36](https://github.com/sdsmdg/trianglify/issues/36)\n    \n* [Version 0.8 beta](https://bintray.com/suyashmahar/trianglify/trianglify/0.8-beta)\n | [demo apk](https://www.dropbox.com/s/cn85g497nkwmx14/trianglify-release-0.8-beta.apk?dl=0)\n    * Generation of triangulation on worker thread to prevent UI freezing [#20](https://github.com/sdsmdg/trianglify/issues/20)\n    * Correct coloring of view, color now drawn matches its name [#18](https://github.com/sdsmdg/trianglify/issues/18)\n    * Support for custom palette ([usage](#26-using-custom-palettes)) [#17](https://github.com/sdsmdg/trianglify/issues/17)\n\n* [Version 0.7 beta](https://bintray.com/suyashmahar/trianglify/trianglify/0.7-beta)\n [Google Play](https://suyashmahar.me/404)\n    * Added library to jCenter | [Link](https://bintray.com/suyashmahar/trianglify/trianglify/)"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "Contributing to Trianglify\n==========================\n:+1::tada: First off, thanks for taking the time to contribute! :tada::+1:  \nIf you'd like to report a bug or join in the development\nof Trianglify, then here are some notes on how to do that.\n\n## Contents\n* [Reporting bugs and opening issues](#reporting-bugs-and-opening-issues)\n* [Coding Guidelines](#coding-guidelines)\n    * [Pull Requests](#pull-requests)\n    * [MVP architecture](#mvp-architecture)\n    * [Style Check](#style-check)\n    * [Git Commit Messages](#git-commit-messages)\n* [MDG Chat Room](#mdg-chat-room)\n* [Security](#security)\n    \n## Reporting bugs and opening issues\n\nIf you'd like a report a bug or open an issue then please:\n\n**Check if there is an existing issue.** If there is then please add\n   any more information that you have, or give it a 👍.\n\nWhen submitting an issue please describe the issue as clearly as possible, including how to\nreproduce the bug, which situations it appears in, what you expected to happen, and what actually happens.\nIf you can include a screenshot for front end issues that is very helpful.\n\n## Coding Guidelines\n\n### Pull Requests\nWe love pull requests, so be bold with them! Don't be afraid of going ahead\nand changing something, or adding a new feature. We're very happy to work with you\nto get your changes merged into Trianglify.\n\nIf you've got an idea for a change then please discuss it in the open first, \neither by opening an issue, or by joining us in our\n[MDG public chat room](https://mdg.sdslabs.co/chat).\n\nIf you're looking for something to work on, have a look at the open issues in the repository [here](https://github.com/sdsmdg/trianglify/issues).\n\n> We don't have a set format for Pull requests, but we expect you to list changes, bugs generated and other relevant things in PR message.\n\n### MVP architecture\nTrianglify is built keeping [MVP (model-view-presenter)](https://en.wikipedia.org/wiki/Model–view–presenter) architecture in mind, so any changes that are proposed to Trianglfiy should follow MVP architecture. If you are confused regarding where a method should be, join us at  [MDG public chat room](https://mdg.sdslabs.co/chat), we'll be happy to help.\n\n### Style Check\nTrianglify uses Sputnik for performing style checks on the codebase, which helps us in maintaining the quality of the code. Sputnik checks for violation upon submission of Pull Requests. If Sputnik reports a violation and you believe that it is not applicable, just comment `N/A` on the sputnik review with the reason of why it is not applicable. **Pull Requests will only be merged once all the violations are resolved**.\n\n### Git Commit Messages\n* Use the present tense (\"Add feature\" not \"Added feature\")\n* Use the imperative mood (\"Move cursor to...\" not \"Moves cursor to...\")\n* Limit the first line to 72 characters or less\n* Reference issues and pull requests liberally\n* When only changing documentation, include `[ci skip]` in the commit description\n* Consider starting the commit message with an applicable emoji:\n    * :art: `:art:` when improving the format/structure of the code\n    * :racehorse: `:racehorse:` when improving performance\n    * :non-potable_water: `:non-potable_water:` when plugging memory leaks\n    * :memo: `:memo:` when writing docs\n    * :bug: `:bug:` when fixing a bug\n    * :fire: `:fire:` when removing code or files\n    * :green_heart: `:green_heart:` when fixing the CI build\n    * :white_check_mark: `:white_check_mark:` when adding tests\n    * :lock: `:lock:` when dealing with security\n    * :arrow_up: `:arrow_up:` when upgrading dependencies\n    * :arrow_down: `:arrow_down:` when downgrading dependencies\n    * :shirt: `:shirt:` when removing linter warnings\n\n## MDG Chat Room\n\nIf you want to ask any questions in real-time, or get a feel for what's going on\nthen please drop into our [MDG public chat room](https://mdg.iitr.ac.in/chat).\nIf no one is online then you can still leave a message that will hopefully get a reply\nwhen we return.\n\n## Security\n\nPlease do not publish security vulnerabilities publicly until we've had a chance\nto address them. All security related issues/patches should be sent directly to\n[mdg@iitr.ac.in](mailto:mdg@iitr.ac.in) where we will attempt to address them quickly. If you're\nunsure whether something is a security issue or not, then please be cautious and contact us at [mdg@iitr.ac.in](mailto:mdg@iitr.ac.in) first.\n\n"
  },
  {
    "path": "DOCUMENTATION.md",
    "content": "Welcome to the Trianglify documentation! Here's the ultimate guide to using Trianglify in your app.\n\n# Documentation\n## Contents\n1. [Usages](#1-usages)\n    1. [Java](#11-java)\n    2. [XML](#12-xml)\n2. [APIs](#2-api-documentation)\n    1. [Attributes and Methods](#21-attributes-and-methods)\n        1. [TrianglifyView](#211-trianglifyview)\n        2. [Palette](#212-palette)\n    2. [Details of Bleed and Grid Dimensions](#22-details-of-bleed-and-grid-dimensions)\n    4. [Note on Units of CellSize, Variance, Bleed & Grid Height](#24-note-on-units-of-cellsize-variance-bleed-and-grid-height)\n    5. [Setting Palette using setPalette](#25-setting-palette-using-setpalette-method)\n    6. [Using Custom Palettes](#26-using-custom-palettes)\n    7. [Updating the View](#27-updating-the-view)\n    8. [Exporting Bitmap](#28-exporting-bitmap)\n3. [Performance Analysis](#3-performance-analysis)\n\n## 1. Usages\n### 1.1 Java\n\n#### Import Statements\nInclude following lines along with other import statements at the beginning of your activity's java class:  \n\n```java\nimport com.sdsmdg.kd.trianglify.views.TrianglifyView;\nimport com.sdsmdg.kd.trianglify.models.Palette;\n```\n\nTo use trianglify view include the following lines to get an instance of view and set its properties:\n\n```java\ntrianglifyView = (TrianglifyView) findViewById(R.id.trianglify_main_view); \ntrianglifyView.setGridWidth(trianglifyView.getWidth())\n            .setGridHeight(trianglifyView.getHeight())\n            .setBleedX(50)\n            .setBleedY(50)\n            .setCellSize(20)\n            .setVariance(10)\n            .setTypeGrid(0)\n            .setPalette(Palette.getPalette(26))\n            .setDrawStrokeEnabled(true);\n```\n\n### 1.2 XML\n\n```xml\n<com.sdsmdg.kd.trianglify.views.TrianglifyView\n    android:id=\"@+id/trianglify_main_view\"\n    app:cellSize=\"20dp\"\n    app:variance=\"10dp\"\n    app:bleedX=\"50dp\"\n    app:bleedY=\"50dp\"\n    app:gridType=\"rectangle\"\n    app:palette=\"Spectral\"\n    app:fillStrokes=\"true\"\n    app:fillTriangle=\"true\" />\n```\n \n\n## 2. API Documentation\n### 2.1 Attributes and Methods\n#### 2.1.1 TrianglifyView\n| Property                    | Default values | Java method             | Attribute       | Description                                                                                                                   |\n|-----------------------------|----------------|-------------------------|-----------------|-------------------------------------------------------------------------------------------------------------------------------|\n| Grid Height                 | NA             | .setGridHeight(...)     | grid_height     | Height of the grid to generate                                                                                                |\n| Grid Width                  | NA             | .setGridWidth(...)      | grid_width      | Width of the grid to generate                                                                                                 |\n| X-axis Bleed                | 0 px         | .setBleedX(...)         | bleed_x         | TrianglifyView generates total area having width = gridWidth + 2*bleedX to avoid unfilled triangles at the edges of the view  |\n| Y-Axis Bleed                | 0 px           | .setBleedY(...)         | bleed_y         | TrianglifyView generates total area having height = gridHeight + 2*bleedY to avoid unfilled triangles at the edges of the view |\n| Variance                    | 10 px          | .setVariance(...)       | variance        | Displacement of points from original grid position to create triangles of different sizes                                     |\n| Cell Size                   | 40 px          | .setCellSize(...)       | cell_size       | Size of cells of rectangular grid used to generated vertices of the triangles                                                 |\n| Grid Type*                  | 0              | .setTypeGrid(...)       | grid_type       | Type of grid 0 for Rectangular                                                                                                |\n| Fill Triangles with color   | true           | .setFillTriangle(...)   | fill_triangles  | Fills the triangle generated with color chosen                                                                                |\n| Draw strokes                | false          | .setDrawStrokes(...)    | draw_strokes    | Draws triangle's border with neighboring triangle's color                                                                     |\n| Color Palette               | YlGn           | .setPalette(...)        | palette         | Set of existing colors to color triangles                                                                                     |\n| Random Coloring             | false          | .setRandomColoring(...) | random_coloring | If random coloring is on triangles will be colored randomly instead of linear interpolation                                   |\n| Fill the View Completely    | false          | .setFillViewCompletely(...) | fillViewCompletely| If fillViewCompletely is true, then it will throw illegalArgumentsException whenever both `BleedX` and `BleedY` are not greater than `cellSize`. Refer to [Section 2.2](#22-details-of-bleed-and-grid-dimensions)\n\n*Current release contains only one GridType accessible with id `0`  \n\n**Other methods**  \nThe following methods are getters for corresponding properties and are not covered in the table above:  \n* isDrawStrokeEnabled\n* isRandomColoringEnabled\n* isFillTriangle\n* isFillViewCompletely\n* getVariance\n* getTypeGrid\n* getPalette\n* getGridWidth\n* getGridHeight\n* getCellSize\n* getBleedX\n* getBleedY\n\nThe following are additional methods provided for the developer:\n\n**`getViewState`**\n\nThis method returns the state of the view. For more information on states of view read **Smart update of view using smartUpdate** in [Section 2.7 Updating the View](#27-updating-the-view).\n\n**`clearView`**\n\nThis method clears the triangulation of the view and sets it to `null`.\n\n#### 2.1.2 Palette\n| Method      | Return Type | Type        | Parameters                                                             | Description                                                                                                                     |\n|-------------|-------------|-------------|------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------|\n| Constructor | -           | Constructor | int c0, int c1, int c2, int c3, int c4, int c5, int c6, int c7, int c8 | Takes nine parameters as colors to construct palette                                                                           |\n| Constructor | -           | Constructor | int[] colors                                                           | Takes nine parameters as an array of colors to construct palette                                                               |\n| getPalette  | Palette     | static      | int paletteIndex                                                       | Returns palette object corresponding to passed value of paletteIndex, palette is constructed from a predefined set of colors. |\n| indexOf     | int         | static      | Palette palette                                                        | Returns index of palette object in predefined palette, -1 if doesn't exists                                                     |\n| getColor    | int         | -           | int index                                                              | Returns color corresponding to index passed from the set of colors for a palette                                                 |\n\n<p>\n\n### 2.2 Details of Bleed and Grid Dimensions\n* **Bleed:** Bleed defines the dimensions of extra size that TrianglifyView view generates so that triangles on the edge don't appear to be chopped off. In most of the cases `min{bleedX, bleedY} > cellSize` would ensure that the view is completely filled.  \n* **Grid Dimensions:** `GridHeight` and `GridWidth` defines the dimensions of the visible area of the view.  \n\nTotal area generated by TrianglifyView is (`gridHeight` + 2  * `BleedY`) * (`gridWidth` + 2 * `BleedX`) while total area visible is (`gridHeight`) * (`gridWidth`)  \n\nFollowing image demonstrates region covered by `gridHeight`, `gridWidth`, `bleedX` and `bleedY`\n<p>\n<img src=\"resources/default_pattern_explained.jpg\" data-canonical-src=\"resources/default_pattern_explained.jpg\" width=\"350\" height=\"350\" />\n\n### 2.4 Note on Units of CellSize, Variance, Bleed and Grid Height\nAttributes of `CellSize`, `Variance`, `Bleed` and `GridHeight` supplied to TrianglifyView using Java are interpreted as `px`. To convert px to dp or vice-versa define and use following methods:\n\n```java\npublic int dpToPx(int dp) {\n    DisplayMetrics displayMetrics = this.getResources().getDisplayMetrics();\n    return Math.round(dp * (displayMetrics.xdpi / DisplayMetrics.DENSITY_DEFAULT));\n}\n\npublic int pxToDp(int px) {\n    DisplayMetrics displayMetrics = this.getResources().getDisplayMetrics();\n    return Math.round(px / (displayMetrics.xdpi / DisplayMetrics.DENSITY_DEFAULT));\n}\n```\n\n### 2.5 Setting Palette using setPalette method\n`TrianglifyView`'s `setPalette` method accepts `Palette` object. Palette can be set using one of the following methods: \n* To use one of the predefined palette, for example **Spectral** use `trianglifyView.setPalette(Palette.getPalette(Palette.Spectral))`.\n* To use palette referring to its index use `Palette.getPalette(<index>)`.  \n* To use custom palette refer to section [2.6 Using custom Palettes](#26-using-custom-palettes).\n\n> **Note:** Index used for addressing palette should be less than `Palette.DEFAULT_PALETTE_COUNT`, if index is greater than `DEFAULT_PALETTE_COUNT` `IllegalArgumentException` is thrown.\n\n**Note: Palette enum defines total of 28 named palettes that can be used to generate views without specifying colors.** \n\n### 2.6 Using Custom Palettes\nCustom Palettes can be used by creating new palette using one of the following constructor:\n\n```java\nPalette customPalette = new Palette(int c0, int c1, int c2, int c3, int c4, int c5, int c6, int c7, int c8);\n```\n\nor\n\n```java\nPalette customPalette = new Palette(int colors[]);\n```\n> Array based constructor will throw `IllegalArgumentException` if size of array is not exactly 9.\n\n### 2.7 Updating the View\n\n`TrianglifyView` should be updated on change of any of the parameter for changes to take effect. `TrianglifyView` can be updated by the following two methods:\n\n**Smart update of view using `smartUpdate`**\n\n`smartUpdate` updates the view smartly by looking at the parameter changes in the view since the last update, and accordingly decides which parts of the view should be updated. More formal description is:\n* If only the `drawStroke` or `fillTriangle` values have been changed since the last update, the triangulation is only replotted in accordance to the new paint strokes. \n* If the `randomColoring` or `palette` have been changed without any changes in the grid parameters, only the new colors are assigned to the triangulation without regenerating the grid and delaunay triangulation, after which the view is plotted in accordance to the `fillTriangle` and `drawStrokes` parameters.\n* If there are changes in the grid parameters, the whole triangulation has to be generated from scratch. The method generates a new grid according to the parameters and fits a delaunay triangulation. This is followed by colorization and plotting of the triangulation onto the view.\n\n**Complete regeneration using `generateAndInvalidate`**\n\nThis is used when the triangulation is to be generated from scratch. The method generates a grid according to the parameters and fits a delaunay triangulation. This is followed by colorization and plotting of the triangulation onto the view.\n\n**(Basic) Performance Comparision of the Two Methods**\n\n`smartUpdate` method regenerates the whole triangulation only when the grid parameters have been changed, thereby bypassing the unnecessary regeneration of grid and delaunay triangulation in situations when parameters other than grid parameters have been changed. This leads to a faster rendering of view. \n\nThe `generateAndInvalidate` method regenerates the whole triangulation irrespective of which parameters have been changed, carrying out steps that might not be necessary, hence causing hindrance to performance.\n\n### 2.8 Exporting Bitmap\n`TrianglifyView` can export Bitmap object of the triangulation plotted, to get a bitmap object use `getBitmap` method of trianglifyView. `getBitmap` returns a mutable bitmap object that is of `ARGB_8888` configuration. \n\nQuality of the bitmap obtained can be set using `setQuality` method of TrianglifyView which accepts one of the three possible parameter `TrianglifyView.DRAWING_CACHE_QUALITY_HIGH`, `TrianglifyView.DRAWING_CACHE_QUALITY_LOW` and `TrianglifyView.DRAWING_CACHE_QUALITY_AUTO`.\n\n## 3. Performance Analysis\nFew notes on performance of Trianglify\n* Performance takes a serious hit with decrease in cell size. Time complexity of the algorithm to generate triangles from grid of points is Ω(n*log(n)). Decreasing cell size increases n (number of points on the grid). \n* Performance of coloring is faster on the use of random coloring rather than gradient.\n* On use of smartUpdate, performance of coloring depends on the parameters changed since last triangulation. Check [2.7 Updating the View](#27-updating-the-view) for more details.\n\n"
  },
  {
    "path": "LICENSE.md",
    "content": "Copyright 2016-17 SDSMDG\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE."
  },
  {
    "path": "README.md",
    "content": "﻿<!--  \n\n<br> \n<br> \n<div align=\"center\"><img src=\"resources/trianglify-logo-with-text-close-fit.png\" data-canonical-src=\"trianglify-logo-180.png\" width=\"154\" height=\"154\" /></div>\n<br> \n<br>\n\n-->\n\n# Trianglify\n\n<!-- [![Build Status](https://travis-ci.com/sdsmdg/trianglify.svg?token=tRURwj39jsSs5JWUTxs6&branch=develop)](https://travis-ci.com/sdsmdg/trianglify) -->\n[![platform](https://img.shields.io/badge/platform-Android-yellow.svg)](https://www.android.com)\n[![API](https://img.shields.io/badge/API-16%2B-brightgreen.svg?style=flat)](https://android-arsenal.com/api?level=16s)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n[![by-SDS-MDG](https://img.shields.io/badge/by-MDG--IITR-blue.svg)](http://mdg.iitr.ac.in)\n\n<img src=\"resources/splash.png\" data-canonical-src=\"resources/default_pattern_explained.jpg\"/>\n\n<a href='http://bit.ly/trianglifyDemo'><img alt='Get it on Google Play' src='https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png' width=\"200\"/></a>\n\nTrianglify is an Android library that helps creates views with beautiful patterns. Trianglify is based on MVP architecture and licensed under MIT license.\n\n# How to Apply\n\nInclude following line in the gradle script of your application to include latest release of Trianglify:\n```gradle\ncompile 'com.sdsmdg.kd:trianglify:1.0.0'\n```\n\n# Features\n**Cell Size**  \n![alt text](resources/gifs/cell_size.gif)  \n**Random Coloring**  \n![alt text](resources/gifs/random_coloring.gif)  \n\n# Examples\n**Navigation Panes**  \n![alt text](resources/gifs/navigation_pane.gif)  \n**Action Bars**  \n![alt text](resources/gifs/actionBar.gif)  \n# Latest Release\n* [Version 1.0.0](https://bintray.com/suyashmahar/trianglify/trianglify/1.0.0)\n | [Google Play](http://bit.ly/trianglifyDemo)  \n**First stable release of Trianglify**\n    * Updated documents so that Trianglify can be seamlessly integrated anywhere\n    * Fixed bugs in demo app\n\nFor more check complete [change log](/CHANGELOG.md).  \n\n# Usages and Documentation\nFor details on usage and documentation of Trianglify, check documentation [here](DOCUMENTATION.md).\n\n# Credits\nTrianglify is inspired from qrohlf's work to generate triangle art, [Trianglify](https://github.com/qrohlf/trianglify)  \n\nDevelopment of Trianglify wouldn't have been possible without following libraries:\n* [Delaunay Triangulator by jdiemke](https://github.com/jdiemke/delaunay-triangulator)\n* [Color Picker by QuadFlask](https://github.com/QuadFlask/colorpicker)\n\n\n# Guidelines for Contributors\nIf you want to contribute to improve this library, please read [our guidelines](CONTRIBUTING.md).\n\n# License\nTrianglify is licensed under `MIT license`. View license [here](LICENSE.md).\n"
  },
  {
    "path": "app/.classpath",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<classpath>\n\t<classpathentry kind=\"con\" path=\"org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8/\"/>\n\t<classpathentry kind=\"con\" path=\"org.eclipse.buildship.core.gradleclasspathcontainer\"/>\n\t<classpathentry kind=\"output\" path=\"bin\"/>\n</classpath>\n"
  },
  {
    "path": "app/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "app/.project",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<projectDescription>\n\t<name>app</name>\n\t<comment>Project app created by Buildship.</comment>\n\t<projects>\n\t</projects>\n\t<buildSpec>\n\t\t<buildCommand>\n\t\t\t<name>org.eclipse.jdt.core.javabuilder</name>\n\t\t\t<arguments>\n\t\t\t</arguments>\n\t\t</buildCommand>\n\t\t<buildCommand>\n\t\t\t<name>org.eclipse.buildship.core.gradleprojectbuilder</name>\n\t\t\t<arguments>\n\t\t\t</arguments>\n\t\t</buildCommand>\n\t</buildSpec>\n\t<natures>\n\t\t<nature>org.eclipse.jdt.core.javanature</nature>\n\t\t<nature>org.eclipse.buildship.core.gradleprojectnature</nature>\n\t</natures>\n</projectDescription>\n"
  },
  {
    "path": "app/.settings/org.eclipse.buildship.core.prefs",
    "content": "connection.gradle.distribution=GRADLE_DISTRIBUTION(WRAPPER)\nconnection.project.dir=..\neclipse.preferences.version=1\n"
  },
  {
    "path": "app/build.gradle",
    "content": "apply plugin: 'com.android.application'\n\nandroid {\n    compileSdkVersion 27\n    buildToolsVersion '26.0.2'\n    defaultConfig {\n        applicationId \"com.sdsmdg.kd.trianglifyexample\"\n        minSdkVersion 16\n        targetSdkVersion 27\n        versionCode 1\n        versionName \"1.0.0\"\n        testInstrumentationRunner \"android.support.test.runner.AndroidJUnitRunner\"\n    }\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n    lintOptions {\n        abortOnError false\n    }\n}\n\ndependencies {\n    compile fileTree(dir: 'libs', include: ['*.jar'])\n    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {\n        exclude group: 'com.android.support', module: 'support-annotations'\n    })\n\n    //----Testing frameworks\n\n    compile project(':trianglify')\n\n    implementation 'com.android.support:appcompat-v7:27.0.2'\n    implementation 'com.android.support.constraint:constraint-layout:1.0.2'\n    implementation 'com.github.QuadFlask:colorpicker:0.0.13'\n    testCompile 'junit:junit:4.12'\n    testCompile 'org.mockito:mockito-core:2.11.0'\n}\n"
  },
  {
    "path": "app/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in /root/Android/Sdk/tools/proguard/proguard-android.txt\n# You can edit the include path and order by changing the proguardFiles\n# directive in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# Add any project specific keep options here:\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n"
  },
  {
    "path": "app/src/androidTest/java/com/sdsmdg/kd/trianglifyexample/ExampleInstrumentedTest.java",
    "content": "package com.sdsmdg.kd.trianglifyexample;\n\nimport android.content.Context;\nimport android.support.test.InstrumentationRegistry;\nimport android.support.test.runner.AndroidJUnit4;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\n\nimport static org.junit.Assert.*;\n\n/**\n * Instrumentation test, which will execute on an Android device.\n *\n * @see <a href=\"http://d.android.com/tools/testing\">Testing documentation</a>\n */\n@RunWith(AndroidJUnit4.class)\npublic class ExampleInstrumentedTest {\n    @Test\n    public void useAppContext() throws Exception {\n        // Context of the app under test.\n        Context appContext = InstrumentationRegistry.getTargetContext();\n\n        assertEquals(\"com.sdsmdg.kd.trianglifyexample\", appContext.getPackageName());\n    }\n}\n"
  },
  {
    "path": "app/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.sdsmdg.kd.trianglifyexample\">\n\n    <uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\" />\n    <uses-permission android:name=\"android.permission.SET_WALLPAPER\"/>\n\n    <application\n        android:allowBackup=\"true\"\n        android:icon=\"@mipmap/ic_launcher\"\n        android:label=\"@string/app_name\"\n        android:supportsRtl=\"true\"\n        android:theme=\"@style/AppTheme\">\n        <activity android:name=\".MainActivity\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\" />\n\n                <category android:name=\"android.intent.category.LAUNCHER\" />\n            </intent-filter>\n        </activity>\n        <activity android:name=\".AboutActivity\" />\n        <activity android:name=\".CustomPalettePickerActivity\"/>\n    </application>\n\n</manifest>\n"
  },
  {
    "path": "app/src/main/java/com/sdsmdg/kd/trianglifyexample/AboutActivity.java",
    "content": "package com.sdsmdg.kd.trianglifyexample;\n\nimport android.content.ActivityNotFoundException;\nimport android.content.DialogInterface;\nimport android.content.Intent;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PackageManager;\nimport android.net.Uri;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.support.v7.app.ActionBar;\nimport android.support.v7.app.AlertDialog;\nimport android.support.v7.app.AppCompatActivity;\nimport android.text.SpannableString;\nimport android.text.style.UnderlineSpan;\nimport android.util.Log;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.widget.ImageView;\nimport android.widget.TextView;\n\npublic class AboutActivity extends AppCompatActivity {\n    private static final String TAG = \"AboutActivity\";\n\n    ImageView githubLinkBtn, reviewLinkBtn, shareLink, backBtn;\n    TextView fragTitle, openSourceLicense, versiontTextView;\n    View bottomMarginLayout;\n    PackageInfo pInfo;\n    String versionName;\n    int versionCode;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n\n        setContentView(R.layout.activity_about);\n\n        // To add underline effect in open source license textView\n        SpannableString content = new SpannableString(\"view license\");\n        content.setSpan(new UnderlineSpan(), 0, content.length(), 0);\n\n        // Gets version and build number from package manager\n        try {\n            pInfo = this.getPackageManager().getPackageInfo(this.getPackageName(), 0);\n            versionName = pInfo.versionName;\n            versionCode = pInfo.versionCode;\n        } catch (PackageManager.NameNotFoundException e) {\n            e.printStackTrace();\n        }\n\n\n        ActionBar actionBar = getSupportActionBar();\n        if (actionBar != null) {\n            actionBar.setTitle(getString(R.string.about_activity_title));\n        }\n\n        try {\n            if (actionBar != null) {\n                actionBar.setDisplayHomeAsUpEnabled(true);\n            }\n        } catch (java.lang.NullPointerException e) {\n            Log.e(TAG, \"Null pointer exception in generating back action button\");\n        }\n\n        versiontTextView = this.findViewById(R.id.about_version_text);\n\n        openSourceLicense = this.findViewById(R.id.about_license_text);\n        openSourceLicense.setText(content);\n\n        githubLinkBtn = this.findViewById(R.id.about_github_link);\n        reviewLinkBtn = this.findViewById(R.id.about_rate_link);\n        shareLink = this.findViewById(R.id.about_share_link);\n\n\n        versiontTextView.setText(getString(R.string.about_activity_version) + versionName);\n        openSourceLicense.setOnClickListener(new View.OnClickListener() {\n            @Override\n            public void onClick(View v) {\n                displayOpenSourceLicenses();\n            }\n        });\n\n        githubLinkBtn.setOnClickListener(new View.OnClickListener() {\n            @Override\n            public void onClick(View v) {\n                Uri uri = Uri.parse(\"https://github.com/sdsmdg/trianglify\");\n                Intent intent = new Intent(Intent.ACTION_VIEW, uri);\n                startActivity(intent);\n            }\n        });\n\n        reviewLinkBtn.setOnClickListener(new View.OnClickListener() {\n            @Override\n            public void onClick(View v) {\n                Uri uri = Uri.parse(\"market://details?id=\" + v.getContext().getPackageName());\n                Intent goToMarket = new Intent(Intent.ACTION_VIEW, uri);\n                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {\n                    goToMarket.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY |\n                            Intent.FLAG_ACTIVITY_NEW_DOCUMENT |\n                            Intent.FLAG_ACTIVITY_MULTIPLE_TASK);\n                }\n                try {\n                    startActivity(goToMarket);\n                } catch (ActivityNotFoundException e) {\n                    startActivity(new Intent(Intent.ACTION_VIEW,\n                            Uri.parse(\"http://play.google.com/store/apps/details?id=\" + v.getContext().getPackageName())));\n                }\n            }\n        });\n\n        //TODO: Update link when app releases to marketplace\n\n        shareLink.setOnClickListener(new View.OnClickListener() {\n            @Override\n            public void onClick(View v) {\n                Intent sendIntent = new Intent();\n                sendIntent.setAction(Intent.ACTION_SEND);\n                sendIntent.putExtra(Intent.EXTRA_TEXT, getResources().getString(R.string.share_application_text) +\n                        \" \" + getResources().getString(R.string.trianglify_store_short_link));\n                sendIntent.setType(\"text/plain\");\n                startActivity(sendIntent);\n            }\n        });\n    }\n\n    public void displayOpenSourceLicenses() {\n        final AlertDialog alertDialog = new AlertDialog.Builder(this).create();\n        alertDialog.setTitle(this.getApplicationInfo().name);\n        alertDialog.setMessage(getResources().getString(R.string.license_text));\n        alertDialog.setButton(AlertDialog.BUTTON_POSITIVE, \"OK\",\n                new DialogInterface.OnClickListener() {\n                    public void onClick(DialogInterface dialog, int which) {\n                        dialog.dismiss();\n                    }\n                });\n        alertDialog.setButton(AlertDialog.BUTTON_NEUTRAL, \"view license\", new DialogInterface.OnClickListener() {\n            @Override\n            public void onClick(DialogInterface dialog, int which) {\n                startActivity(new Intent(Intent.ACTION_VIEW,\n                        Uri.parse(getResources().getString(R.string.license_link))));\n            }\n        });\n        alertDialog.show();\n    }\n\n    // Sets action for Action Bar Items\n    public boolean onOptionsItemSelected(MenuItem item) {\n        switch (item.getItemId()) {\n            case android.R.id.home:\n                onBackPressed();\n                return true;\n            default:\n                return super.onOptionsItemSelected(item);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/sdsmdg/kd/trianglifyexample/CustomPalettePickerActivity.java",
    "content": "package com.sdsmdg.kd.trianglifyexample;\n\nimport android.content.Context;\nimport android.content.DialogInterface;\nimport android.content.Intent;\nimport android.graphics.Color;\nimport android.support.v7.app.ActionBar;\nimport android.support.v7.app.AlertDialog;\nimport android.support.v7.app.AppCompatActivity;\nimport android.os.Bundle;\nimport android.util.Log;\nimport android.view.Menu;\nimport android.view.MenuInflater;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.widget.ImageView;\n\nimport com.flask.colorpicker.ColorPickerView;\nimport com.flask.colorpicker.OnColorSelectedListener;\nimport com.flask.colorpicker.builder.ColorPickerClickListener;\nimport com.flask.colorpicker.builder.ColorPickerDialogBuilder;\nimport com.sdsmdg.kd.trianglify.models.Palette;\nimport com.sdsmdg.kd.trianglify.views.TrianglifyView;\n\npublic class CustomPalettePickerActivity extends AppCompatActivity {\n    private static final String TAG = \"CustomPalleteActivity\";\n\n    private Palette palette;\n    private TrianglifyView trianglifyView;\n    private Context context;\n    private ImageView[] imageViews = new ImageView[9];\n    private int[] colors = {Color.BLACK, Color.BLUE, Color.BLACK, Color.CYAN, Color.DKGRAY, Color.GREEN, Color.RED, Color.MAGENTA, Color.LTGRAY};\n    public static final String CUSTOM_PALETTE_COLOR_ARRAY = \"Custom Palette Color Array\";\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n\n        ActionBar actionBar = getSupportActionBar();\n        setContentView(R.layout.activity_custom_palette_picker);\n\n        try {\n            if (actionBar != null) {\n                actionBar.setDisplayHomeAsUpEnabled(true);\n            }\n        } catch (java.lang.NullPointerException e) {\n            Log.e(TAG, \"Null pointer exception in generating back action button\");\n        }\n\n        try {\n            if (actionBar != null) {\n                actionBar.setTitle(\"Custom Palette Picker\");\n            }\n        } catch (java.lang.NullPointerException e) {\n            Log.e(TAG, \"Null pointer exception on setting About activity title\");\n        }\n\n        colors = getIntent().getIntArrayExtra(getResources().getString(R.string.palette_color_array));\n\n        context = this;\n\n        trianglifyView = findViewById(R.id.trianglify_custom_palette_view);\n        trianglifyView.setPalette(new Palette(colors));\n        trianglifyView.smartUpdate();\n\n        for (int i = 0; i < imageViews.length; i++) {\n            String imageViewNumber = \"custom_palette_c\" + String.valueOf(i);\n            int resID = getResources().getIdentifier(imageViewNumber, \"id\", getPackageName());\n            imageViews[i] = findViewById(resID);\n            imageViews[i].setBackgroundColor(colors[i] + 0xff000000);\n\n            final int finalI = i;\n\n            imageViews[i].setOnClickListener(new View.OnClickListener() {\n                @Override\n                public void onClick(View v) {\n                    final AlertDialog dialog = ColorPickerDialogBuilder\n                            .with(context)\n                            .initialColor(colors[finalI] + 0xff000000)\n                            .setTitle(\"Choose Color\")\n                            .wheelType(ColorPickerView.WHEEL_TYPE.FLOWER)\n                            .density(9)\n                            .showColorEdit(true)\n                            .lightnessSliderOnly()\n                            .setColorEditTextColor(0xff000000)\n                            .showColorPreview(true)\n                            .setOnColorSelectedListener(new OnColorSelectedListener() {\n                                @Override\n                                public void onColorSelected(int color) {\n                                }\n                            })\n                            .setPositiveButton(\"ok\", new ColorPickerClickListener() {\n                                @Override\n                                public void onClick(DialogInterface dialog, int color, Integer[] allColors) {\n                                    imageViews[finalI].setBackgroundColor(color);\n                                    colors[finalI] = color - 0xff000000;\n                                    palette = new Palette(colors);\n                                    trianglifyView.setPalette(palette);\n                                    trianglifyView.smartUpdate();\n                                }\n                            })\n                            .setNegativeButton(\"cancel\", new DialogInterface.OnClickListener() {\n                                @Override\n                                public void onClick(DialogInterface dialog, int which) {\n                                    dialog.dismiss();\n                                }\n                            })\n                            .build();\n\n                    dialog.show();\n                }\n            });\n        }\n    }\n\n    @Override\n    public boolean onCreateOptionsMenu(Menu menu) {\n        MenuInflater inflater = getMenuInflater();\n        inflater.inflate(R.menu.menu_custom_palette_picker, menu);\n        return true;\n    }\n\n    public boolean onOptionsItemSelected(MenuItem item) {\n        switch (item.getItemId()) {\n            case android.R.id.home:\n                onBackPressed();\n                return true;\n            case R.id.custom_palette_ok:\n                Intent intent = new Intent();\n                intent.putExtra(CUSTOM_PALETTE_COLOR_ARRAY, colors);\n                setResult(RESULT_OK, intent);\n                onBackPressed();\n                return true;\n            default:\n                return super.onOptionsItemSelected(item);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/sdsmdg/kd/trianglifyexample/MainActivity.java",
    "content": "package com.sdsmdg.kd.trianglifyexample;\n\nimport android.Manifest;\nimport android.app.WallpaperManager;\nimport android.content.Context;\nimport android.content.DialogInterface;\nimport android.content.Intent;\nimport android.content.pm.PackageManager;\nimport android.graphics.Bitmap;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.os.Environment;\nimport android.provider.MediaStore;\nimport android.support.annotation.NonNull;\nimport android.support.v4.app.ActivityCompat;\nimport android.support.v4.content.ContextCompat;\nimport android.support.v7.app.AlertDialog;\nimport android.support.v7.app.AppCompatActivity;\nimport android.util.DisplayMetrics;\nimport android.view.Menu;\nimport android.view.MenuInflater;\nimport android.view.MenuItem;\nimport android.widget.CheckBox;\nimport android.widget.CompoundButton;\nimport android.widget.SeekBar;\nimport android.widget.Toast;\n\nimport com.sdsmdg.kd.trianglify.models.Palette;\nimport com.sdsmdg.kd.trianglify.views.TrianglifyView;\n\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\nimport java.util.Locale;\nimport java.util.Random;\n\npublic class MainActivity extends AppCompatActivity {\n    public TrianglifyView trianglifyView;\n    private SeekBar varianceSeekBar;\n    private SeekBar cellSizeSeekBar;\n    private SeekBar paletteSeekBar;\n    private CheckBox strokeCheckBox;\n    private CheckBox fillCheckBox;\n    private CheckBox randomColoringCheckbox;\n    private CheckBox customPaletteCheckbox;\n    private Palette customPalette;\n    private final int PERMISSION_CODE = 69;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_main);\n\n\n        trianglifyView = findViewById(R.id.trianglify_main_view);\n        trianglifyView.setBitmapQuality(TrianglifyView.DRAWING_CACHE_QUALITY_HIGH);\n\n        customPalette = trianglifyView.getPalette();\n\n        varianceSeekBar = findViewById(R.id.variance_seekbar);\n        varianceSeekBar.setMax(100);\n        varianceSeekBar.setProgress(trianglifyView.getVariance());\n        varianceSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {\n            @Override\n            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {\n                trianglifyView.setVariance(progress + 1);\n                trianglifyView.smartUpdate();\n            }\n\n            @Override\n            public void onStartTrackingTouch(SeekBar seekBar) {\n\n            }\n\n            @Override\n            public void onStopTrackingTouch(SeekBar seekBar) {\n\n            }\n        });\n\n        cellSizeSeekBar = findViewById(R.id.cell_size_seekbar);\n        int maxCellSize = 150;\n\n        cellSizeSeekBar.setMax(maxCellSize);\n        cellSizeSeekBar.setProgress(trianglifyView.getCellSize() - 100);\n        cellSizeSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {\n            @Override\n            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {\n                trianglifyView.setCellSize(progress + 100);\n                trianglifyView.smartUpdate();\n            }\n\n            @Override\n            public void onStartTrackingTouch(SeekBar seekBar) {\n\n            }\n\n            @Override\n            public void onStopTrackingTouch(SeekBar seekBar) {\n\n            }\n        });\n\n        paletteSeekBar = findViewById(R.id.palette_seekbar);\n        paletteSeekBar.setMax(Palette.DEFAULT_PALETTE_COUNT - 1);\n        paletteSeekBar.setProgress(Palette.indexOf(trianglifyView.getPalette()));\n        paletteSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {\n            @Override\n            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {\n                trianglifyView.setPalette(Palette.getPalette(progress));\n                customPaletteCheckbox.setChecked(false);\n                trianglifyView.smartUpdate();\n            }\n\n            @Override\n            public void onStartTrackingTouch(SeekBar seekBar) {\n\n            }\n\n            @Override\n            public void onStopTrackingTouch(SeekBar seekBar) {\n\n            }\n        });\n\n        strokeCheckBox = findViewById(R.id.draw_stroke_checkbox);\n        strokeCheckBox.setChecked(trianglifyView.isDrawStrokeEnabled());\n        strokeCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {\n            @Override\n            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {\n                if (isChecked || trianglifyView.isFillTriangle()) {\n                    trianglifyView.setDrawStrokeEnabled(isChecked);\n                    strokeCheckBox.setChecked(isChecked);\n                    trianglifyView.smartUpdate();\n                } else {\n                    strokeCheckBox.setChecked(!isChecked);\n                    showColoringError();\n                }\n            }\n        });\n\n        fillCheckBox = findViewById(R.id.draw_fill_checkbox);\n        fillCheckBox.setChecked(trianglifyView.isFillTriangle());\n        fillCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {\n            @Override\n            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {\n                if (isChecked || trianglifyView.isDrawStrokeEnabled()) {\n                    trianglifyView.setFillTriangle(isChecked);\n                    fillCheckBox.setChecked(isChecked);\n                    trianglifyView.smartUpdate();\n                } else {\n                    fillCheckBox.setChecked(!isChecked);\n                    showColoringError();\n                }\n            }\n        });\n\n        randomColoringCheckbox = findViewById(R.id.random_coloring_checkbox);\n        randomColoringCheckbox.setChecked(trianglifyView.isRandomColoringEnabled());\n        randomColoringCheckbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {\n            @Override\n            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {\n                trianglifyView.setRandomColoring(isChecked);\n                trianglifyView.smartUpdate();\n            }\n        });\n\n        customPaletteCheckbox = findViewById(R.id.custom_palette_checkbox);\n        customPaletteCheckbox.setChecked(false);\n        customPaletteCheckbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {\n            @Override\n            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {\n                if (isChecked) {\n                    trianglifyView.setPalette(customPalette);\n                    trianglifyView.smartUpdate();\n                } else {\n                    trianglifyView.setPalette(Palette.getPalette(paletteSeekBar.getProgress()));\n                    trianglifyView.smartUpdate();\n                }\n            }\n        });\n    }\n\n    @Override\n    public boolean onCreateOptionsMenu(Menu menu) {\n        MenuInflater inflater = getMenuInflater();\n        inflater.inflate(R.menu.menu, menu);\n        return true;\n    }\n\n    public void updateUIElements(TrianglifyView trianglifyView) {\n        fillCheckBox.setChecked(trianglifyView.isFillTriangle());\n        strokeCheckBox.setChecked(trianglifyView.isDrawStrokeEnabled());\n        randomColoringCheckbox.setChecked(trianglifyView.isRandomColoringEnabled());\n\n        varianceSeekBar.setProgress(trianglifyView.getVariance());\n        cellSizeSeekBar.setProgress(trianglifyView.getCellSize());\n        paletteSeekBar.setProgress(Palette.indexOf(trianglifyView.getPalette()));\n    }\n\n    public void randomizeTrianglifyParameters(TrianglifyView trianglifyView) {\n        Random rnd = new Random(System.currentTimeMillis());\n        trianglifyView.setCellSize(dpToPx(rnd.nextInt(10) + 35))\n                .setPalette(Palette.getPalette(rnd.nextInt(28)))\n                .setRandomColoring(rnd.nextInt(2) == 0)\n                .setFillTriangle(rnd.nextInt(2) == 0)\n                .setDrawStrokeEnabled(rnd.nextInt(2) == 0)\n                .setVariance(rnd.nextInt(60));\n\n        if (!trianglifyView.isFillTriangle() && !trianglifyView.isDrawStrokeEnabled()) {\n            trianglifyView.setDrawStrokeEnabled(true);\n            trianglifyView.setFillTriangle(true);\n        }\n\n        updateUIElements(trianglifyView);\n    }\n\n    public int dpToPx(int dp) {\n        DisplayMetrics displayMetrics = this.getResources().getDisplayMetrics();\n        return Math.round(dp * (displayMetrics.xdpi / DisplayMetrics.DENSITY_DEFAULT));\n    }\n\n    public int pxToDp(int px) {\n        DisplayMetrics displayMetrics = this.getResources().getDisplayMetrics();\n        return Math.round(px / (displayMetrics.xdpi / DisplayMetrics.DENSITY_DEFAULT));\n    }\n\n    // Click handlers for action bar menu items\n    @Override\n    public boolean onOptionsItemSelected(MenuItem item) {\n        switch (item.getItemId()) {\n            case R.id.action_save:\n                try {\n                    exportImage();\n                } catch (IOException e) {\n                    Toast.makeText(MainActivity.this,\n                            \"Storage access failed!\",Toast.LENGTH_LONG).show();\n                }\n                break;\n            case R.id.action_about:\n                Intent aboutActivityIntent = new Intent(this, AboutActivity.class);\n                startActivity(aboutActivityIntent);\n                break;\n            case R.id.action_refresh:\n                randomizeTrianglifyParameters(trianglifyView);\n                trianglifyView.generateAndInvalidate();\n                break;\n            case R.id.custom_palette_picker:\n                Intent customPalettePickerIntent = new Intent(this, CustomPalettePickerActivity.class);\n                customPalettePickerIntent.putExtra(getResources().getString(R.string.palette_color_array),\n                        trianglifyView.getPalette().getColors());\n                startActivityForResult(customPalettePickerIntent, 1);\n                customPaletteCheckbox.setChecked(true);\n                break;\n            case R.id.action_set_wall:\n                setWallpaper(MainActivity.this.trianglifyView);\n                break;\n            default:\n                break;\n        }\n\n        return true;\n    }\n\n    public void showColoringError() {\n        Toast.makeText(this, \"View should at least be set to draw strokes or fill triangles or both.\",\n                Toast.LENGTH_LONG).show();\n    }\n\n    public void onActivityResult(int requestCode, int resultCode, Intent data) {\n        super.onActivityResult(requestCode, resultCode, data);\n        if (requestCode == 1 && resultCode == RESULT_OK) {\n            customPalette = new Palette(data.getIntArrayExtra(CustomPalettePickerActivity.CUSTOM_PALETTE_COLOR_ARRAY));\n            if (customPaletteCheckbox.isChecked()) {\n                trianglifyView.setPalette(customPalette);\n                trianglifyView.smartUpdate();\n            }\n        }\n    }\n\n    private void exportImage() throws IOException {\n        // Checks if permission is required for android version > 6\n        boolean permissionStatus = ContextCompat.checkSelfPermission(this,\n                Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED;\n\n        if (permissionStatus) {\n            ActivityCompat.requestPermissions(this,\n                    new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},\n                    PERMISSION_CODE);\n        } else {\n            Bitmap bitmap = trianglifyView.getBitmap();\n            if (bitmap != null)\n                addImageToGallery(bitmap, this);\n            else\n                Toast.makeText(this, \"Unable to generate image, please try again\",\n                        Toast.LENGTH_LONG).show();\n\n        }\n    }\n\n    public static void addImageToGallery(Bitmap bitmap, Context context) throws IOException {\n        String timeStamp = \"IMG_\" + new SimpleDateFormat(\"yyyyMMdd_HHmmss\", Locale.US).format(new Date()) + \".png\";\n        OutputStream os = new FileOutputStream(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) + File.separator + timeStamp);\n        bitmap.compress(Bitmap.CompressFormat.PNG, 100, os);\n        os.flush();\n        os.close();\n        Toast.makeText(context, \"Saved!\", Toast.LENGTH_SHORT).show();\n    }\n\n    // Sets bitmap from trianglify view as wallpaper of device\n    public void setWallpaper(final TrianglifyView view) {\n        AlertDialog.Builder alertDgBuilder = new AlertDialog.Builder(this);\n        alertDgBuilder.setMessage(getString(R.string.wall_alert_dg_text));\n        alertDgBuilder.setPositiveButton(\"Yes\", new DialogInterface.OnClickListener() {\n            @Override\n            public void onClick(DialogInterface dialog, int which) {\n                WallpaperManager trianglifyWallpaperManager = WallpaperManager.getInstance(getApplicationContext());\n                try {\n                    trianglifyWallpaperManager.setBitmap(view.getBitmap());\n                    Toast.makeText(MainActivity.this, \"Wallpaper set successfuly\",\n                            Toast.LENGTH_SHORT).show();\n                } catch (IOException e) {\n                    Toast.makeText(MainActivity.this, \"Something went wrong, please try again.\",\n                            Toast.LENGTH_LONG).show();\n                }\n            }\n        });\n        alertDgBuilder.setNegativeButton(\"No\", new DialogInterface.OnClickListener() {\n            @Override\n            public void onClick(DialogInterface dialog, int which) {\n                // Perform inbuilt functions\n            }\n        });\n\n        alertDgBuilder.create().show();\n    }\n\n    @Override\n    public void onRequestPermissionsResult(int requestCode,\n                                           @NonNull String permissions[], @NonNull int[] grantResults) {\n        switch (requestCode) {\n            case PERMISSION_CODE:\n                if (grantResults.length > 0\n                        && grantResults[0] == PackageManager.PERMISSION_GRANTED) {\n                    try {\n                        exportImage();\n                    } catch (IOException e) {\n                        Toast.makeText(MainActivity.this,\n                                \"Storage access failed!\",Toast.LENGTH_LONG).show();\n                    }\n                } else {\n                    Toast.makeText(this, \"Storage access failed, check permission\",\n                            Toast.LENGTH_LONG).show();\n                }\n                break;\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/res/drawable/color_picked_imageview_border.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <stroke android:width=\"2dp\" android:color=\"#bdbdbd\"/>\n    <padding android:left=\"1dp\" android:top=\"1dp\" android:right=\"1dp\" android:bottom=\"1dp\"/>\n</shape>\n"
  },
  {
    "path": "app/src/main/res/drawable/ok_icon.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:height=\"48dp\"\n    android:width=\"48dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\">\n    <path android:fillColor=\"#fff\" android:pathData=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/palette_icon.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:height=\"48dp\"\n    android:width=\"48dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\">\n    <path android:fillColor=\"#efeaeaea\" android:pathData=\"M17.5,12A1.5,1.5 0 0,1 16,10.5A1.5,1.5 0 0,1 17.5,9A1.5,1.5 0 0,1 19,10.5A1.5,1.5 0 0,1 17.5,12M14.5,8A1.5,1.5 0 0,1 13,6.5A1.5,1.5 0 0,1 14.5,5A1.5,1.5 0 0,1 16,6.5A1.5,1.5 0 0,1 14.5,8M9.5,8A1.5,1.5 0 0,1 8,6.5A1.5,1.5 0 0,1 9.5,5A1.5,1.5 0 0,1 11,6.5A1.5,1.5 0 0,1 9.5,8M6.5,12A1.5,1.5 0 0,1 5,10.5A1.5,1.5 0 0,1 6.5,9A1.5,1.5 0 0,1 8,10.5A1.5,1.5 0 0,1 6.5,12M12,3A9,9 0 0,0 3,12A9,9 0 0,0 12,21A1.5,1.5 0 0,0 13.5,19.5C13.5,19.11 13.35,18.76 13.11,18.5C12.88,18.23 12.73,17.88 12.73,17.5A1.5,1.5 0 0,1 14.23,16H16A5,5 0 0,0 21,11C21,6.58 16.97,3 12,3Z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/layout/activity_about.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:fancy=\"http://schemas.android.com/apk/res-auto\"\n    android:theme=\"@android:style/Theme.Holo.NoActionBar\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"#FFF\"\n    android:clipToPadding=\"false\">\n\n    <com.sdsmdg.kd.trianglify.views.TrianglifyView\n        android:id=\"@+id/trianglify_main_view\"\n        android:layout_centerHorizontal=\"true\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        app:cellSize=\"50dp\"\n        app:variance=\"5dp\"\n        app:bleedX=\"50dp\"\n        app:bleedY=\"50dp\"\n        app:gridType=\"rectangle\"\n        app:palette=\"PuBu\"\n        app:fillStrokes=\"true\"\n        app:fillTriangle=\"true\"\n        />\n    <ScrollView\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:layout_marginTop=\"32dp\"\n        android:layout_alignParentTop=\"true\">\n        <RelativeLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\">\n\n\n\n            <ImageView\n                android:id=\"@+id/about_mdg_logo\"\n                android:layout_marginTop=\"32dp\"\n                android:layout_width=\"175dp\"\n                android:layout_height=\"175dp\"\n                android:layout_centerHorizontal=\"true\"\n                android:src=\"@drawable/web_hi_res_512\" />\n            <TextView\n                android:id=\"@+id/about_trianglify_title\"\n                android:layout_below=\"@id/about_mdg_logo\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_centerHorizontal=\"true\"\n                android:layout_marginTop=\"12dp\"\n                android:text=\"Trianglify\"\n                android:textSize=\"18sp\"\n                android:textAlignment=\"center\"\n                android:textColor=\"#FFF\"/>\n\n            <TextView\n                android:id=\"@+id/about_version_text\"\n                android:layout_below=\"@id/about_trianglify_title\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_centerHorizontal=\"true\"\n                android:layout_marginBottom=\"8dp\"\n                android:text=\"Version 1.1.0\"\n                android:textSize=\"11sp\"\n                android:textAlignment=\"center\"\n                android:textColor=\"#FFF\"/>\n\n            <TextView\n                android:id=\"@+id/about_brought_by\"\n                android:layout_below=\"@id/about_version_text\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_centerHorizontal=\"true\"\n                android:layout_marginBottom=\"8dp\"\n                android:layout_marginTop=\"64dp\"\n                android:text=\"developed by\"\n                android:textSize=\"12sp\"\n                android:textStyle=\"italic\"\n                android:textAlignment=\"center\"\n                android:textColor=\"#FFF\"/>\n\n            <ImageView\n                android:id=\"@+id/about_trianglify_logo\"\n                android:layout_below=\"@id/about_brought_by\"\n                android:layout_width=\"140dp\"\n                android:layout_height=\"70dp\"\n                android:layout_centerHorizontal=\"true\"\n                android:src=\"@drawable/logo_mdg\"\n                android:scaleType=\"centerInside\"\n                />\n\n\n            <TextView\n                android:id=\"@+id/about_text\"\n                android:layout_below=\"@id/about_trianglify_logo\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_centerHorizontal=\"true\"\n                android:layout_marginBottom=\"16dp\"\n                android:layout_marginLeft=\"32dp\"\n                android:layout_marginRight=\"32dp\"\n                android:layout_marginTop=\"8dp\"\n                android:text=\"@string/mdg_description\"\n                android:textAlignment=\"center\"\n                android:textColor=\"#FFF\"\n                android:textSize=\"12dp\" />\n\n\n            <ImageView\n                android:id=\"@+id/about_github_link\"\n                android:layout_width=\"50dp\"\n                android:layout_height=\"50dp\"\n                android:src=\"@drawable/ic_github\"\n                android:layout_below=\"@+id/about_text\"\n                android:layout_marginBottom=\"12dp\"\n                android:layout_marginRight=\"4dp\"\n                android:layout_toLeftOf=\"@+id/about_rate_link\"\n                android:padding=\"2dp\"\n                />\n            <ImageView\n                android:id=\"@+id/about_rate_link\"\n                android:layout_width=\"50dp\"\n                android:layout_height=\"50dp\"\n                android:src=\"@drawable/ic_rate_play\"\n                android:layout_below=\"@+id/about_text\"\n                android:layout_marginBottom=\"12dp\"\n                android:layout_centerHorizontal=\"true\"\n                android:padding=\"8dp\"\n                />\n            <ImageView\n                android:id=\"@+id/about_share_link\"\n                android:layout_toRightOf=\"@id/about_rate_link\"\n                android:layout_width=\"50dp\"\n                android:layout_height=\"50dp\"\n                android:layout_marginLeft=\"4dp\"\n                android:src=\"@drawable/ic_share_app\"\n                android:layout_below=\"@+id/about_text\"\n                android:layout_marginBottom=\"12dp\"\n                android:padding=\"10dp\"\n                />\n\n            <TextView\n                android:id=\"@+id/about_license_text\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_centerHorizontal=\"true\"\n                android:layout_marginTop=\"0dp\"\n                android:layout_marginBottom=\"32dp\"\n                android:text=\"View license\"\n                android:textAlignment=\"center\"\n                android:textColor=\"@color/colorAccent\"\n                android:autoLink=\"web\"\n                android:clickable=\"true\"\n                android:layout_below=\"@+id/about_share_link\"\n                android:textSize=\"14sp\"\n                />\n        </RelativeLayout>\n    </ScrollView>\n</RelativeLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/activity_custom_palette_picker.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:id=\"@+id/activity_custom_palette_picker\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    tools:context=\"com.sdsmdg.kd.trianglifyexample.CustomPalettePickerActivity\">\n\n    <com.sdsmdg.kd.trianglify.views.TrianglifyView\n        android:id=\"@+id/trianglify_custom_palette_view\"\n        android:layout_centerHorizontal=\"true\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        app:cellSize=\"30dp\"\n        app:variance=\"5dp\"\n        app:bleedX=\"50dp\"\n        app:bleedY=\"50dp\"\n        app:palette=\"RdBu\"\n        app:gridType=\"rectangle\"\n        app:fillStrokes=\"true\"\n        app:fillTriangle=\"true\"\n        app:randomColoring=\"false\"\n        />\n    <RelativeLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:layout_marginTop=\"?android:attr/actionBarSize\">\n        <ImageView\n            android:id=\"@+id/custom_palette_c0\"\n            android:layout_width=\"40dp\"\n            android:layout_height=\"40dp\"\n            android:background=\"#ffffff\"\n            android:layout_marginLeft = \"16dp\"\n            android:layout_marginTop=\"32dp\"\n            android:clickable=\"true\"\n            android:src=\"@drawable/color_picked_imageview_border\"\n            />\n\n        <ImageView\n            android:id=\"@+id/custom_palette_c1\"\n            android:layout_width=\"40dp\"\n            android:layout_height=\"40dp\"\n            android:background=\"#ffffff\"\n            android:layout_margin =\"32dp\"\n            android:layout_centerHorizontal=\"true\"\n            android:clickable=\"true\"\n            android:src=\"@drawable/color_picked_imageview_border\"\n            />\n\n        <ImageView\n            android:id=\"@+id/custom_palette_c2\"\n            android:layout_width=\"40dp\"\n            android:layout_height=\"40dp\"\n            android:background=\"#ffffff\"\n            android:layout_marginRight = \"16dp\"\n            android:layout_marginTop=\"32dp\"\n            android:layout_alignParentRight=\"true\"\n            android:clickable=\"true\"\n            android:src=\"@drawable/color_picked_imageview_border\"\n            />\n\n        <ImageView\n            android:id=\"@+id/custom_palette_c3\"\n            android:layout_width=\"40dp\"\n            android:layout_height=\"40dp\"\n            android:background=\"#ffffff\"\n            android:layout_margin=\"16dp\"\n            android:layout_alignParentRight=\"true\"\n            android:layout_centerVertical=\"true\"\n            android:clickable=\"true\"\n            android:src=\"@drawable/color_picked_imageview_border\"\n            />\n\n        <ImageView\n            android:id=\"@+id/custom_palette_c4\"\n            android:layout_width=\"40dp\"\n            android:layout_height=\"40dp\"\n            android:background=\"#ffffff\"\n            android:layout_marginRight=\"16dp\"\n            android:layout_marginBottom=\"32dp\"\n            android:layout_alignParentBottom=\"true\"\n            android:layout_alignParentRight=\"true\"\n            android:clickable=\"true\"\n            android:src=\"@drawable/color_picked_imageview_border\"\n            />\n\n        <ImageView\n            android:id=\"@+id/custom_palette_c5\"\n            android:layout_width=\"40dp\"\n            android:layout_height=\"40dp\"\n            android:background=\"#ffffff\"\n            android:layout_marginBottom=\"32dp\"\n            android:layout_alignParentBottom=\"true\"\n            android:layout_centerHorizontal=\"true\"\n            android:clickable=\"true\"\n            android:src=\"@drawable/color_picked_imageview_border\"\n            />\n\n        <ImageView\n            android:id=\"@+id/custom_palette_c6\"\n            android:layout_width=\"40dp\"\n            android:layout_height=\"40dp\"\n            android:background=\"#ffffff\"\n            android:layout_marginLeft=\"16dp\"\n            android:layout_marginBottom=\"32dp\"\n            android:layout_alignParentBottom=\"true\"\n            android:clickable=\"true\"\n            android:src=\"@drawable/color_picked_imageview_border\"\n            />\n\n        <ImageView\n            android:id=\"@+id/custom_palette_c7\"\n            android:layout_width=\"40dp\"\n            android:layout_height=\"40dp\"\n            android:background=\"#ffffff\"\n            android:layout_margin=\"16dp\"\n            android:layout_centerVertical=\"true\"\n            android:clickable=\"true\"\n            android:src=\"@drawable/color_picked_imageview_border\"\n            />\n\n        <ImageView\n            android:id=\"@+id/custom_palette_c8\"\n            android:layout_width=\"40dp\"\n            android:layout_height=\"40dp\"\n            android:background=\"#ffffff\"\n            android:layout_centerInParent=\"true\"\n            android:clickable=\"true\"\n            android:src=\"@drawable/color_picked_imageview_border\"\n            />\n    </RelativeLayout>\n\n</RelativeLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/activity_main.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:id=\"@+id/activity_main\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"#D3D3D3\"\n    tools:context=\"com.sdsmdg.kd.trianglifyexample.MainActivity\">\n    <com.sdsmdg.kd.trianglify.views.TrianglifyView\n        android:id=\"@+id/trianglify_main_view\"\n        android:layout_centerHorizontal=\"true\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        app:cellSize=\"30dp\"\n        app:variance=\"5dp\"\n        app:bleedX=\"75dp\"\n        app:bleedY=\"75dp\"\n        app:gridType=\"rectangle\"\n        app:palette=\"RdBu\"\n        app:fillStrokes=\"true\"\n        app:fillTriangle=\"true\"\n        app:randomColoring=\"false\"\n        />\n\n    <RelativeLayout\n        android:layout_alignParentBottom=\"true\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:elevation=\"10dp\"\n        android:background=\"#84FFFFFF\"\n        android:layout_margin=\"8dp\"\n        android:padding=\"16dp\">\n\n        <TextView\n            android:id=\"@+id/variance_textview\"\n            android:layout_width=\"72dp\"\n            android:text=\"Variance: \"\n            android:textColor=\"#212121\"\n            android:layout_margin=\"4dp\"\n            android:layout_height=\"wrap_content\" />\n\n        <SeekBar\n            android:id=\"@+id/variance_seekbar\"\n            android:layout_alignParentRight=\"true\"\n            android:layout_toRightOf=\"@id/variance_textview\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginTop=\"2dp\"\n            />\n\n        <TextView\n            android:id=\"@+id/cell_size_textview\"\n            android:layout_below=\"@id/variance_textview\"\n            android:layout_width=\"72dp\"\n            android:textColor=\"#212121\"\n            android:layout_margin=\"4dp\"\n            android:text=\"Cell Size: \"\n            android:layout_height=\"wrap_content\" />\n\n        <SeekBar\n            android:id=\"@+id/cell_size_seekbar\"\n            android:layout_toRightOf=\"@id/cell_size_textview\"\n            android:layout_below=\"@+id/variance_textview\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginTop=\"2dp\"\n            />\n\n        <TextView\n            android:id=\"@+id/palette_textview\"\n            android:layout_below=\"@id/cell_size_textview\"\n            android:layout_width=\"72dp\"\n            android:textColor=\"#212121\"\n            android:layout_margin=\"4dp\"\n            android:text=\"Palette: \"\n            android:layout_height=\"wrap_content\" />\n\n        <SeekBar\n            android:id=\"@+id/palette_seekbar\"\n            android:layout_toRightOf=\"@id/palette_textview\"\n            android:layout_below=\"@+id/cell_size_textview\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginTop=\"2dp\"\n            />\n\n        <RelativeLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_below=\"@id/palette_textview\"\n            android:layout_marginTop=\"4dp\"\n            >\n\n            <View\n                android:id=\"@+id/layout_middle_point\"\n                android:layout_width=\"0dp\"\n                android:layout_height=\"0dp\"\n                android:layout_centerInParent=\"true\"\n                />\n\n            <CheckBox\n                android:id=\"@+id/random_coloring_checkbox\"\n                android:layout_toRightOf=\"@id/layout_middle_point\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"Random Coloring\"\n                android:checked=\"false\"\n                />\n\n            <CheckBox\n                android:id=\"@+id/custom_palette_checkbox\"\n                android:layout_toLeftOf=\"@id/layout_middle_point\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"Custom Palette\"\n                />\n\n            <CheckBox\n                android:id=\"@+id/draw_stroke_checkbox\"\n                android:layout_below=\"@id/custom_palette_checkbox\"\n                android:layout_toLeftOf=\"@id/layout_middle_point\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"Draw Strokes\"\n                />\n\n            <CheckBox\n                android:id=\"@+id/draw_fill_checkbox\"\n                android:layout_below=\"@id/random_coloring_checkbox\"\n                android:layout_toRightOf=\"@id/layout_middle_point\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"Fill Triangles\"\n                />\n\n        </RelativeLayout>\n\n    </RelativeLayout>\n\n</RelativeLayout>\n"
  },
  {
    "path": "app/src/main/res/menu/menu.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n\n    <item\n        android:id=\"@+id/action_refresh\"\n        android:orderInCategory=\"100\"\n        app:showAsAction=\"ifRoom\"\n        android:icon=\"@drawable/ic_refresh\"\n        android:title=\"@string/menu_refresh\"/>\n    <item\n        android:id=\"@+id/action_set_wall\"\n        android:orderInCategory=\"100\"\n        android:icon=\"@drawable/ic_about_icon\"\n        android:title=\"@string/menu_set_as_wallpaper\"/>\n    <item\n        android:id=\"@+id/action_save\"\n        android:orderInCategory=\"100\"\n        android:icon=\"@drawable/ic_action_save\"\n        android:title=\"@string/menu_save\"/>\n    <item\n        android:id=\"@+id/custom_palette_picker\"\n        android:orderInCategory=\"100\"\n        app:showAsAction=\"ifRoom\"\n        android:icon=\"@drawable/palette_icon\"\n        android:title=\"@string/menu_custom_color\"/>\n    <item\n        android:id=\"@+id/action_about\"\n        android:orderInCategory=\"100\"\n        android:icon=\"@drawable/ic_about_icon\"\n        android:title=\"@string/menu_about\"/>\n\n</menu>\n\n"
  },
  {
    "path": "app/src/main/res/menu/menu_custom_palette_picker.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<menu\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n\n    <item\n        android:id=\"@+id/custom_palette_ok\"\n        android:orderInCategory=\"100\"\n        app:showAsAction=\"always\"\n        android:icon=\"@drawable/ok_icon\"\n        android:title=\"OK\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        />\n\n</menu>\n"
  },
  {
    "path": "app/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"colorPrimary\">#009688</color>\n    <color name=\"colorPrimaryDark\">#00796B</color>\n    <color name=\"colorAccent\">#3F51B5</color>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values/dimens.xml",
    "content": "<resources>\n    <!-- Default screen margins, per the Android Design guidelines. -->\n    <dimen name=\"activity_horizontal_margin\">16dp</dimen>\n    <dimen name=\"activity_vertical_margin\">16dp</dimen>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">Trianglify Demo</string>\n\n\n    <!-- About Fragment strings -->\n    <string name=\"mdg_description\">A place where \\nIdeas meet reality!</string>\n    <string name=\"share_application_text\">Check out trianglify a library to generate beautiful view for Android. Link: </string>\n    <string name=\"trianglify_store_short_link\">http://bit.ly/trianglifyDemo</string>\n    <string name=\"license_text\">Trianglify library and all related material are distributed under \\'MIT license\\' a copy of which can be obtained from link provided.</string>\n    <string name=\"license_link\">https://github.com/sdsmdg/trianglify/blob/develop/LICENSE.md</string>\n\n    <!-- Main Activity overflow menu strings -->\n    <string name=\"menu_save\">Save</string>\n    <string name=\"menu_refresh\">Refresh</string>\n    <string name=\"menu_custom_color\">Customize colors</string>\n    <string name=\"menu_about\">About</string>\n    <string name=\"menu_set_as_wallpaper\">Set as wallpaper</string>\n\n    <!-- Main Activity strings -->\n    <string name=\"wall_alert_dg_text\">Set current art as wallpaper?</string>\n    <string name=\"palette_color_array\">Palette Color Array</string>\n\n    <!-- About Activity strings -->\n    <string name=\"about_activity_title\">About</string>\n    <string name=\"about_activity_version\">Version</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values/styles.xml",
    "content": "<resources>\n\n    <!-- Base application theme. -->\n    <style name=\"AppTheme\" parent=\"Theme.AppCompat.Light.DarkActionBar\">\n        <!-- Customize your theme here. -->\n        <item name=\"colorPrimary\">@color/colorPrimary</item>\n        <item name=\"colorPrimaryDark\">@color/colorPrimaryDark</item>\n        <item name=\"colorAccent\">@color/colorAccent</item>\n        <item name=\"android:windowActionBarOverlay\">true</item>\n        <item name=\"windowActionBarOverlay\">true</item>\n    </style>\n\n    <style name=\"AppTheme.NoActionBar\" parent=\"Theme.AppCompat.Light.DarkActionBar\">\n        <item name=\"windowActionBar\">false</item>\n        <item name=\"windowNoTitle\">true</item>\n        <item name=\"android:windowFullscreen\">true</item>\n    </style>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-w820dp/dimens.xml",
    "content": "<resources>\n    <!-- Example customization of dimensions originally defined in res/values/dimens.xml\n         (such as screen margins) for screens with more than 820dp of available width. This\n         would include 7\" and 10\" devices in landscape (~960dp and ~1280dp respectively). -->\n    <dimen name=\"activity_horizontal_margin\">64dp</dimen>\n</resources>\n"
  },
  {
    "path": "app/src/test/java/com/sdsmdg/kd/trianglifyexample/ExampleUnitTest.java",
    "content": "package com.sdsmdg.kd.trianglifyexample;\n\nimport org.junit.Test;\n\nimport static org.junit.Assert.*;\n\n/**\n * Example local unit test, which will execute on the development machine (host).\n *\n * @see <a href=\"http://d.android.com/tools/testing\">Testing documentation</a>\n */\npublic class ExampleUnitTest {\n    @Test\n    public void addition_isCorrect() throws Exception {\n        assertEquals(4, 2 + 2);\n    }\n}"
  },
  {
    "path": "build.gradle",
    "content": "// Top-level build file where you can add configuration options common to all sub-projects/modules.\n\nbuildscript {\n    repositories {\n        jcenter()\n        google()\n    }\n    dependencies {\n        classpath 'com.android.tools.build:gradle:3.0.1'\n        classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.4'\n        classpath 'com.github.dcendents:android-maven-gradle-plugin:1.4.1'\n\n        // NOTE: Do not place your application dependencies here; they belong\n        // in the individual module build.gradle files\n    }\n}\n\nallprojects {\n    repositories {\n        jcenter()\n        maven { url \"https://jitpack.io\" }\n        google()\n    }\n}\n\ntask clean(type: Delete) {\n    delete rootProject.buildDir\n}\n\nsubprojects {\n    tasks.withType(Javadoc).all { enabled = false }\n}\n\n"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "content": "#Wed Feb 07 13:07:53 IST 2018\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-4.1-all.zip\n"
  },
  {
    "path": "gradle.properties",
    "content": "# Project-wide Gradle settings.\n\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will override*\n# any settings specified in this file.\n\n# For more details on how to configure your build environment visit\n# http://www.gradle.org/docs/current/userguide/build_environment.html\n\n# Specifies the JVM arguments used for the daemon process.\n# The setting is particularly useful for tweaking memory settings.\norg.gradle.jvmargs=-Xmx1536m\n\n# When configured, Gradle will run in incubating parallel mode.\n# This option should only be used with decoupled projects. More details, visit\n# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects\n# org.gradle.parallel=true\n"
  },
  {
    "path": "gradlew",
    "content": "#!/usr/bin/env bash\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS=\"\"\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn ( ) {\n    echo \"$*\"\n}\n\ndie ( ) {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\nesac\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/\" >/dev/null\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >/dev/null\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n        JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=\"java\"\n    which java >/dev/null 2>&1 || die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"$cygwin\" = \"false\" -a \"$darwin\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ $? -eq 0 ] ; then\n        if [ \"$MAX_FD\" = \"maximum\" -o \"$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"$MAX_FD_LIMIT\"\n        fi\n        ulimit -n $MAX_FD\n        if [ $? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: $MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif $darwin; then\n    GRADLE_OPTS=\"$GRADLE_OPTS \\\"-Xdock:name=$APP_NAME\\\" \\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\"\"\nfi\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n    JAVACMD=`cygpath --unix \"$JAVACMD\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=$((i+1))\n    done\n    case $i in\n        (0) set -- ;;\n        (1) set -- \"$args0\" ;;\n        (2) set -- \"$args0\" \"$args1\" ;;\n        (3) set -- \"$args0\" \"$args1\" \"$args2\" ;;\n        (4) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" ;;\n        (5) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" ;;\n        (6) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" ;;\n        (7) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" ;;\n        (8) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" ;;\n        (9) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" \"$args8\" ;;\n    esac\nfi\n\n# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules\nfunction splitJvmOpts() {\n    JVM_OPTS=(\"$@\")\n}\neval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS\nJVM_OPTS[${#JVM_OPTS[*]}]=\"-Dorg.gradle.appname=$APP_BASE_NAME\"\n\nexec \"$JAVACMD\" \"${JVM_OPTS[@]}\" -classpath \"$CLASSPATH\" org.gradle.wrapper.GradleWrapperMain \"$@\"\n"
  },
  {
    "path": "gradlew.bat",
    "content": "@if \"%DEBUG%\" == \"\" @echo off\r\n@rem ##########################################################################\r\n@rem\r\n@rem  Gradle startup script for Windows\r\n@rem\r\n@rem ##########################################################################\r\n\r\n@rem Set local scope for the variables with windows NT shell\r\nif \"%OS%\"==\"Windows_NT\" setlocal\r\n\r\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\r\nset DEFAULT_JVM_OPTS=\r\n\r\nset DIRNAME=%~dp0\r\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\r\nset APP_BASE_NAME=%~n0\r\nset APP_HOME=%DIRNAME%\r\n\r\n@rem Find java.exe\r\nif defined JAVA_HOME goto findJavaFromJavaHome\r\n\r\nset JAVA_EXE=java.exe\r\n%JAVA_EXE% -version >NUL 2>&1\r\nif \"%ERRORLEVEL%\" == \"0\" goto init\r\n\r\necho.\r\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:findJavaFromJavaHome\r\nset JAVA_HOME=%JAVA_HOME:\"=%\r\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\r\n\r\nif exist \"%JAVA_EXE%\" goto init\r\n\r\necho.\r\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:init\r\n@rem Get command-line arguments, handling Windowz variants\r\n\r\nif not \"%OS%\" == \"Windows_NT\" goto win9xME_args\r\nif \"%@eval[2+2]\" == \"4\" goto 4NT_args\r\n\r\n:win9xME_args\r\n@rem Slurp the command line arguments.\r\nset CMD_LINE_ARGS=\r\nset _SKIP=2\r\n\r\n:win9xME_args_slurp\r\nif \"x%~1\" == \"x\" goto execute\r\n\r\nset CMD_LINE_ARGS=%*\r\ngoto execute\r\n\r\n:4NT_args\r\n@rem Get arguments from the 4NT Shell from JP Software\r\nset CMD_LINE_ARGS=%$\r\n\r\n:execute\r\n@rem Setup the command line\r\n\r\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\r\n\r\n@rem Execute Gradle\r\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%\r\n\r\n:end\r\n@rem End local scope for the variables with windows NT shell\r\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\r\n\r\n:fail\r\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\r\nrem the _cmd.exe /c_ return code!\r\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\r\nexit /b 1\r\n\r\n:mainEnd\r\nif \"%OS%\"==\"Windows_NT\" endlocal\r\n\r\n:omega\r\n"
  },
  {
    "path": "resources/tables/palette-methods-table.tgn",
    "content": "{\"rows_views\":[[{\"style\":{\"borders\":\"\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"middle\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"middle\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"middle\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}}],[{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}}],[{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}}],[{\"style\":{\"borders\":\"\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"middle\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"middle\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"middle\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}}],[{\"style\":{\"borders\":\"\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"middle\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"middle\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"middle\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}}],[{\"style\":{\"borders\":\"\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"middle\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"middle\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"middle\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}}]],\"model\":{\"rows\":[[{\"value\":\"Method\",\"cspan\":1,\"rspan\":1},{\"value\":\"Return Type\\n\",\"cspan\":1,\"rspan\":1},{\"value\":\"Type\\n\",\"cspan\":1,\"rspan\":1},{\"value\":\"Parameters\",\"cspan\":1,\"rspan\":1},{\"value\":\"Description\",\"cspan\":1,\"rspan\":1}],[{\"value\":\"Constructor\",\"cspan\":1,\"rspan\":1},{\"value\":\"-\",\"cspan\":1,\"rspan\":1},{\"value\":\"Constructor\",\"cspan\":1,\"rspan\":1},{\"value\":\"int c0, int c1, int c2, int c3, int c4, int c5, int c6, int c7, int c8\",\"cspan\":1,\"rspan\":1},{\"value\":\"Takes eight parameters as colors to construct palette\\n\",\"cspan\":1,\"rspan\":1}],[{\"value\":\"Constructor\",\"cspan\":1,\"rspan\":1},{\"value\":\"-\",\"cspan\":1,\"rspan\":1},{\"value\":\"Constructor\",\"cspan\":1,\"rspan\":1},{\"value\":\"int[] colors\",\"cspan\":1,\"rspan\":1},{\"value\":\"Takes eight parameters as an array of colors to construct palette\",\"cspan\":1,\"rspan\":1}],[{\"value\":\"getPalette\",\"cspan\":1,\"rspan\":1},{\"value\":\"Palette\",\"cspan\":1,\"rspan\":1},{\"value\":\"static\",\"cspan\":1,\"rspan\":1},{\"value\":\"int paletteIndex\\n\",\"cspan\":1,\"rspan\":1},{\"value\":\"Returns palette object corresponding to supplied value of paletteIndex, palette is constructed from a predefined set of colors.\",\"cspan\":1,\"rspan\":1}],[{\"value\":\"indexOf\",\"cspan\":1,\"rspan\":1},{\"value\":\"int\",\"cspan\":1,\"rspan\":1},{\"value\":\"static\",\"cspan\":1,\"rspan\":1},{\"value\":\"Palette palette\",\"cspan\":1,\"rspan\":1},{\"value\":\"Returns index of palette object in predefined palette, -1 if doesn't exists\\n\",\"cspan\":1,\"rspan\":1}],[{\"value\":\"\",\"cspan\":1,\"rspan\":1},{\"value\":\"int\",\"cspan\":1,\"rspan\":1},{\"value\":\"-\\n\",\"cspan\":1,\"rspan\":1},{\"value\":\"int index\",\"cspan\":1,\"rspan\":1},{\"value\":\"Returns color corresponding to index passed from the set of color for a palette\",\"cspan\":1,\"rspan\":1}]]},\"theme\":null,\"fixed_layout\":false}"
  },
  {
    "path": "resources/tables/trianglify-view-attributes-table.tgn",
    "content": "{\"rows_views\":[[{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}}],[{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}}],[{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}}],[{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}}],[{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}}],[{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}}],[{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}}],[{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}}],[{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}}],[{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}}],[{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}}],[{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}}],[{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}},{\"style\":{\"borders\":\"lrtb\",\"font_style\":{},\"text_color\":\"\",\"bg_color\":\"\",\"halign\":\"left\",\"valign\":\"top\",\"padding\":{\"top\":10,\"right\":5,\"bottom\":10,\"left\":5}}}]],\"model\":{\"rows\":[[{\"value\":\"Property\",\"cspan\":1,\"rspan\":1},{\"value\":\"Default values\\n\",\"cspan\":1,\"rspan\":1},{\"value\":\"Java method\\n\",\"cspan\":1,\"rspan\":1},{\"value\":\"Attribute\\n\",\"cspan\":1,\"rspan\":1},{\"value\":\"Description\",\"cspan\":1,\"rspan\":1}],[{\"value\":\"Grid Height\\n\",\"cspan\":1,\"rspan\":1},{\"value\":\"NA\",\"cspan\":1,\"rspan\":1},{\"value\":\".setGridHeight(...)\",\"cspan\":1,\"rspan\":1},{\"value\":\"grid_height\",\"cspan\":1,\"rspan\":1},{\"value\":\"Height of the grid to generate\",\"cspan\":1,\"rspan\":1}],[{\"value\":\"Grid Width\\n\",\"cspan\":1,\"rspan\":1},{\"value\":\"NA\",\"cspan\":1,\"rspan\":1},{\"value\":\".setGridWidth(...)\",\"cspan\":1,\"rspan\":1},{\"value\":\"grid_width\\n\",\"cspan\":1,\"rspan\":1},{\"value\":\"Width of the grid to generate\",\"cspan\":1,\"rspan\":1}],[{\"value\":\"X-axis Bleed\\n\",\"cspan\":1,\"rspan\":1},{\"value\":\"0\",\"cspan\":1,\"rspan\":1},{\"value\":\".setBleedX(...)\",\"cspan\":1,\"rspan\":1},{\"value\":\"bleed_x\",\"cspan\":1,\"rspan\":1},{\"value\":\"TrianglifyView generates total area having width = gridWidth + 2*bleedX to avoid unfilled triangles at the edges of the view\",\"cspan\":1,\"rspan\":1}],[{\"value\":\"Y-Axis Bleed\\n\",\"cspan\":1,\"rspan\":1},{\"value\":\"0 \\n\",\"cspan\":1,\"rspan\":1},{\"value\":\".setBleedY(...)\",\"cspan\":1,\"rspan\":1},{\"value\":\"bleed_y\",\"cspan\":1,\"rspan\":1},{\"value\":\"TrianglifyView generates total area having height = gridWidth + 2*bleedY to avoid unfilled triangles at the edges of the view\",\"cspan\":1,\"rspan\":1}],[{\"value\":\"Variance\",\"cspan\":1,\"rspan\":1},{\"value\":\"10 px\\n\",\"cspan\":1,\"rspan\":1},{\"value\":\".setVariance(...)\",\"cspan\":1,\"rspan\":1},{\"value\":\"variance\\n\",\"cspan\":1,\"rspan\":1},{\"value\":\"Displacement of points from original grid position to create triangles of different sizes\",\"cspan\":1,\"rspan\":1}],[{\"value\":\"Cell Size\\n\",\"cspan\":1,\"rspan\":1},{\"value\":\"40 px\",\"cspan\":1,\"rspan\":1},{\"value\":\".setCellSize(...)\",\"cspan\":1,\"rspan\":1},{\"value\":\"cell_size\\n\",\"cspan\":1,\"rspan\":1},{\"value\":\"Size of cells of rectangular grid used to generated vertices of the triangles\",\"cspan\":1,\"rspan\":1}],[{\"value\":\"Grid Type*\\n\",\"cspan\":1,\"rspan\":1},{\"value\":\"0\",\"cspan\":1,\"rspan\":1},{\"value\":\".setGridType(...)\",\"cspan\":1,\"rspan\":1},{\"value\":\"grid_type\\n\",\"cspan\":1,\"rspan\":1},{\"value\":\"Type of grid 0 for Rectangular\",\"cspan\":1,\"rspan\":1}],[{\"value\":\"Fill Triangles with color**\\n\",\"cspan\":1,\"rspan\":1},{\"value\":\"true\\n\",\"cspan\":1,\"rspan\":1},{\"value\":\".setFillTriangle(...)\",\"cspan\":1,\"rspan\":1},{\"value\":\"fill_triangles\",\"cspan\":1,\"rspan\":1},{\"value\":\"Fills the triangle generated with color chosen\",\"cspan\":1,\"rspan\":1}],[{\"value\":\"Draw strokes\\n\",\"cspan\":1,\"rspan\":1},{\"value\":\"false\",\"cspan\":1,\"rspan\":1},{\"value\":\".setDrawStrokes(...)\",\"cspan\":1,\"rspan\":1},{\"value\":\"draw_strokes\",\"cspan\":1,\"rspan\":1},{\"value\":\"Draws triangle's border with neighboring triangle's color\",\"cspan\":1,\"rspan\":1}],[{\"value\":\"Color Palette\\n\",\"cspan\":1,\"rspan\":1},{\"value\":\"YlGn\",\"cspan\":1,\"rspan\":1},{\"value\":\".setPalette(...)\",\"cspan\":1,\"rspan\":1},{\"value\":\"palette\",\"cspan\":1,\"rspan\":1},{\"value\":\"Set of existing colors to color triangles\",\"cspan\":1,\"rspan\":1}],[{\"value\":\"Random Coloring\\n\",\"cspan\":1,\"rspan\":1},{\"value\":\"false\",\"cspan\":1,\"rspan\":1},{\"value\":\".setRandomColoring(...)\",\"cspan\":1,\"rspan\":1},{\"value\":\"random_coloring\",\"cspan\":1,\"rspan\":1},{\"value\":\"If random coloring is on triangles will be colored randomly instead of linear interpolation\",\"cspan\":1,\"rspan\":1}],[{\"value\":\"\",\"cspan\":1,\"rspan\":1},{\"value\":\"\",\"cspan\":1,\"rspan\":1},{\"value\":\"\",\"cspan\":1,\"rspan\":1},{\"value\":\"\",\"cspan\":1,\"rspan\":1},{\"value\":\"\",\"cspan\":1,\"rspan\":1}]]},\"theme\":null,\"fixed_layout\":false}"
  },
  {
    "path": "settings.gradle",
    "content": "include ':app', ':trianglify'\n"
  },
  {
    "path": "trianglify/.classpath",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<classpath>\n\t<classpathentry kind=\"con\" path=\"org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8/\"/>\n\t<classpathentry kind=\"con\" path=\"org.eclipse.buildship.core.gradleclasspathcontainer\"/>\n\t<classpathentry kind=\"output\" path=\"bin\"/>\n</classpath>\n"
  },
  {
    "path": "trianglify/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "trianglify/.project",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<projectDescription>\n\t<name>trianglify-trianglify</name>\n\t<comment>Project trianglify-trianglify created by Buildship.</comment>\n\t<projects>\n\t</projects>\n\t<buildSpec>\n\t\t<buildCommand>\n\t\t\t<name>org.eclipse.jdt.core.javabuilder</name>\n\t\t\t<arguments>\n\t\t\t</arguments>\n\t\t</buildCommand>\n\t\t<buildCommand>\n\t\t\t<name>org.eclipse.buildship.core.gradleprojectbuilder</name>\n\t\t\t<arguments>\n\t\t\t</arguments>\n\t\t</buildCommand>\n\t</buildSpec>\n\t<natures>\n\t\t<nature>org.eclipse.jdt.core.javanature</nature>\n\t\t<nature>org.eclipse.buildship.core.gradleprojectnature</nature>\n\t</natures>\n</projectDescription>\n"
  },
  {
    "path": "trianglify/.settings/org.eclipse.buildship.core.prefs",
    "content": "connection.gradle.distribution=GRADLE_DISTRIBUTION(WRAPPER)\nconnection.project.dir=..\neclipse.preferences.version=1\n"
  },
  {
    "path": "trianglify/build.gradle",
    "content": "apply plugin: 'com.android.library'\n\next {\n\n    bintrayRepo = 'trianglify'\n    bintrayName = 'trianglify'   // Has to be same as library module name\n\n    PUBLISH_GROUP_ID = 'com.sdsmdg.kd'\n    PUBLISH_ARTIFACT_ID = 'trianglify'\n    PUBLISH_VERSION = '1.0.0'\n\n    publishedGroupId = 'com.sdsmdg.kd'\n    libraryName = 'trianglify'\n    artifact = 'trianglify'     // Has to be same as library module name\n\n    siteUrl = 'https://github.com/sdsmdg/trianglify'\n    gitUrl = 'https://github.com/sdsmdg/trianglify.git'\n    githubRepository= 'sdsmdg/trianglify'\n\n    libraryVersion = '1.0.0'\n    libraryDescription = 'Generate beautiful view for android.'\n\n    developerId = 'sdsmdg'\n    developerName = 'SDS, MDG'\n    developerEmail = 'sdsmdg@gmail.com'\n\n    licenseName = 'MIT License'\n    licenseUrl = 'https://github.com/sdsmdg/trianglify/blob/develop/LICENSE.md'\n    allLicenses = [\"MIT\"]\n}\n\nandroid {\n    compileSdkVersion 27\n    buildToolsVersion '26.0.2'\n\n    defaultConfig {\n        minSdkVersion 16\n        targetSdkVersion 27\n        versionCode 0\n        versionName \"1.0.0\"\n\n        testInstrumentationRunner \"android.support.test.runner.AndroidJUnitRunner\"\n\n    }\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n    lintOptions {\n        abortOnError false\n    }\n}\n\ndependencies {\n    compile fileTree(dir: 'libs', include: ['*.jar'])\n    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {\n        exclude group: 'com.android.support', module: 'support-annotations'\n    })\n    implementation 'com.android.support:appcompat-v7:27.0.2'\n    testCompile 'junit:junit:4.12'\n    testCompile 'org.mockito:mockito-core:2.13.0'\n\n}\n\n//apply from: 'https://raw.githubusercontent.com/nuuneoi/JCenter/master/installv1.gradle'\n//apply from: 'https://raw.githubusercontent.com/nuuneoi/JCenter/master/bintrayv1.gradle'"
  },
  {
    "path": "trianglify/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in /root/Android/Sdk/tools/proguard/proguard-android.txt\n# You can edit the include path and order by changing the proguardFiles\n# directive in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# Add any project specific keep options here:\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n"
  },
  {
    "path": "trianglify/src/androidTest/java/com/sdsmdg/kd/trianglify/ExampleInstrumentedTest.java",
    "content": "package com.sdsmdg.kd.trianglify;\n\nimport android.content.Context;\nimport android.support.test.InstrumentationRegistry;\nimport android.support.test.runner.AndroidJUnit4;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\n\nimport static org.junit.Assert.*;\n\n/**\n * Instrumentation test, which will execute on an Android device.\n *\n * @see <a href=\"http://d.android.com/tools/testing\">Testing documentation</a>\n */\n@RunWith(AndroidJUnit4.class)\npublic class ExampleInstrumentedTest {\n    @Test\n    public void useAppContext() throws Exception {\n        // Context of the app under test.\n        Context appContext = InstrumentationRegistry.getTargetContext();\n\n        assertEquals(\"com.sdsmdg.kd.trianglify.test\", appContext.getPackageName());\n    }\n}\n"
  },
  {
    "path": "trianglify/src/main/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.sdsmdg.kd.trianglify\">\n\n    <application android:label=\"@string/app_name\">\n\n    </application>\n</manifest>\n"
  },
  {
    "path": "trianglify/src/main/java/com/sdsmdg/kd/trianglify/models/Grid.java",
    "content": "package com.sdsmdg.kd.trianglify.models;\n\nimport com.sdsmdg.kd.trianglify.utilities.triangulator.Vector2D;\n\nimport java.util.List;\n\n/**\n * Created by shyam on 12-Mar-17.\n */\n\npublic class Grid {\n    private List<Vector2D> gridPoints;\n\n    public Grid(List<Vector2D> gridPoints) {\n        this.gridPoints = gridPoints;\n    }\n\n    public List<Vector2D> getGridPoints() {\n        return gridPoints;\n    }\n}\n"
  },
  {
    "path": "trianglify/src/main/java/com/sdsmdg/kd/trianglify/models/Palette.java",
    "content": "package com.sdsmdg.kd.trianglify.models;\n\n/**\n * <h1>Palette</h1>\n * <b>Description : </b>\n * Set of 9 colors that are used to color a triangulation. Palette contains few predefined color sets\n * as well as method to perform operations on palette.\n *\n * @author kriti\n * @since 18/3/17.\n */\n\npublic class Palette {\n    public static final int DEFAULT_PALETTE_COUNT = 28;\n\n    private static final int YL_GN = 0;\n    private static final int YL = 1;\n    private static final int YL_GN_BU = 2;\n    private static final int GN_BU = 3;\n    private static final int BU_GN = 4;\n    private static final int PU_BU_GN = 5;\n    private static final int PU_BU = 6;\n    private static final int BU_PU = 7;\n    private static final int RD_PU = 8;\n    private static final int PU_RD = 9;\n    private static final int OR_RD = 10;\n    private static final int YL_OR_RD = 11;\n    private static final int YL_OR_BR = 12;\n    private static final int PURPLES = 13;\n    private static final int BLUES = 14;\n    private static final int GREENS = 15;\n    private static final int ORANGES = 16;\n    private static final int REDS = 17;\n    private static final int GREYS = 18;\n    private static final int PU_OR = 19;\n    private static final int BR_BL = 20;\n    private static final int PU_RD_GN = 21;\n    private static final int PI_YL_GN = 22;\n    private static final int RD_BU = 23;\n    private static final int RD_GY = 24;\n    private static final int RD_YL_BU = 25;\n    private static final int SPECTRAL = 26;\n    private static final int RD_YL_GN = 27;\n\n    private int[] colors;\n\n    public int[] getColors() {\n        return colors;\n    }\n\n    public void setColors(int[] colors) {\n        if (colors.length != 9) {\n            throw new IllegalArgumentException(\"Colors array length should exactly be 9\");\n        }\n        this.colors = colors;\n    }\n\n    /**\n     * Return palette object corresponding to supplied value of paletteIndex, palette is constructed\n     * from a predefined set of colors\n     * @param paletteIndex Index of palette to return\n     * @return Palette object generated from predefined set of colors\n     */\n    public static Palette getPalette(int paletteIndex) {\n        switch (paletteIndex) {\n            case YL:\n                return new Palette(0xffffe0, 0xffffcc, 0xfffacd, 0xffff00, 0xffef00, 0xffd300, 0xf8de7e, 0xffd700, 0xc3b091);\n            case YL_GN:\n                return new Palette(0xffffe5, 0xf7fcb9, 0xd9f0a3, 0xaddd8e, 0x78c679, 0x41ab5d, 0x238443, 0x006837, 0x004529);\n            case YL_GN_BU:\n                return new Palette(0xffffd9, 0xedf8b1, 0xc7e9b4, 0x7fcdbb, 0x41b6c4, 0x1d91c0, 0x225ea8, 0x253494, 0x081d58);\n            case GN_BU:\n                return new Palette(0xf7fcf0, 0xe0f3db, 0xccebc5, 0xa8ddb5, 0x7bccc4, 0x4eb3d3, 0x2b8cbe, 0x0868ac, 0x084081);\n            case BU_GN:\n                return new Palette(0xf7fcfd, 0xe5f5f9, 0xccece6, 0x99d8c9, 0x66c2a4, 0x41ae76, 0x238b45, 0x006d2c, 0x00441c);\n            case PU_BU_GN:\n                return new Palette(0xfff7fb, 0xece2f0, 0xd0d1e6, 0xa6bddb, 0x67a9cf, 0x3690c0, 0x02818a, 0x016c59, 0x014636);\n            case PU_BU:\n                return new Palette(0xfff7fb, 0xece7f2, 0xd0d1e6, 0xa6bddb, 0x74a9cf, 0x3690c0, 0x0570b0, 0x045a8d, 0x023858);\n            case BU_PU:\n                return new Palette(0xf7fcfd, 0xe0ecf4, 0xbfd3e6, 0x9ebcda, 0x8c96c6, 0x8c6bb1, 0x88419d, 0x810f7c, 0x4d004b);\n            case RD_PU:\n                return new Palette(0xfff7f3, 0xfde0dd, 0xfcc5c0, 0xfa9fb5, 0xf768a1, 0xdd3497, 0xae017e, 0x7a0177, 0x49006a);\n            case PU_RD:\n                return new Palette(0xf7f4f9, 0xe7e1ef, 0xd4b9da, 0xc994c7, 0xdf65b0, 0xe7298a, 0xce1256, 0x980043, 0x67001f);\n            case OR_RD:\n                return new Palette(0xfff7ec, 0xfee8c8, 0xfdd49e, 0xfdbb84, 0xfc8d59, 0xef6548, 0xd7301f, 0xb30000, 0x7f0000);\n            case YL_OR_RD:\n                return new Palette(0xffffcc, 0xffeda0, 0xfed976, 0xfeb24c, 0xfd8d3c, 0xfc4e2a, 0xe31a1c, 0xbd0026, 0x800026);\n            case YL_OR_BR:\n                return new Palette(0xffffe5, 0xfff7bc, 0xfee391, 0xfec44f, 0xfe9929, 0xec7014, 0xcc4c02, 0x993404, 0x662506);\n            case PURPLES:\n                return new Palette(0xfcfbfd, 0xefedf5, 0xdadaeb, 0xbcbddc, 0x9e9ac8, 0x807dba, 0x6a51a3, 0x54278f, 0x3f007d);\n            case BLUES:\n                return new Palette(0xf7fbff, 0xdeebf7, 0xc6dbef, 0x9ecae1, 0x6baed6, 0x4292c6, 0x2171b5, 0x08519c, 0x08306b);\n            case GREENS:\n                return new Palette(0xf7fcf5, 0xe5f5e0, 0xc7e9c0, 0xa1d99b, 0x74c476, 0x41ab5d, 0x238b45, 0x006d2c, 0x00441b);\n            case ORANGES:\n                return new Palette(0xfff5eb, 0xfee6ce, 0xfdd0a2, 0xfdae6b, 0xfd8d3c, 0xf16913, 0xd94801, 0xa63603, 0x7f2704);\n            case REDS:\n                return new Palette(0xfff5f0, 0xfee0d2, 0xfcbba1, 0xfc9272, 0xfb6a4a, 0xef3b2c, 0xcb181d, 0xa50f15, 0x67000d);\n            case GREYS:\n                return new Palette(0xffffff, 0xf0f0f0, 0xd9d9d9, 0xbdbdbd, 0x969696, 0x737373, 0x525252, 0x252525, 0x000000);\n            case PU_OR:\n                return new Palette(0x7f3b08, 0xb35806, 0xe08214, 0xfdb863, 0xfee0b6, 0xf7f7f7, 0xd8daeb, 0xb2abd2, 0x8073ac);\n            case BR_BL:\n                return new Palette(0x543005, 0x8c510a, 0xbf812d, 0xdfc27d, 0xf6e8c3, 0xf5f5f5, 0xc7eae5, 0x80cdc1, 0x35978f);\n            case PU_RD_GN:\n                return new Palette(0x40004b, 0x762a83, 0x9970ab, 0xc2a5cf, 0xe7d4e8, 0xf7f7f7, 0xd9f0d3, 0xa6dba0, 0x5aae61);\n            case PI_YL_GN:\n                return new Palette(0x8e0152, 0xc51b7d, 0xde77ae, 0xf1b6da, 0xfde0ef, 0xf7f7f7, 0xe6f5d0, 0xb8e186, 0x7fbc41);\n            case RD_BU:\n                return new Palette(0x67001f, 0xb2182b, 0xd6604d, 0xf4a582, 0xfddbc7, 0xf7f7f7, 0xd1e5f0, 0x92c5de, 0x4393c3);\n            case RD_GY:\n                return new Palette(0x67001f, 0xb2182b, 0xd6604d, 0xf4a582, 0xfddbc7, 0xffffff, 0xe0e0e0, 0xbababa, 0x878787);\n            case RD_YL_BU:\n                return new Palette(0xa50026, 0xd73027, 0xf46d43, 0xfdae61, 0xfee090, 0xffffbf, 0xe0f3f8, 0xabd9e9, 0x74add1);\n            case SPECTRAL:\n                return new Palette(0x9e0142, 0xd53e4f, 0xf46d43, 0xfdae61, 0xfee08b, 0xffffbf, 0xe6f598, 0xabdda4, 0x66c2a5);\n            case RD_YL_GN:\n                return new Palette(0xa50026, 0xd73027, 0xf46d43, 0xfdae61, 0xfee08b, 0xffffbf, 0xd9ef8b, 0xa6d96a, 0x66bd63);\n            default:\n                throw new IllegalArgumentException(\"Index should be less Palette.DEFAULT_PALETTE_COUNT\");\n        }\n    }\n\n    /**\n     * Returns index of palette object passed from list of palettes predefined in Palette\n     * @param palette Object for finding index\n     * @return Index from predefined pallete or -1 if not found\n     */\n    public static int indexOf(Palette palette) {\n        int pos = -1;\n        int[] passedPaletteColors = palette.getColors();\n\n        for (int i = 0; i < Palette.DEFAULT_PALETTE_COUNT; i++) {\n            int[] calledPaletteColors = Palette.getPalette(i).getColors();\n\n            for (int j = 0; j < 9; j++) {\n                if (passedPaletteColors[j] != calledPaletteColors[j]) {\n                    break;\n                }\n\n                if (j == 8) {\n                    return i;\n                }\n            }\n        }\n        return  pos;\n    }\n\n    public Palette(int c0, int c1, int c2, int c3, int c4, int c5, int c6, int c7, int c8) {\n        colors = new int[9];\n        colors[0] = c0;\n        colors[1] = c1;\n        colors[2] = c2;\n        colors[3] = c3;\n        colors[4] = c4;\n        colors[5] = c5;\n        colors[6] = c6;\n        colors[7] = c7;\n        colors[8] = c8;\n    }\n\n    public Palette(int[] colors) {\n        if (colors.length != 9) {\n            throw new IllegalArgumentException(\"Colors array length should exactly be 9\");\n        }\n        this.colors = colors;\n    }\n\n    /**\n     * Returns color corresponding to index passed from the set of color for a palette\n     * @param index Index of color in set of color for current palette object\n     * @return color as int without alpha channel\n     */\n    public int getColor(int index) {\n        switch (index) {\n            case 0:\n                return colors[0];\n            case 1:\n                return colors[1];\n            case 2:\n                return colors[2];\n            case 3:\n                return colors[3];\n            case 4:\n                return colors[4];\n            case 5:\n                return colors[5];\n            case 6:\n                return colors[6];\n            case 7:\n                return colors[7];\n            case 8:\n                return colors[8];\n            default:\n                throw new IllegalArgumentException(\"Index should be less than 9\");\n        }\n    }\n}\n"
  },
  {
    "path": "trianglify/src/main/java/com/sdsmdg/kd/trianglify/models/Triangulation.java",
    "content": "package com.sdsmdg.kd.trianglify.models;\n\nimport com.sdsmdg.kd.trianglify.utilities.triangulator.Triangle2D;\n\nimport java.util.List;\n\n/**\n * Created by shyam on 12-Mar-17.\n */\n\npublic class Triangulation {\n    private List<Triangle2D> triangleList;\n\n    public Triangulation(List<Triangle2D> triangleList) {\n        this.triangleList = triangleList;\n    }\n\n    public List<Triangle2D> getTriangleList() {\n        return triangleList;\n    }\n}\n"
  },
  {
    "path": "trianglify/src/main/java/com/sdsmdg/kd/trianglify/presenters/Presenter.java",
    "content": "package com.sdsmdg.kd.trianglify.presenters;\n\n\nimport android.os.AsyncTask;\n\nimport com.sdsmdg.kd.trianglify.models.Triangulation;\nimport com.sdsmdg.kd.trianglify.utilities.colorizers.Colorizer;\nimport com.sdsmdg.kd.trianglify.utilities.colorizers.FixedPointsColorizer;\nimport com.sdsmdg.kd.trianglify.utilities.patterns.Circle;\nimport com.sdsmdg.kd.trianglify.utilities.patterns.Patterns;\nimport com.sdsmdg.kd.trianglify.utilities.patterns.Rectangle;\nimport com.sdsmdg.kd.trianglify.utilities.triangulator.DelaunayTriangulator;\nimport com.sdsmdg.kd.trianglify.utilities.triangulator.NotEnoughPointsException;\nimport com.sdsmdg.kd.trianglify.utilities.triangulator.Vector2D;\nimport com.sdsmdg.kd.trianglify.views.TrianglifyViewInterface;\n\nimport java.util.List;\n\n/**\n * <h1>Presenter.java</h1>\n * <b>Description :</b>\n * P of MVP implemented to present data generated using models\n * to a view.\n *\n * @author suyash\n * @since 18/3/17.\n */\n\n\npublic class Presenter {\n    private TrianglifyViewInterface view;\n    private Triangulation triangulation;\n    private TriangleGeneratorTask generatorTask;\n\n    /**\n     * Flag for keeping track of changes in attributes of the view. Helpful in increasing\n     * performance by stopping unnecessary regeneration of triangulation. Look at smartUpdate method for more.\n     * if triangulation is null then value is NULL_TRIANGULATION\n     * if triangulation is unchanged then value is UNCHANGED_TRIANGULATION\n     * if change in fillTriangle or drawStroke then value is PAINT_STYLE_CHANGED\n     * if change in grid width, grid height, variance, bleedX, bleedY, typeGrid or cell size then value is GRID_PARAMETERS_CHANGED\n     * if change in palette or random coloring then value is COLOR_SCHEME_CHANGED\n     */\n    public ViewState viewState = ViewState.NULL_TRIANGULATION;\n\n    public enum ViewState {\n        NULL_TRIANGULATION,\n        UNCHANGED_TRIANGULATION,\n        PAINT_STYLE_CHANGED,\n        COLOR_SCHEME_CHANGED,\n        GRID_PARAMETERS_CHANGED\n    }\n\n    /**\n     * flag that keeps track of whether just the color of the triangulation is to be changed or not.\n     */\n    private boolean generateOnlyColor;\n\n    public Presenter(TrianglifyViewInterface view) {\n        this.view = view;\n    }\n\n    public void setGenerateOnlyColor(boolean generateOnlyColor) {\n        this.generateOnlyColor = generateOnlyColor;\n    }\n\n    public void updateView() {\n        viewState = view.getViewState();\n        if (viewState == ViewState.PAINT_STYLE_CHANGED || viewState == ViewState.UNCHANGED_TRIANGULATION) {\n            view.invalidateView(triangulation);\n        } else if (viewState == ViewState.COLOR_SCHEME_CHANGED) {\n            generateNewColoredSoupAndInvalidate();\n        } else if (viewState == ViewState.GRID_PARAMETERS_CHANGED || viewState == ViewState.NULL_TRIANGULATION) {\n            generateOnlyColor = false;\n            generateSoupAndInvalidateView();\n        }\n    }\n\n    /**\n     * generateNewColoredSoupAndInvalidate method is called when only the coloration of the view is to be changed. It sets the\n     * GenerateOnlyColor boolean of presenter to true, so that when generateSoupAndInvalidateView is\n     * called, only the new colors are assigned to the triangles in the triangulation, since the\n     * grid parameters have not been changed, thereby bypassing the unnecessary regeneration of grid and delaunay triangulation.\n     */\n    private void generateNewColoredSoupAndInvalidate() {\n        setGenerateOnlyColor(true);\n        generateSoupAndInvalidateView();\n    }\n\n    /**\n     * Generates a grid on basis of selected grid type\n     * @return Grid of Vector2D\n     */\n    private List<Vector2D> generateGrid() {\n        int gridType = view.getTypeGrid();\n        Patterns patterns;\n\n        switch (gridType) {\n            case TrianglifyViewInterface.GRID_RECTANGLE:\n                patterns = new Rectangle(\n                        view.getBleedX(), view.getBleedY(), view.getGridHeight(),\n                        view.getGridWidth(), view.getCellSize(), view.getVariance());\n                break;\n            case TrianglifyViewInterface.GRID_CIRCLE:\n                patterns = new Circle(\n                        view.getBleedX(), view.getBleedY(), 8, view.getGridHeight(),\n                        view.getGridWidth(), view.getCellSize(), view.getVariance());\n                break;\n            default:\n                patterns = new Rectangle(\n                        view.getBleedX(), view.getBleedY(), view.getGridHeight(),\n                        view.getGridWidth(), view.getCellSize(), view.getVariance());\n                break;\n        }\n        return patterns.generate();\n    }\n\n    /**\n     * Generates soup corresponding to current instance parameters\n     * @return triangulation generated\n     */\n    private Triangulation getSoup() {\n        if (generateOnlyColor) {\n            triangulation = generateColoredSoup(triangulation);\n        } else {\n            generateSoup();\n        }\n        return triangulation;\n    }\n\n    /**\n     * Generates colored triangulation.\n     */\n    private void generateSoup() {\n        triangulation = generateTriangulation(generateGrid());\n        triangulation = generateColoredSoup(triangulation);\n    }\n\n    /**\n     * Creates triangles from a list of points\n     * @param inputGrid Grid of points for generating triangles\n     * @return List of Triangles generated from list of input points\n     */\n    private Triangulation generateTriangulation(List<Vector2D> inputGrid) {\n        DelaunayTriangulator triangulator = new DelaunayTriangulator(inputGrid);\n        try {\n            triangulator.triangulate();\n        } catch (NotEnoughPointsException e) {\n            e.printStackTrace();\n        }\n        return new Triangulation(triangulator.getTriangles());\n    }\n\n    /**\n     * Colors each triangle in triangulation and stores color as triangle's color variable\n     * @param inputTriangulation triangulation to color\n     * @return Colored triangulation of input triangulation\n     */\n    private Triangulation generateColoredSoup(Triangulation inputTriangulation) {\n        Colorizer colorizer = new FixedPointsColorizer(inputTriangulation,\n                view.getPalette(), view.getGridHeight() + 2*view.getBleedY(),\n                view.getGridWidth() + 2*view.getBleedX(), view.isRandomColoringEnabled());\n        return colorizer.getColororedTriangulation();\n    }\n\n    public void clearSoup() {\n        triangulation = null;\n        viewState = ViewState.NULL_TRIANGULATION;\n    }\n\n    /**\n     * generateSoupAndInvalidateView method starts a new thread to regenerate the triangulation so\n     * that the regeneration is not done on the UI thread, thereby reducing the workload on the UI thread.\n     */\n    public void generateSoupAndInvalidateView() {\n        if (generatorTask != null) {\n            generatorTask.cancel(true);\n        }\n        generatorTask = new TriangleGeneratorTask();\n        generatorTask.execute();\n    }\n\n    /**\n     * TriangleGeneratorTask specifies the task of the thread. It regenerates the triangulation in the background in\n     * accordance to the value of the generateOnlyColor boolean. Upon the generation of the triangulation, it calls\n     * upon the invalidateView method to render the triangulation to the view.\n     */\n\n    class TriangleGeneratorTask extends AsyncTask<Void, Void, Triangulation> {\n\n        @Override\n        protected Triangulation doInBackground(Void... params) {\n            return getSoup();\n        }\n\n        @Override\n        protected void onPostExecute(Triangulation triangulation) {\n            super.onPostExecute(triangulation);\n            view.invalidateView(triangulation);\n        }\n    }\n}\n"
  },
  {
    "path": "trianglify/src/main/java/com/sdsmdg/kd/trianglify/utilities/ExtendedColor.java",
    "content": "package com.sdsmdg.kd.trianglify.utilities;\n\n/**\n * <h1>Title</h1>\n * <b>Description : Extends android.graphics.Color to add function that helps colorizer work.</b>\n * <p>\n *\n * @author suyash\n * @since 1/4/17.\n */\n\npublic class ExtendedColor extends android.graphics.Color {\n    public int a;\n    public int r;\n    public int g;\n    public int b;\n\n    public ExtendedColor(int palleteColor) {\n        this(0xFF,\n             (palleteColor >> 4*4),\n             ((palleteColor >> 4*2) & 0xFF),\n             ((palleteColor) & 0xFF));\n    }\n\n    public ExtendedColor(int r, int g, int b) {\n        this(0xFF, r, g, b);\n    }\n\n    private ExtendedColor(int a, int r, int g, int b) {\n        this.a = a;\n        this.r = r;\n        this.g = g;\n        this.b = b;\n    }\n\n    public static ExtendedColor avg(ExtendedColor c0, ExtendedColor c1) {\n        return new ExtendedColor((c0.a + c1.a) / 2,\n                (c0.r + c1.r) / 2,\n                (c0.g + c1.g) / 2,\n                (c0.b + c1.b) / 2\n        );\n    }\n\n    public int toInt() {\n        return argb(a, r, g, b);\n    }\n}\n"
  },
  {
    "path": "trianglify/src/main/java/com/sdsmdg/kd/trianglify/utilities/Point.java",
    "content": "package com.sdsmdg.kd.trianglify.utilities;\n\n/**\n * <h1>Title</h1>\n * <b>Description :</b>\n * <p>\n *\n * @author suyash\n * @since 25/3/17.\n */\n\npublic class Point{\n    public int x;\n    public int y;\n\n    public Point() {\n        this(0, 0);\n    }\n\n    public Point(int x, int y) {\n        this.x = x;\n        this.y = y;\n    }\n\n    public static Point subtract(Point a, Point b) {\n        return new Point(a.x - a.y, b.x - b.y);\n    }\n\n    public static Point add(Point a, Point b) {\n        return new Point(a.x + a.y, b.x + b.y);\n    }\n\n    /**\n     * Calculates mid point of two given points using integer arithmetic\n     * @param a First Point\n     * @param b Second Point\n     * @return Mid Point\n     */\n    public static Point midPoint(Point a, Point b) {\n        return new Point((a.x + a.y) / 2, (b.x + b.y) / 2);\n    }\n}\n"
  },
  {
    "path": "trianglify/src/main/java/com/sdsmdg/kd/trianglify/utilities/ThreadLocalRandom.java",
    "content": "package com.sdsmdg.kd.trianglify.utilities;\n\n/**\n * <h1>Thread Local Random</h1>\n * <b>Description : Generates Random numbers that are local to a thread thus reducing instructions\n *                  needed to generate a random number.</b>\n *\n * @author suyash\n * @since 2/5/17.\n */\n\npublic class ThreadLocalRandom {\n    private long seed = 0x5DEECE66DL;\n\n    public ThreadLocalRandom() {\n\n    }\n\n    public ThreadLocalRandom(long seed) {\n        this.seed = seed;\n    }\n\n    /**\n     * Generates a psuedoRandom integer that has computational costs of several instructions less\n     * than that of java.util.random.nextInt().\n     * @param mod limit for generation of pseudo random number\n     * @return Random number between 0 and mod (exclusive)\n     */\n    public int nextInt(int mod) {\n        if ( mod != 0 ) {\n            seed = (seed * 0x5DEECE66DL + 0xBL) & ((1L << 48) - 1);\n            return (int) (seed % mod);\n        }\n        return 0;\n    }\n\n}\n"
  },
  {
    "path": "trianglify/src/main/java/com/sdsmdg/kd/trianglify/utilities/Utilities.java",
    "content": "package com.sdsmdg.kd.trianglify.utilities;\n\nimport android.content.Context;\nimport android.util.DisplayMetrics;\n\n/**\n * <h1>Title</h1>\n * <b>Description :</b>\n * <p>\n *\n * @author suyash\n * @since 5/5/17.\n */\n\npublic class Utilities {\n    public int dpToPx(int dp, Context context) {\n        DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();\n        return Math.round(dp * (displayMetrics.xdpi / DisplayMetrics.DENSITY_DEFAULT));\n    }\n\n    public int pxToDp(int px, Context context) {\n        DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();\n        return Math.round(px / (displayMetrics.xdpi / DisplayMetrics.DENSITY_DEFAULT));\n    }\n\n}\n"
  },
  {
    "path": "trianglify/src/main/java/com/sdsmdg/kd/trianglify/utilities/colorizers/Colorizer.java",
    "content": "package com.sdsmdg.kd.trianglify.utilities.colorizers;\n\nimport com.sdsmdg.kd.trianglify.models.Triangulation;\n\n/**\n * <h1>Title</h1>\n * <b>Description :</b>\n * <p>\n *\n * @author suyash\n * @since 24/3/17.\n */\n\npublic interface Colorizer {\n    Triangulation getColororedTriangulation();\n}\n"
  },
  {
    "path": "trianglify/src/main/java/com/sdsmdg/kd/trianglify/utilities/colorizers/FixedPointsColorizer.java",
    "content": "package com.sdsmdg.kd.trianglify.utilities.colorizers;\n\nimport android.util.Log;\n\nimport com.sdsmdg.kd.trianglify.models.Palette;\nimport com.sdsmdg.kd.trianglify.models.Triangulation;\nimport com.sdsmdg.kd.trianglify.utilities.ExtendedColor;\nimport com.sdsmdg.kd.trianglify.utilities.Point;\nimport com.sdsmdg.kd.trianglify.utilities.triangulator.Triangle2D;\nimport com.sdsmdg.kd.trianglify.utilities.triangulator.Vector2D;\n\nimport com.sdsmdg.kd.trianglify.utilities.ThreadLocalRandom;\n\nimport static android.content.ContentValues.TAG;\n\n/**\n * <h1>Fixed Point Colorizer</h1>\n * <b>Description :</b>\n * Fixed point colorizer contains methods that colorize triangles\n * based on the color palette provided in the constructor.\n *\n * @author suyash\n * @since 24/3/17.\n */\n\npublic class FixedPointsColorizer implements Colorizer {\n    private ThreadLocalRandom random;\n    private Triangulation triangulation;\n    private Palette colorPalette;\n\n    private int gridWidth;\n    private int gridHeight;\n\n    private Boolean randomColoring = false;\n\n    public Palette getColorPalette() {\n        return colorPalette;\n    }\n\n    public void setColorPalette(Palette colorPalette) {\n        this.colorPalette = colorPalette;\n    }\n\n    public Triangulation getTriangulation() {\n        return triangulation;\n    }\n\n    public void setTriangulation(Triangulation triangulation) {\n        this.triangulation = triangulation;\n    }\n\n    public FixedPointsColorizer(Triangulation triangulation, Palette colorPalette,\n                                int gridHeight, int gridWidth) {\n        this(triangulation, colorPalette, gridHeight, gridWidth, false);\n    }\n\n    public FixedPointsColorizer(Triangulation triangulation, Palette colorPalette,\n                                int gridHeight, int gridWidth, Boolean randomColoring) {\n        this.randomColoring = randomColoring;\n        random = new ThreadLocalRandom(System.currentTimeMillis());\n        this.triangulation = triangulation;\n        this.colorPalette = colorPalette;\n        this.gridHeight = gridHeight;\n        this.gridWidth = gridWidth;\n    }\n\n    @Override\n    public Triangulation getColororedTriangulation() {\n        if (triangulation != null) {\n            for (Triangle2D triangle : triangulation.getTriangleList()) {\n                triangle.setColor(getColorForPoint(triangle.getCentroid()));\n            }\n        } else {\n            Log.i(TAG, \"colorizeTriangulation: Triangulation cannot be null!\");\n        }\n        return getTriangulation();\n    }\n\n    /**\n     * Returns color corresponding to the point passed in parameter by\n     * calculating average of specified by the palette.\n     *\n     *\n     * Relation between palette color and position on rectangle is\n     * depicted in the following figure:\n     *\n     *(c1 are corresponding int values representing color in ColorPalette.java)\n     *    c0              c1                c2\n     *       +-------------+--------------+\n     *       |             |              |\n     *       |     r1      |      r2      |\n     *       |             |              |\n     *    c7 +------------c8--------------+ c3\n     *       |             |              |\n     *       |     r3      |      r4      |\n     *       |             |              |\n     *       +-------------+--------------+\n     *    c6              c5                c4\n     *\n     *\n     * <b>Algorithm</b>\n     * Grid provided is divided into four regions r1 to r4. Each of the region\n     * is considered independent on calculating color for a point.\n     *\n     * Sub-rectangle in which given point lies has four vertices, denoted by\n     * Point topLeft, topRight, bottomLeft and bottomRight. Algorith then\n     * calculates weighted mean of color corresponding to vertices (seperately\n     * in x-axis and y-axis). Result of this calculation is returned as int.\n     *\n     * @param point Point to get color for\n     * @return  Color corresponding to current point\n     */\n\n    // Sorry for such long method, here's a ASCII potato\n    //          __\n    //         /   \\\n    //        /  o  \\\n    //       |     o \\\n    //      / o      |\n    //     /    o    |\n    //     \\______o__/\n    //\n\n    private int getColorForPoint(Vector2D point) {\n        if (randomColoring) {\n            return colorPalette.getColor(random.nextInt(9));\n        } else {\n\n            ExtendedColor topLeftColor, topRightColor;\n            ExtendedColor bottomLeftColor, bottomRightColor;\n\n            Point topLeft, topRight;\n            Point bottomLeft, bottomRight;\n\n            // Following if..else identifies which sub-rectangle given point lies\n            if (point.x < gridWidth/2 && point.y < gridHeight/2) {\n                topLeftColor = new ExtendedColor(colorPalette.getColor(0));\n                topRightColor = new ExtendedColor(colorPalette.getColor(1));\n                bottomLeftColor = new ExtendedColor(colorPalette.getColor(7));\n                bottomRightColor = new ExtendedColor(colorPalette.getColor(8));\n            } else if (point.x >= gridWidth/2 && point.y < gridHeight/2) {\n                topLeftColor = new ExtendedColor(colorPalette.getColor(1));\n                topRightColor = new ExtendedColor(colorPalette.getColor(2));\n                bottomLeftColor = new ExtendedColor(colorPalette.getColor(8));\n                bottomRightColor = new ExtendedColor(colorPalette.getColor(3));\n            } else if (point.x >= gridWidth/2 && point.y >= gridHeight/2) {\n                topLeftColor = new ExtendedColor(colorPalette.getColor(8));\n                topRightColor = new ExtendedColor(colorPalette.getColor(3));\n                bottomLeftColor = new ExtendedColor(colorPalette.getColor(5));\n                bottomRightColor = new ExtendedColor(colorPalette.getColor(4));\n            } else {\n                topLeftColor = new ExtendedColor(colorPalette.getColor(7));\n                topRightColor = new ExtendedColor(colorPalette.getColor(8));\n                bottomLeftColor = new ExtendedColor(colorPalette.getColor(6));\n                bottomRightColor = new ExtendedColor(colorPalette.getColor(5));\n            }\n\n            // Calculate corners of sub rectangle in which point is identified\n            topLeft = new Point(\n                    (point.x >= gridWidth/2) ? gridWidth/2 : 0,\n                    (point.y >= gridHeight/2) ? gridHeight/2 : 0);\n            topRight = new Point(\n                    (point.x >= gridWidth/2) ? gridWidth : gridWidth/2,\n                    (point.y >= gridHeight/2) ? gridHeight/2 : 0);\n            bottomLeft = new Point(\n                    (point.x >= gridWidth/2) ? gridWidth/2 : 0,\n                    (point.y >= gridHeight/2) ? gridHeight : gridHeight/2);\n            bottomRight = new Point(\n                    (point.x >= gridWidth/2) ? gridWidth : gridWidth/2,\n                    (point.y >= gridHeight/2) ? gridHeight : gridHeight/2);\n\n            // Calculates weighted mean of colors\n            ExtendedColor weightedTopColor = new ExtendedColor(\n                    (int)((topRightColor.r*(point.x - topLeft.x) + (topLeftColor.r)*(topRight.x - point.x))\n                            / ((topRight.x - topLeft.x))),\n                    (int)((topRightColor.g*(point.x - topLeft.x) + (topLeftColor.g)*(topRight.x - point.x))\n                            / ((topRight.x - topLeft.x))),\n                    (int)((topRightColor.b*(point.x - topLeft.x) + (topLeftColor.b)*(topRight.x - point.x))\n                            / ((topRight.x - topLeft.x)))\n            );\n            ExtendedColor weightedBottomColor = new ExtendedColor(\n                    (int) ((bottomRightColor.r*(point.x - topLeft.x) + (bottomLeftColor.r)*(topRight.x - point.x))\n                            / ((topRight.x - topLeft.x))),\n                    (int)((bottomRightColor.g*(point.x - topLeft.x) + (bottomLeftColor.g)*(topRight.x - point.x))\n                            / ((topRight.x - topLeft.x))),\n                    (int)((bottomRightColor.b*(point.x - topLeft.x) + (bottomLeftColor.b)*(topRight.x - point.x))\n                            / ((topRight.x - topLeft.x)))\n\n            );\n            ExtendedColor weightedLeftColor = new ExtendedColor(\n                    (int)((bottomLeftColor.r*(point.y - topLeft.y) + (topLeftColor.r)*(bottomLeft.y - point.y))\n                            / ((bottomLeft.y - topLeft.y))),\n                    (int)((bottomLeftColor.g*(point.y - topLeft.y) + (topLeftColor.g)*(bottomLeft.y - point.y))\n                            / ((bottomLeft.y - topLeft.y))),\n                    (int)((bottomLeftColor.b*(point.y - topLeft.y) + (topLeftColor.b)*(bottomLeft.y - point.y))\n                            / ((bottomLeft.y - topLeft.y)))\n            );\n\n            ExtendedColor weightedRightColor = new ExtendedColor(\n                    (int)((bottomRightColor.r*(point.y - topRight.y)\n                            + (topRightColor.r)*(bottomRight.y - point.y))\n                            / ((bottomRight.y - topRight.y))),\n                    (int)((bottomRightColor.g*(point.y - topRight.y)\n                            + (topRightColor.g)*(bottomRight.y - point.y))\n                            / ((bottomRight.y - topRight.y))),\n                    (int)((bottomRightColor.b*(point.y - topRight.y)\n                            + (topRightColor.b)*(bottomRight.y - point.y))\n                            / ((bottomRight.y - topRight.y)))\n            );\n\n\n            ExtendedColor weightedYColor = new ExtendedColor(\n                    (int)((weightedRightColor.r*(point.x - topLeft.x)\n                            + (weightedLeftColor.r)*(topRight.x - point.x))\n                            / ((topRight.x - topLeft.x))),\n                    (int)((weightedRightColor.g*(point.x - topLeft.x)\n                            + (weightedLeftColor.g)*(topRight.x - point.x))\n                            / ((topRight.x - topLeft.x))),\n                    (int)((weightedRightColor.b*(point.x - topLeft.x)\n                            + (weightedLeftColor.b)*(topRight.x - point.x))\n                            / ((topRight.x - topLeft.x)))\n            );\n\n\n            ExtendedColor weightedXColor = new ExtendedColor(\n                    (int)((weightedBottomColor.r*(point.y - topLeft.y)\n                            + (weightedTopColor.r)*(bottomLeft.y - point.y))\n                            / ((bottomLeft.y - topLeft.y))),\n                    (int)((weightedBottomColor.g*(point.y - topLeft.y)\n                            + (weightedTopColor.g)*(bottomLeft.y - point.y))\n                            / ((bottomLeft.y - topLeft.y))),\n                    (int)((weightedBottomColor.b*(point.y - topLeft.y)\n                            + (weightedTopColor.b)*(bottomLeft.y - point.y))\n                            / ((bottomLeft.y - topLeft.y)))\n\n            );\n\n            return ExtendedColor.avg(weightedXColor, weightedYColor).toInt();\n        }\n    }\n\n    /**\n     * Calculates average of given numbers without using floating point\n     * operations\n     *\n     * @param args Values to calculate average of\n     * @return  Average of values provided\n     */\n    private int avg(int...args) {\n        int sum = 0;\n        for (int arg : args) {\n            sum += arg;\n        }\n        return sum/args.length;\n    }\n}\n"
  },
  {
    "path": "trianglify/src/main/java/com/sdsmdg/kd/trianglify/utilities/patterns/Circle.java",
    "content": "package com.sdsmdg.kd.trianglify.utilities.patterns;\n\n\nimport com.sdsmdg.kd.trianglify.utilities.triangulator.Vector2D;\n\nimport java.util.List;\nimport java.util.Random;\n\n/**\n * Created by suyash on 12/3/17.\n */\n\n public class Circle implements Patterns {\n    private final Random random = new Random();\n    private int bleedX = 0;\n    private int bleedY = 0;\n    private int pointsPerCircle = 8;\n\n    private int height = 0;\n    private int width = 0;\n\n    private int cellSize = 0;\n    private int variance = 0;\n\n    public List<Vector2D> grid;\n\n    public Random getRandom() {\n        return random;\n    }\n\n    public int getBleedX() {\n        return bleedX;\n    }\n\n    public void setBleedX(int bleedX) {\n        this.bleedX = bleedX;\n    }\n\n    public int getBleedY() {\n        return bleedY;\n    }\n\n    public void setBleedY(int bleedY) {\n        this.bleedY = bleedY;\n    }\n\n    public int getPointsPerCircle() {\n        return pointsPerCircle;\n    }\n\n    public void setPointsPerCircle(int pointsPerCircle) {\n        this.pointsPerCircle = pointsPerCircle;\n    }\n\n    public int getHeight() {\n        return height;\n    }\n\n    public void setHeight(int height) {\n        this.height = height;\n    }\n\n    public int getWidth() {\n        return width;\n    }\n\n    public void setWidth(int width) {\n        this.width = width;\n    }\n\n    public int getCellSize() {\n        return cellSize;\n    }\n\n    public void setCellSize(int cellSize) {\n        this.cellSize = cellSize;\n    }\n\n    public int getVariance() {\n        return variance;\n    }\n\n    public void setVariance(int variance) {\n        this.variance = variance;\n    }\n\n    public Circle(int bleedX, int bleedY, int pointsPerCircle, int height, int width, int cellSize, int variance) {\n        this.bleedX = bleedX;\n        this.bleedY = bleedY;\n\n        this.pointsPerCircle = pointsPerCircle;\n\n        this.height = height;\n        this.width = width;\n\n        this.cellSize = cellSize;\n        this.variance = variance;\n    }\n\n    public List<Vector2D> generate() {\n        Vector2D center = new Vector2D(width / 2, height / 2);\n\n        grid.clear();\n\n        int maxRadius = Math.max(width + bleedX, height + bleedY);\n        this.grid.add(center);\n\n        double slice, angle;\n        int x, y;\n\n        for (int radius = cellSize; radius < maxRadius; radius += cellSize) {\n            slice = 2 * Math.PI / pointsPerCircle;\n            for (int i = 0; i < pointsPerCircle; i++) {\n                angle = slice * i;\n                x = (int) (center.x + radius * Math.cos(angle)) + random.nextInt(variance);\n                y = (int) (center.y + radius * Math.sin(angle)) + random.nextInt(variance);\n                this.grid.add(new Vector2D(x, y));\n            }\n        }\n\n        return grid;\n    }\n}\n"
  },
  {
    "path": "trianglify/src/main/java/com/sdsmdg/kd/trianglify/utilities/patterns/Patterns.java",
    "content": "package com.sdsmdg.kd.trianglify.utilities.patterns;\n\n\n\nimport com.sdsmdg.kd.trianglify.utilities.triangulator.Vector2D;\n\nimport java.util.List;\n\n/**\n * Created by suyash on 17/3/17.\n */\n\n\npublic interface Patterns {\n    public List<Vector2D> generate();\n}\n"
  },
  {
    "path": "trianglify/src/main/java/com/sdsmdg/kd/trianglify/utilities/patterns/Rectangle.java",
    "content": "package com.sdsmdg.kd.trianglify.utilities.patterns;\n\nimport com.sdsmdg.kd.trianglify.utilities.triangulator.Vector2D;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Random;\nimport com.sdsmdg.kd.trianglify.utilities.ThreadLocalRandom;\n\n/**\n * Created by suyash on 12/3/17.\n */\n\npublic class Rectangle implements Patterns {\n    private final ThreadLocalRandom random;\n    private int bleedX = 0;\n    private int bleedY = 0;\n\n    private int height= 0;\n    private int width= 0;\n\n    private int cellSize = 0;\n    private int variance= 0;\n\n    List<Vector2D> grid;\n\n    public Rectangle(int bleedX, int bleedY, int height, int width, int cellSize, int variance) {\n        this.bleedX = bleedX;\n        this.bleedY = bleedY;\n\n        this.variance = variance;\n        this.cellSize = cellSize;\n\n        this.height = height;\n        this.width = width;\n\n        random = new ThreadLocalRandom();\n\n        grid = new ArrayList<>();\n    }\n\n    /**\n     * Generates array of points arranged in a grid of rectangles with deviation from their positions\n     * on the basis of bleed value.\n     * @return List of Vector2D containing points that resembles rectangular grid\n     */\n    @Override\n    public List<Vector2D> generate() {\n        grid.clear();\n\n        int x, y;\n        for (int j = 0; j < height + 2*bleedY; j += cellSize) {\n            for (int i = 0; i < width + 2*bleedX; i += cellSize) {\n                x = i + random.nextInt(variance);\n                y = j + random.nextInt(variance);\n                this.grid.add(new Vector2D(x, y));\n            }\n        }\n\n        return grid;\n    }\n}\n\n"
  },
  {
    "path": "trianglify/src/main/java/com/sdsmdg/kd/trianglify/utilities/triangulator/DelaunayTriangulation.java",
    "content": "package com.sdsmdg.kd.trianglify.utilities.triangulator;\n\n//import Triangulation.Triagulation;\n\n/**\n * <h1>Title</h1>\n * <b>Description :</b>\n * <p>\n *\n * @author suyash\n * @since 31/3/17.\n */\n\npublic class DelaunayTriangulation {\n\n}\n"
  },
  {
    "path": "trianglify/src/main/java/com/sdsmdg/kd/trianglify/utilities/triangulator/DelaunayTriangulator.java",
    "content": "package com.sdsmdg.kd.trianglify.utilities.triangulator;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\n\n/**\n * A Java implementation of an incremental 2D Delaunay triangulation algorithm.\n * \n * @author Johannes Diemke\n */\npublic class DelaunayTriangulator {\n\n    private List<Vector2D> pointSet;\n    private TriangleSoup triangleSoup;\n\n    /**\n     * Constructor of the SimpleDelaunayTriangulator class used to create a new\n     * triangulator instance.\n     * \n     * @param pointSet\n     *            The point set to be triangulated\n     * @throws NotEnoughPointsException\n     *             Thrown when the point set contains less than three points\n     */\n    public DelaunayTriangulator(List<Vector2D> pointSet) {\n        this.pointSet = pointSet;\n        this.triangleSoup = new TriangleSoup();\n    }\n\n    /**\n     * This method generates a Delaunay triangulation from the specified point\n     * set.\n     *\n     * @throws com.sdsmdg.kd.trianglify.utilities.triangulator.NotEnoughPointsException\n     */\n    public void triangulate() throws NotEnoughPointsException {\n        triangleSoup = new TriangleSoup();\n\n        if (pointSet == null || pointSet.size() < 3) {\n            throw new NotEnoughPointsException(\"Less than three points in point set.\");\n        }\n\n        /**\n         * In order for the in circumcircle test to not consider the vertices of\n         * the super triangle we have to start out with a big triangle\n         * containing the whole point set. We have to scale the super triangle\n         * to be very large. Otherwise the triangulation is not convex.\n         */\n        float maxOfAnyCoordinate = 0.0f;\n\n        for (Vector2D vector : getPointSet()) {\n            maxOfAnyCoordinate = Math.max(Math.max(vector.x, vector.y), maxOfAnyCoordinate);\n        }\n\n        maxOfAnyCoordinate *= 16.0d;\n\n        float newCoordinate = 3.0f * maxOfAnyCoordinate;\n        final Vector2D p1 = new Vector2D(0.0f, newCoordinate);\n        final Vector2D p2 = new Vector2D(newCoordinate, 0.0f);\n        final Vector2D p3 = new Vector2D(-newCoordinate, -newCoordinate);\n\n        final Triangle2D superTriangle = new Triangle2D(p1, p2, p3);\n\n        triangleSoup.add(superTriangle);\n\n        for (int i = 0; i < pointSet.size(); i++) {\n            Triangle2D triangle = triangleSoup.findContainingTriangle(pointSet.get(i));\n\n            if (triangle == null) {\n                /**\n                 * If no containing triangle exists, then the vertex is not\n                 * inside a triangle (this can also happen due to numerical\n                 * errors) and lies on an edge. In order to find this edge we\n                 * search all edges of the triangle soup and select the one\n                 * which is nearest to the point we try to add. This edge is\n                 * removed and four new edges are added.\n                 */\n                final Edge2D edge = triangleSoup.findNearestEdge(pointSet.get(i));\n\n                final Triangle2D first = triangleSoup.findOneTriangleSharing(edge);\n                final Triangle2D second = triangleSoup.findNeighbour(first, edge);\n\n                final Vector2D firstNoneEdgeVertex = first.getNoneEdgeVertex(edge);\n                final Vector2D secondNoneEdgeVertex = second.getNoneEdgeVertex(edge);\n\n                triangleSoup.remove(first);\n                triangleSoup.remove(second);\n\n                final Triangle2D triangle1 = new Triangle2D(edge.a, firstNoneEdgeVertex, pointSet.get(i));\n                final Triangle2D triangle2 = new Triangle2D(edge.b, firstNoneEdgeVertex, pointSet.get(i));\n                final Triangle2D triangle3 = new Triangle2D(edge.a, secondNoneEdgeVertex, pointSet.get(i));\n                final Triangle2D triangle4 = new Triangle2D(edge.b, secondNoneEdgeVertex, pointSet.get(i));\n\n                triangleSoup.add(triangle1);\n                triangleSoup.add(triangle2);\n                triangleSoup.add(triangle3);\n                triangleSoup.add(triangle4);\n\n                legalizeEdge(triangle1, new Edge2D(edge.a, firstNoneEdgeVertex), pointSet.get(i));\n                legalizeEdge(triangle2, new Edge2D(edge.b, firstNoneEdgeVertex), pointSet.get(i));\n                legalizeEdge(triangle3, new Edge2D(edge.a, secondNoneEdgeVertex), pointSet.get(i));\n                legalizeEdge(triangle4, new Edge2D(edge.b, secondNoneEdgeVertex), pointSet.get(i));\n            } else {\n                /**\n                 * The vertex is inside a triangle.\n                 */\n                final Vector2D a = triangle.a;\n                final Vector2D b = triangle.b;\n                final Vector2D c = triangle.c;\n\n                triangleSoup.remove(triangle);\n\n                final Triangle2D first = new Triangle2D(a, b, pointSet.get(i));\n                final Triangle2D second = new Triangle2D(b, c, pointSet.get(i));\n                final Triangle2D third = new Triangle2D(c, a, pointSet.get(i));\n\n                triangleSoup.add(first);\n                triangleSoup.add(second);\n                triangleSoup.add(third);\n\n                legalizeEdge(first, new Edge2D(a, b), pointSet.get(i));\n                legalizeEdge(second, new Edge2D(b, c), pointSet.get(i));\n                legalizeEdge(third, new Edge2D(c, a), pointSet.get(i));\n            }\n        }\n\n        /**\n         * Remove all triangles that contain vertices of the super triangle.\n         */\n        triangleSoup.removeTrianglesUsing(superTriangle.a);\n        triangleSoup.removeTrianglesUsing(superTriangle.b);\n        triangleSoup.removeTrianglesUsing(superTriangle.c);\n    }\n\n    /**\n     * This method legalizes edges by recursively flipping all illegal edges.\n     * \n     * @param triangle\n     *            The triangle\n     * @param edge\n     *            The edge to be legalized\n     * @param newVertex\n     *            The new vertex\n     */\n    private void legalizeEdge(Triangle2D triangle, Edge2D edge, Vector2D newVertex) {\n        final Triangle2D neighbourTriangle = triangleSoup.findNeighbour(triangle, edge);\n\n        /**\n         * If the triangle has a neighbor, then legalize the edge\n         */\n        if (neighbourTriangle != null) {\n            if (neighbourTriangle.isPointInCircumcircle(newVertex)) {\n                triangleSoup.remove(triangle);\n                triangleSoup.remove(neighbourTriangle);\n\n                final Vector2D noneEdgeVertex = neighbourTriangle.getNoneEdgeVertex(edge);\n\n                final Triangle2D firstTriangle = new Triangle2D(noneEdgeVertex, edge.a, newVertex);\n                final Triangle2D secondTriangle = new Triangle2D(noneEdgeVertex, edge.b, newVertex);\n\n                triangleSoup.add(firstTriangle);\n                triangleSoup.add(secondTriangle);\n\n                legalizeEdge(firstTriangle, new Edge2D(noneEdgeVertex, edge.a), newVertex);\n                legalizeEdge(secondTriangle, new Edge2D(noneEdgeVertex, edge.b), newVertex);\n            }\n        }\n    }\n\n    /**\n     * Creates a random permutation of the specified point set. Based on the\n     * implementation of the Delaunay algorithm this can speed up the\n     * computation.\n     */\n    public void shuffle() {\n        Collections.shuffle(pointSet);\n    }\n\n    /**\n     * Shuffles the point set using a custom permutation sequence.\n     * \n     * @param permutation\n     *            The permutation used to shuffle the point set\n     */\n    public void shuffle(int[] permutation) {\n        List<Vector2D> temp = new ArrayList<Vector2D>();\n        for (int i = 0; i < permutation.length; i++) {\n            temp.add(pointSet.get(permutation[i]));\n        }\n        pointSet = temp;\n    }\n\n    /**\n     * Returns the point set in form of a vector of 2D vectors.\n     * \n     * @return Returns the points set.\n     */\n    public List<Vector2D> getPointSet() {\n        return pointSet;\n    }\n\n    /**\n     * Returns the trianges of the triangulation in form of a vector of 2D\n     * triangles.\n     * \n     * @return Returns the triangles of the triangulation.\n     */\n    public List<Triangle2D> getTriangles() {\n        return triangleSoup.getTriangles();\n    }\n\n}"
  },
  {
    "path": "trianglify/src/main/java/com/sdsmdg/kd/trianglify/utilities/triangulator/Edge2D.java",
    "content": "package com.sdsmdg.kd.trianglify.utilities.triangulator;\n\n/**\n * 2D edge class implementation.\n * \n * @author Johannes Diemke\n */\npublic class Edge2D {\n\n    public Vector2D a;\n    public Vector2D b;\n\n    /**\n     * Constructor of the 2D edge class used to create a new edge instance from\n     * two 2D vectors describing the edge's vertices.\n     * \n     * @param a\n     *            The first vertex of the edge\n     * @param b\n     *            The second vertex of the edge\n     */\n    public Edge2D(Vector2D a, Vector2D b) {\n        this.a = a;\n        this.b = b;\n    }\n\n}"
  },
  {
    "path": "trianglify/src/main/java/com/sdsmdg/kd/trianglify/utilities/triangulator/EdgeDistancePack.java",
    "content": "package com.sdsmdg.kd.trianglify.utilities.triangulator;\n\n/**\n * Edge distance pack class implementation used to describe the distance to a\n * given edge.\n * \n * @author Johannes Diemke\n */\npublic class EdgeDistancePack implements Comparable<EdgeDistancePack> {\n\n    public Edge2D edge;\n    public double distance;\n\n    /**\n     * Constructor of the edge distance pack class used to create a new edge\n     * distance pack instance from a 2D edge and a scalar value describing a\n     * distance.\n     * \n     * @param edge\n     *            The edge\n     * @param distance\n     *            The distance of the edge to some point\n     */\n    public EdgeDistancePack(Edge2D edge, double distance) {\n        this.edge = edge;\n        this.distance = distance;\n    }\n\n    @Override\n    public int compareTo(EdgeDistancePack o) {\n        return Double.compare(this.distance, o.distance);\n    }\n\n}"
  },
  {
    "path": "trianglify/src/main/java/com/sdsmdg/kd/trianglify/utilities/triangulator/NotEnoughPointsException.java",
    "content": "package com.sdsmdg.kd.trianglify.utilities.triangulator;\n\n/**\n * Exception thrown by the Delaunay triangulator when it is initialized with\n * less than three points.\n * \n * @author Johannes Diemke\n */\npublic class NotEnoughPointsException extends Exception {\n\n    private static final long serialVersionUID = 7061712854155625067L;\n\n    public NotEnoughPointsException() {\n    }\n\n    public NotEnoughPointsException(String s) {\n        super(s);\n    }\n\n}"
  },
  {
    "path": "trianglify/src/main/java/com/sdsmdg/kd/trianglify/utilities/triangulator/Triangle2D.java",
    "content": "package com.sdsmdg.kd.trianglify.utilities.triangulator;\n\nimport java.util.Arrays;\n\n/**\n * 2D triangle class implementation.\n * \n * @author Johannes Diemke\n */\npublic class Triangle2D {\n\n    public Vector2D a;\n    public Vector2D b;\n    public Vector2D c;\n    private int color;\n\n    /**\n     * Constructor of the 2D triangle class used to create a new triangle\n     * instance from three 2D vectors describing the triangle's vertices.\n     * \n     * @param a\n     *            The first vertex of the triangle\n     * @param b\n     *            The second vertex of the triangle\n     * @param c\n     *            The third vertex of the triangle\n     */\n    public Triangle2D(Vector2D a, Vector2D b, Vector2D c) {\n        this.a = a;\n        this.b = b;\n        this.c = c;\n    }\n\n    /**\n     * Tests if a 2D point lies inside this 2D triangle. See Real-Time Collision\n     * Detection, chap. 5, p. 206.\n     * \n     * @param point\n     *            The point to be tested\n     * @return Returns true iff the point lies inside this 2D triangle\n     */\n    public boolean contains(Vector2D point) {\n        final double pab = point.sub(a).cross(b.sub(a));\n        final double pbc = point.sub(b).cross(c.sub(b));\n\n        if (!hasSameSign(pab, pbc)) {\n            return false;\n        }\n\n        double pca = point.sub(c).cross(a.sub(c));\n\n        if (!hasSameSign(pab, pca)) {\n            return false;\n        }\n\n        return true;\n    }\n\n    /**\n     * Tests if a given point lies in the circumcircle of this triangle. Let the\n     * triangle ABC appear in counterclockwise (CCW) order. Then when det &gt;\n     * 0, the point lies inside the circumcircle through the three points a, b\n     * and c. If instead det &lt; 0, the point lies outside the circumcircle.\n     * When det = 0, the four points are cocircular. If the triangle is oriented\n     * clockwise (CW) the result is reversed. See Real-Time Collision Detection,\n     * chap. 3, p. 34.\n     * \n     * @param point\n     *            The point to be tested\n     * @return Returns true iff the point lies inside the circumcircle through\n     *         the three points a, b, and c of the triangle\n     */\n    public boolean isPointInCircumcircle(Vector2D point) {\n        final double a11 = a.x - point.x;\n        final double a21 = b.x - point.x;\n        final double a31 = c.x - point.x;\n\n        final double a12 = a.y - point.y;\n        final double a22 = b.y - point.y;\n        final double a32 = c.y - point.y;\n\n        final double a13 = (a.x - point.x) * (a.x - point.x) + (a.y - point.y) * (a.y - point.y);\n        final double a23 = (b.x - point.x) * (b.x - point.x) + (b.y - point.y) * (b.y - point.y);\n        final double a33 = (c.x - point.x) * (c.x - point.x) + (c.y - point.y) * (c.y - point.y);\n\n        final double det = a11 * a22 * a33 + a12 * a23 * a31 + a13 * a21 * a32 - a13 * a22 * a31 - a12 * a21 * a33\n                - a11 * a23 * a32;\n\n        if (isOrientedCCW()) {\n            return det > 0.0d;\n        }\n\n        return det < 0.0d;\n    }\n\n    /**\n     * Test if this triangle is oriented counterclockwise (CCW). Let A, B and C\n     * be three 2D points. If det &gt; 0, C lies to the left of the directed\n     * line AB. Equivalently the triangle ABC is oriented counterclockwise. When\n     * det &lt; 0, C lies to the right of the directed line AB, and the triangle\n     * ABC is oriented clockwise. When det = 0, the three points are colinear.\n     * See Real-Time Collision Detection, chap. 3, p. 32\n     * \n     * @return Returns true iff the triangle ABC is oriented counterclockwise\n     *         (CCW)\n     */\n    public boolean isOrientedCCW() {\n        final double a11 = a.x - c.x;\n        final double a21 = b.x - c.x;\n\n        final double a12 = a.y - c.y;\n        final double a22 = b.y - c.y;\n\n        final double det = a11 * a22 - a12 * a21;\n\n        return det > 0.0d;\n    }\n\n    /**\n     * Returns true if this triangle contains the given edge.\n     * \n     * @param edge\n     *            The edge to be tested\n     * @return Returns true if this triangle contains the edge\n     */\n    public boolean isNeighbour(Edge2D edge) {\n        return (a == edge.a || b == edge.a || c == edge.a) && (a == edge.b || b == edge.b || c == edge.b);\n    }\n\n    /**\n     * Returns the vertex of this triangle that is not part of the given edge.\n     * \n     * @param edge\n     *            The edge\n     * @return The vertex of this triangle that is not part of the edge\n     */\n    public Vector2D getNoneEdgeVertex(Edge2D edge) {\n        if (a != edge.a && a != edge.b) {\n            return a;\n        } else if (b != edge.a && b != edge.b) {\n            return b;\n        } else if (c != edge.a && c != edge.b) {\n            return c;\n        }\n\n        return null;\n    }\n\n    /**\n     * Returns true if the given vertex is one of the vertices describing this\n     * triangle.\n     * \n     * @param vertex\n     *            The vertex to be tested\n     * @return Returns true if the Vertex is one of the vertices describing this\n     *         triangle\n     */\n    public boolean hasVertex(Vector2D vertex) {\n        if (a == vertex || b == vertex || c == vertex) {\n            return true;\n        }\n\n        return false;\n    }\n\n    /**\n     * Returns an EdgeDistancePack containing the edge and its distance nearest\n     * to the specified point.\n     * \n     * @param point\n     *            The point the nearest edge is queried for\n     * @return The edge of this triangle that is nearest to the specified point\n     */\n    public EdgeDistancePack findNearestEdge(Vector2D point) {\n        EdgeDistancePack[] edges = new EdgeDistancePack[3];\n\n        edges[0] = new EdgeDistancePack(new Edge2D(a, b),\n                computeClosestPoint(new Edge2D(a, b), point).sub(point).mag());\n        edges[1] = new EdgeDistancePack(new Edge2D(b, c),\n                computeClosestPoint(new Edge2D(b, c), point).sub(point).mag());\n        edges[2] = new EdgeDistancePack(new Edge2D(c, a),\n                computeClosestPoint(new Edge2D(c, a), point).sub(point).mag());\n\n        Arrays.sort(edges);\n        return edges[0];\n    }\n\n    /**\n     * Computes the closest point on the given edge to the specified point.\n     * \n     * @param edge\n     *            The edge on which we search the closest point to the specified\n     *            point\n     * @param point\n     *            The point to which we search the closest point on the edge\n     * @return The closest point on the given edge to the specified point\n     */\n    private Vector2D computeClosestPoint(Edge2D edge, Vector2D point) {\n        final Vector2D ab = edge.b.sub(edge.a);\n        float t = point.sub(edge.a).dot(ab) / ab.dot(ab);\n\n        if (t < 0.0f) {\n            t = 0.0f;\n        } else if (t > 1.0f) {\n            t = 1.0f;\n        }\n\n        return edge.a.add(ab.mult(t));\n    }\n\n    /**\n     * Tests if the two arguments have the same sign.\n     * \n     * @param a\n     *            The first floating point argument\n     * @param b\n     *            The second floating point argument\n     * @return Returns true iff both arguments have the same sign\n     */\n    private boolean hasSameSign(double a, double b) {\n        return Math.signum(a) == Math.signum(b);\n    }\n\n    public void setColor(int color) {\n        this.color = color;\n    }\n\n    public int getColor() {\n        return color;\n    }\n\n    @Override\n    public String toString() {\n        return \"Triangle2D[\" + a + \", \" + b + \", \" + c + \"]\";\n    }\n\n\n\n    public Vector2D getCentroid() {\n        Vector2D centroid = new Vector2D(0,0);\n        centroid.x = ((a.x) + (b.x) + (c.x))/3;\n        centroid.y = ((a.y) + (b.y) + (c.y))/3;\n        return centroid;\n    }\n}"
  },
  {
    "path": "trianglify/src/main/java/com/sdsmdg/kd/trianglify/utilities/triangulator/TriangleSoup.java",
    "content": "package com.sdsmdg.kd.trianglify.utilities.triangulator;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.HashSet;\nimport java.util.List;\n\n/**\n * Triangle soup class implementation.\n * \n * @author Johannes Diemke\n */\nclass TriangleSoup {\n\n    private HashSet<Triangle2D> triangleSoup;\n\n    /**\n     * Constructor of the triangle soup class used to create a new triangle soup\n     * instance.\n     */\n    public TriangleSoup() {\n        this.triangleSoup = new HashSet<>();\n    }\n\n    /**\n     * Adds a triangle to this triangle soup.\n     * \n     * @param triangle\n     *            The triangle to be added to this triangle soup\n     */\n    public void add(Triangle2D triangle) {\n        this.triangleSoup.add(triangle);\n    }\n\n    /**\n     * Removes a triangle from this triangle soup.\n     * \n     * @param triangle\n     *            The triangle to be removed from this triangle soup\n     */\n    public void remove(Triangle2D triangle) {\n        this.triangleSoup.remove(triangle);\n    }\n\n    /**\n     * Returns the triangles from this triangle soup.\n     * \n     * @return The triangles from this triangle soup\n     */\n    public List<Triangle2D> getTriangles() {\n        return new ArrayList<>(this.triangleSoup);\n    }\n\n    /**\n     * Returns the triangle from this triangle soup that contains the specified\n     * point or null if no triangle from the triangle soup contains the point.\n     * \n     * @param point\n     *            The point\n     * @return Returns the triangle from this triangle soup that contains the\n     *         specified point or null\n     */\n    public Triangle2D findContainingTriangle(Vector2D point) {\n        for (Triangle2D triangle : triangleSoup) {\n            if (triangle.contains(point)) {\n                return triangle;\n            }\n        }\n        return null;\n    }\n\n    /**\n     * Returns the neighbor triangle of the specified triangle sharing the same\n     * edge as specified. If no neighbor sharing the same edge exists null is\n     * returned.\n     * \n     * @param triangle\n     *            The triangle\n     * @param edge\n     *            The edge\n     * @return The triangles neighbor triangle sharing the same edge or null if\n     *         no triangle exists\n     */\n    public Triangle2D findNeighbour(Triangle2D triangle, Edge2D edge) {\n        for (Triangle2D triangleFromSoup : triangleSoup) {\n            if (triangleFromSoup.isNeighbour(edge) && triangleFromSoup != triangle) {\n                return triangleFromSoup;\n            }\n        }\n        return null;\n    }\n\n    /**\n     * Returns one of the possible triangles sharing the specified edge. Based\n     * on the ordering of the triangles in this triangle soup the returned\n     * triangle may differ. To find the other triangle that shares this edge use\n     * the {@link findNeighbour(Triangle2D triangle, Edge2D edge)} method.\n     * \n     * @param edge\n     *            The edge\n     * @return Returns one triangle that shares the specified edge\n     */\n    public Triangle2D findOneTriangleSharing(Edge2D edge) {\n        for (Triangle2D triangle : triangleSoup) {\n            if (triangle.isNeighbour(edge)) {\n                return triangle;\n            }\n        }\n        return null;\n    }\n\n    /**\n     * Returns the edge from the triangle soup nearest to the specified point.\n     * \n     * @param point\n     *            The point\n     * @return The edge from the triangle soup nearest to the specified point\n     */\n    public Edge2D findNearestEdge(Vector2D point) {\n        List<EdgeDistancePack> edgeList = new ArrayList<EdgeDistancePack>();\n\n        for (Triangle2D triangle : triangleSoup) {\n            edgeList.add(triangle.findNearestEdge(point));\n        }\n\n        EdgeDistancePack[] edgeDistancePacks = new EdgeDistancePack[edgeList.size()];\n        edgeList.toArray(edgeDistancePacks);\n\n        Arrays.sort(edgeDistancePacks);\n        return edgeDistancePacks[0].edge;\n    }\n\n    /**\n     * Removes all triangles from this triangle soup that contain the specified\n     * vertex.\n     * \n     * @param vertex\n     *            The vertex\n     */\n    public void removeTrianglesUsing(Vector2D vertex) {\n        List<Triangle2D> trianglesToBeRemoved = new ArrayList<Triangle2D>();\n\n        for (Triangle2D triangle : triangleSoup) {\n            if (triangle.hasVertex(vertex)) {\n                trianglesToBeRemoved.add(triangle);\n            }\n        }\n\n        triangleSoup.removeAll(trianglesToBeRemoved);\n    }\n\n}"
  },
  {
    "path": "trianglify/src/main/java/com/sdsmdg/kd/trianglify/utilities/triangulator/Vector2D.java",
    "content": "package com.sdsmdg.kd.trianglify.utilities.triangulator;\n\n/**\n * 2D vector class implementation.\n * \n * @author Johannes Diemke\n */\npublic class Vector2D {\n\n    public float x;\n    public float y;\n\n    /**\n     * Constructor of the 2D vector class used to create new vector instances.\n     * \n     * @param x\n     *            The x coordinate of the new vector\n     * @param y\n     *            The y coordinate of the new vector\n     */\n    public Vector2D(float x, float y) {\n        this.x = x;\n        this.y = y;\n    }\n\n    /**\n     * Subtracts the given vector from this.\n     * \n     * @param vector\n     *            The vector to be subtracted from this\n     * @return A new instance holding the result of the vector subtraction\n     */\n    public Vector2D sub(Vector2D vector) {\n        return new Vector2D(this.x - vector.x, this.y - vector.y);\n    }\n\n    /**\n     * Adds the given vector to this.\n     * \n     * @param vector\n     *            The vector to be added to this\n     * @return A new instance holding the result of the vector addition\n     */\n    public Vector2D add(Vector2D vector) {\n        return new Vector2D(this.x + vector.x, this.y + vector.y);\n    }\n\n    /**\n     * Multiplies this by the given scalar.\n     * \n     * @param scalar\n     *            The scalar to be multiplied by this\n     * @return A new instance holding the result of the multiplication\n     */\n    public Vector2D mult(float scalar) {\n        return new Vector2D(this.x * scalar, this.y * scalar);\n    }\n\n    /**\n     * Computes the magnitude or length of this.\n     * \n     * @return The magnitude of this\n     */\n    public float mag() {\n        return (float)Math.sqrt(this.x * this.x + this.y * this.y);\n    }\n\n    /**\n     * Computes the dot product of this and the given vector.\n     * \n     * @param vector\n     *            The vector to be multiplied by this\n     * @return A new instance holding the result of the multiplication\n     */\n    public float dot(Vector2D vector) {\n        return this.x * vector.x + this.y * vector.y;\n    }\n\n    /**\n     * Computes the 2D pseudo cross product Dot(Perp(this), vector) of this and\n     * the given vector.\n     * \n     * @param vector\n     *            The vector to be multiplied to the perpendicular vector of\n     *            this\n     * @return A new instance holding the result of the pseudo cross product\n     */\n    public float cross(Vector2D vector) {\n        return this.y * vector.x - this.x * vector.y;\n    }\n\n    @Override\n    public String toString() {\n        return \"Vector2D[\" + x + \", \" + y + \"]\";\n    }\n\n}"
  },
  {
    "path": "trianglify/src/main/java/com/sdsmdg/kd/trianglify/views/TrianglifyView.java",
    "content": "package com.sdsmdg.kd.trianglify.views;\n\nimport android.content.Context;\nimport android.content.res.TypedArray;\nimport android.graphics.Bitmap;\nimport android.graphics.Canvas;\nimport android.graphics.Paint;\nimport android.graphics.Path;\nimport android.util.AttributeSet;\nimport android.view.View;\n\nimport com.sdsmdg.kd.trianglify.presenters.Presenter;\nimport com.sdsmdg.kd.trianglify.R;\nimport com.sdsmdg.kd.trianglify.models.Palette;\nimport com.sdsmdg.kd.trianglify.models.Triangulation;\nimport com.sdsmdg.kd.trianglify.utilities.triangulator.Triangle2D;\n\npublic class TrianglifyView extends View implements TrianglifyViewInterface{\n    private int bleedX;\n    private int bleedY;\n    private int gridHeight;\n    private int gridWidth;\n    private int typeGrid;\n    private int variance;\n    private int cellSize;\n    private int paletteNumber;\n    private boolean fillTriangle;\n    private boolean drawStroke;\n    private boolean randomColoring;\n    private Palette palette;\n    private Triangulation triangulation;\n    private Presenter presenter;\n    private int bitmapQuality;\n\n    /**\n     *This variable is used to know whether the user wants the view to completely fill the passed gridHeight\n     * and gridWidth. If it is TRUE, then it will throw an exception whenever either bleedX or bleedY are not\n     * greater than the cellSize. If it is FALSE, then it will not check for the above condition, and hence will\n     * not throw an exception.\n     */\n    private boolean fillViewCompletely;\n\n    public TrianglifyView(Context context, AttributeSet attrs) {\n        super(context, attrs);\n        TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.TrianglifyView, 0, 0);\n        attributeSetter(a);\n        this.presenter = new Presenter(this);\n        this.setDrawingCacheEnabled(true);\n        this.setDrawingCacheQuality(DRAWING_CACHE_QUALITY_AUTO);\n    }\n\n    @Override\n    protected void onSizeChanged(int w, int h, int oldw, int oldh) {\n        super.onSizeChanged(w, h, oldw, oldh);\n        setGridWidth(w);\n        setGridHeight(h);\n        smartUpdate();\n    }\n\n    private void attributeSetter(TypedArray typedArray) {\n\n        bleedX = (int) typedArray.getDimension(R.styleable.TrianglifyView_bleedX, 0);\n        bleedY = (int) typedArray.getDimension(R.styleable.TrianglifyView_bleedY, 0);\n        variance = (int) typedArray.getDimension(R.styleable.TrianglifyView_variance, 10);\n        cellSize = (int) typedArray.getDimension(R.styleable.TrianglifyView_cellSize, 40);\n        typeGrid = typedArray.getInt(R.styleable.TrianglifyView_gridType, 0);\n        fillTriangle = typedArray.getBoolean(R.styleable.TrianglifyView_fillTriangle, true);\n        drawStroke = typedArray.getBoolean(R.styleable.TrianglifyView_fillStrokes, false);\n        paletteNumber = typedArray.getInt(R.styleable.TrianglifyView_palette, 0);\n        palette = Palette.getPalette(paletteNumber);\n        typeGrid = GRID_RECTANGLE;\n        randomColoring = typedArray.getBoolean(R.styleable.TrianglifyView_randomColoring, false);\n        fillViewCompletely = typedArray.getBoolean(R.styleable.TrianglifyView_fillViewCompletely, false);\n\n        typedArray.recycle();\n\n        if (fillViewCompletely) {\n            checkViewFilledCompletely();\n        }\n\n    }\n\n    @Override\n    public int getBleedX() {\n        return bleedX;\n    }\n\n    public TrianglifyView setBleedX(int bleedX) {\n        this.bleedX = bleedX;\n        presenter.viewState = Presenter.ViewState.GRID_PARAMETERS_CHANGED;\n        if (fillViewCompletely) {\n            checkViewFilledCompletely();\n        }\n        return this;\n    }\n\n    @Override\n    public int getBleedY() {\n        return bleedY;\n    }\n\n    public TrianglifyView setBleedY(int bleedY) {\n        this.bleedY = bleedY;\n        presenter.viewState = Presenter.ViewState.GRID_PARAMETERS_CHANGED;\n        if (fillViewCompletely) {\n            checkViewFilledCompletely();\n        }\n        return this;\n    }\n\n    @Override\n    public int getGridHeight() {\n        return gridHeight;\n    }\n\n    public TrianglifyView setGridHeight(int gridHeight) {\n        this.gridHeight = gridHeight;\n        presenter.viewState = Presenter.ViewState.GRID_PARAMETERS_CHANGED;\n        return this;\n    }\n\n    @Override\n    public int getGridWidth() {\n        return gridWidth;\n    }\n\n    public TrianglifyView setGridWidth(int gridWidth) {\n        this.gridWidth = gridWidth;\n        presenter.viewState = Presenter.ViewState.GRID_PARAMETERS_CHANGED;\n        return this;\n    }\n\n    @Override\n    public int getBitmapQuality() {\n        return bitmapQuality;\n    }\n\n    public void setBitmapQuality(int bitmapQuality) {\n        this.bitmapQuality = bitmapQuality;\n        setDrawingCacheQuality(bitmapQuality);\n    }\n\n    @Override\n    public int getTypeGrid() {\n        return typeGrid;\n    }\n\n    public TrianglifyView setTypeGrid(int typeGrid) {\n        this.typeGrid = typeGrid;\n        presenter.viewState = Presenter.ViewState.GRID_PARAMETERS_CHANGED;\n        return this;\n    }\n\n    @Override\n    public int getVariance() {\n        return variance;\n    }\n\n    public TrianglifyView setVariance(int variance) {\n        this.variance = variance;\n        presenter.viewState = Presenter.ViewState.GRID_PARAMETERS_CHANGED;\n        return this;\n    }\n\n    @Override\n    public int getCellSize() {\n        return cellSize;\n    }\n\n    public TrianglifyView setCellSize(int cellSize) {\n        this.cellSize = cellSize;\n        presenter.viewState = Presenter.ViewState.GRID_PARAMETERS_CHANGED;\n        if (fillViewCompletely) {\n            checkViewFilledCompletely();\n        }\n        return this;\n    }\n\n    public TrianglifyView setFillViewCompletely(boolean fillViewCompletely) {\n        this.fillViewCompletely = fillViewCompletely;\n        if (fillViewCompletely) {\n            checkViewFilledCompletely();\n        }\n        return this;\n    }\n\n    @Override\n    public boolean isFillViewCompletely() {\n        return fillViewCompletely;\n    }\n\n    @Override\n    public boolean isFillTriangle() {\n        return fillTriangle;\n    }\n\n    public TrianglifyView setFillTriangle(boolean fillTriangle) {\n        this.fillTriangle = fillTriangle;\n        if (presenter.viewState != Presenter.ViewState.GRID_PARAMETERS_CHANGED && presenter.viewState != Presenter.ViewState.COLOR_SCHEME_CHANGED) {\n            presenter.viewState = Presenter.ViewState.PAINT_STYLE_CHANGED;\n        }\n        return this;\n    }\n\n    @Override\n    public boolean isDrawStrokeEnabled() {\n        return drawStroke;\n    }\n\n    public TrianglifyView setDrawStrokeEnabled(boolean drawStroke) {\n        this.drawStroke = drawStroke;\n        if (presenter.viewState != Presenter.ViewState.GRID_PARAMETERS_CHANGED && presenter.viewState != Presenter.ViewState.COLOR_SCHEME_CHANGED) {\n            presenter.viewState = Presenter.ViewState.PAINT_STYLE_CHANGED;\n        }\n        return this;\n    }\n\n    @Override\n    public boolean isRandomColoringEnabled() {\n        return randomColoring;\n    }\n\n    public TrianglifyView setRandomColoring(boolean randomColoring) {\n        this.randomColoring = randomColoring;\n        if (presenter.viewState != Presenter.ViewState.GRID_PARAMETERS_CHANGED) {\n            presenter.viewState = Presenter.ViewState.COLOR_SCHEME_CHANGED;\n        }\n        return this;\n    }\n\n    @Override\n    public Palette getPalette() {\n        return palette;\n    }\n\n    public TrianglifyView setPalette(Palette palette) {\n        this.palette = palette;\n        if (presenter.viewState != Presenter.ViewState.GRID_PARAMETERS_CHANGED) {\n            presenter.viewState = Presenter.ViewState.COLOR_SCHEME_CHANGED;\n        }\n        return this;\n    }\n\n    @Override\n    public Presenter.ViewState getViewState() {\n        return presenter.viewState;\n    }\n\n    private TrianglifyView setTriangulation(Triangulation triangulation) {\n        this.triangulation = triangulation;\n        return this;\n    }\n\n\n    /**\n     * This method clears the triangulation and sets the view state to NULL_TRIANGULATION.\n     */\n    public void clearView() {\n        presenter.clearSoup();\n    }\n\n    /**\n     * invalidateView method invalidates the view by setting\n     * @param triangulation to the view instance triangulation and calling invalidate method.\n     * Once invalidated, the viewState is changed to UNCHANGED_TRIANGULATION to denote no change in the triangulation\n     * parameters after rendering the view.\n     */\n    @Override\n    public void invalidateView(Triangulation triangulation) {\n        this.setTriangulation(triangulation);\n        invalidate();\n        presenter.viewState = Presenter.ViewState.UNCHANGED_TRIANGULATION;\n    }\n\n    @Override\n    protected void onDraw(Canvas canvas) {\n        super.onDraw(canvas);\n        gridHeight = getHeight();\n        gridWidth = getWidth();\n        if (triangulation != null) {\n            plotOnCanvas(canvas);\n        } else {\n            generateAndInvalidate();\n        }\n    }\n\n    /**\n     * smartUpdate method ensures the increase in performance by generating only the necessary changes in triangulation.\n     * According to the value of viewState, it makes the necessary method call.\n     */\n    public void smartUpdate() {\n        presenter.updateView();\n    }\n\n    /**\n     * generateAndInvalidate method is called when the triangulation is to be generated from scratch. It sets the\n     * GenerateOnlyColor boolean of presenter to false so that when generateSoupAndInvalidateView is\n     * called, the grid and delaunay triangulation is regenerated according to the new parameters, followed by\n     * colorization and plotting of the triangulation onto the view.\n     */\n    public void generateAndInvalidate() {\n        presenter.setGenerateOnlyColor(false);\n        presenter.generateSoupAndInvalidateView();\n    }\n\n    private void plotOnCanvas(Canvas canvas) {\n        for (int i = 0; i < triangulation.getTriangleList().size(); i++) {\n            drawTriangle(canvas, triangulation.getTriangleList().get(i));\n        }\n    }\n\n    /**\n     * Draws triangle on the canvas object passed using the parameters of current view instance\n     * @param canvas Canvas to paint on\n     * @param triangle2D Triangle to draw on canvas\n     */\n    private void drawTriangle(Canvas canvas, Triangle2D triangle2D) {\n        Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);\n        int color = triangle2D.getColor();\n\n        /*\n         * Add 0xff000000 for alpha channel required by android.graphics.Color\n         */\n        color += 0xff000000;\n\n        paint.setColor(color);\n        paint.setStrokeWidth(4);\n        if (isFillTriangle() && isDrawStrokeEnabled()) {\n            paint.setStyle(Paint.Style.FILL_AND_STROKE);\n        } else if (isFillTriangle()) {\n            paint.setStyle(Paint.Style.FILL);\n        } else if (isDrawStrokeEnabled()) {\n            paint.setStyle(Paint.Style.STROKE);\n        } else {\n            paint.setStyle(Paint.Style.FILL_AND_STROKE);\n        }\n        paint.setAntiAlias(false);\n\n        Path path = new Path();\n        path.setFillType(Path.FillType.EVEN_ODD);\n\n        path.moveTo(triangle2D.a.x - bleedX, triangle2D.a.y - bleedY);\n        path.lineTo(triangle2D.b.x - bleedX, triangle2D.b.y - bleedY);\n        path.lineTo(triangle2D.c.x - bleedX, triangle2D.c.y - bleedY);\n        path.lineTo(triangle2D.a.x - bleedX, triangle2D.a.y - bleedY);\n        path.close();\n\n        canvas.drawPath(path, paint);\n    }\n\n    /**\n     * This method checks whether the view will be filled completely by testing if both bleedY and bleedX are\n     * greater than cellSize. If not, then it throws an illegal argument exception.\n     *\n     * Explaination for Condition:\n     * Bleed defines the dimensions of extra size that TrianglifyView view generates so that triangles\n     * on the edge don't appear to be chopped off. In most of the cases min{bleedX, bleedY} > cellSize\n     * would ensure that the view is completely filled.\n     */\n\n    private void checkViewFilledCompletely() {\n        if (bleedY <= cellSize || bleedX <= cellSize) {\n            throw new IllegalArgumentException(\"bleedY and bleedX should be larger than cellSize for view to be completely filled.\");\n        }\n    }\n\n    public Bitmap getBitmap() {\n        Bitmap resultBitmap = getDrawingCache().copy(Bitmap.Config.ARGB_8888, true);\n        this.destroyDrawingCache();\n        return resultBitmap;\n    }\n}\n"
  },
  {
    "path": "trianglify/src/main/java/com/sdsmdg/kd/trianglify/views/TrianglifyViewInterface.java",
    "content": "package com.sdsmdg.kd.trianglify.views;\n\n/**\n * Created by suyash on 18/3/17.\n */\n\nimport com.sdsmdg.kd.trianglify.models.Palette;\nimport com.sdsmdg.kd.trianglify.models.Triangulation;\nimport com.sdsmdg.kd.trianglify.presenters.Presenter;\n\npublic interface TrianglifyViewInterface {\n    int GRID_RECTANGLE = 0;\n    int GRID_CIRCLE = 1;\n\n    int getBleedX();\n    int getBleedY();\n    int getTypeGrid();\n    int getGridWidth();\n    int getGridHeight();\n    int getVariance();\n    int getCellSize();\n    int getBitmapQuality();\n    Presenter.ViewState getViewState();\n    boolean isFillViewCompletely();\n    boolean isFillTriangle();\n    boolean isDrawStrokeEnabled();\n    boolean isRandomColoringEnabled();\n    Palette getPalette();\n    void invalidateView(Triangulation triangulation);\n}\n"
  },
  {
    "path": "trianglify/src/main/res/values/attrs.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <declare-styleable name=\"TrianglifyView\">\n        <attr name=\"bleedX\" format=\"dimension\"/>\n        <attr name=\"bleedY\" format=\"dimension\"/>\n        <attr name=\"cellSize\" format=\"dimension\"/>\n        <attr name=\"variance\" format=\"dimension\"/>\n        <attr name=\"gridType\" format=\"enum\">\n            <enum name=\"rectangle\" value=\"0\"/>\n            <enum name=\"circle\" value=\"1\"/>\n        </attr>\n        <attr name=\"fillTriangle\" format=\"boolean\"/>\n        <attr name=\"fillStrokes\" format=\"boolean\"/>\n        <attr name=\"randomColoring\" format=\"boolean\"/>\n        <attr name=\"fillViewCompletely\" format=\"boolean\"/>\n        <attr name=\"palette\" format=\"enum\">\n            <enum name=\"Yl\" value=\"0\"/>\n            <enum name=\"YlGn\" value=\"1\"/>\n            <enum name=\"YlGnBu\" value=\"2\"/>\n            <enum name=\"GnBu\" value=\"3\"/>\n            <enum name=\"BuGn\" value=\"4\"/>\n            <enum name=\"PuBuGn\" value=\"5\"/>\n            <enum name=\"PuBu\" value=\"6\"/>\n            <enum name=\"BuPu\" value=\"7\"/>\n            <enum name=\"RdPu\" value=\"8\"/>\n            <enum name=\"PuRd\" value=\"9\"/>\n            <enum name=\"OrRd\" value=\"10\"/>\n            <enum name=\"YlOrRd\" value=\"11\"/>\n            <enum name=\"YlOrBr\" value=\"12\"/>\n            <enum name=\"Purples\" value=\"13\"/>\n            <enum name=\"Blues\" value=\"14\"/>\n            <enum name=\"Greens\" value=\"15\"/>\n            <enum name=\"Oranges\" value=\"16\"/>\n            <enum name=\"Reds\" value=\"17\"/>\n            <enum name=\"Greys\" value=\"18\"/>\n            <enum name=\"PuOr\" value=\"19\"/>\n            <enum name=\"BrBG\" value=\"20\"/>\n            <enum name=\"PRGn\" value=\"21\"/>\n            <enum name=\"PiYG\" value=\"22\"/>\n            <enum name=\"RdBu\" value=\"23\"/>\n            <enum name=\"RdGy\" value=\"24\"/>\n            <enum name=\"RdYlBu\" value=\"25\"/>\n            <enum name=\"Spectral\" value=\"26\"/>\n            <enum name=\"RdYlGn\" value=\"27\"/>\n        </attr>\n    </declare-styleable>\n</resources>\n"
  },
  {
    "path": "trianglify/src/main/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">trianglify</string>\n</resources>\n"
  },
  {
    "path": "trianglify/src/test/java/com/sdsmdg/kd/trianglify/ExampleUnitTest.java",
    "content": "package com.sdsmdg.kd.trianglify;\n\nimport org.junit.Test;\n\nimport static org.junit.Assert.*;\n\n/**\n * Example local unit test, which will execute on the development machine (host).\n *\n * @see <a href=\"http://d.android.com/tools/testing\">Testing documentation</a>\n */\npublic class ExampleUnitTest {\n    @Test\n    public void addition_isCorrect() throws Exception {\n        assertEquals(4, 2 + 2);\n    }\n}"
  }
]