Merge branch 'release-ios-v3.4.0' into 1ec5-release-ios-v3.4.0-beta.5-master

Also reran make style-code and manually discarded anything related to fill extrusion layers.
This commit is contained in:
Minh Nguyễn
2016-12-20 12:41:40 -08:00
153 changed files with 4808 additions and 2364 deletions

View File

@@ -171,6 +171,7 @@ public:
// Add image, bound to the style
void addImage(const std::string&, std::unique_ptr<const SpriteImage>);
void removeImage(const std::string&);
const SpriteImage* getImage(const std::string&);
// Defaults
std::string getStyleName() const;

View File

@@ -7,8 +7,8 @@ namespace style {
/**
* Initialize any GL state needed by the custom layer. This method is called once, from the
* rendering thread, at a point when the GL context is active but before rendering for the
* first time.
* main thread, at a point when the GL context is active but before rendering for the first
* time.
*
* Resources that are acquired in this method must be released in the UninitializeFunction.
*/
@@ -40,7 +40,7 @@ using CustomLayerRenderFunction = void (*)(void* context, const CustomLayerRende
/**
* Destroy any GL state needed by the custom layer, and deallocate context, if necessary. This
* method is called once, from the rendering thread, at a point when the GL context is active.
* method is called once, from the main thread, at a point when the GL context is active.
*
* Note that it may be called even when the InitializeFunction has not been called.
*/

View File

@@ -5,7 +5,7 @@
// ===========================================================================
$body_background: #fff;
$body_font: 15px/25px 'Open Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
$body_font: 14px/25px 'Open Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
$text_color: #333;
$gray_border: 1px solid #ddd;
@@ -18,9 +18,15 @@ $link_hover_color: #63b6e5;
$table_alt_row_color: #fbfbfb;
$table_border_color: #ddd;
$code_bg_color: #f6f6f6;
$color_light: #F5F8FC;
$color_darkblue: #0B293A;
$color_brightblue: #3A68D8;
$color_darkblue_lighten: rgba(11, 41, 58, 0.75);
$keyline_color: rgba(12, 40, 73, 0.08);
$code_font: Menlo, Bitstream Vera Sans Mono, Monaco, Consolas, monospacee;
$purple: #9595D1;
$blue: #4092C5;
// ----- Layout
@@ -34,38 +40,29 @@ $navigation_max_width: 300px;
$header_weight: normal;
$header_color: #555;
$header_font: 'Open Sans Bold', 'Helvetica Neue', Helvetica, Arial, sans-serif;
$header_bg_color: #3887be;
$header_link_color: #fff;
$doc_coverage_color: #999;
// ----- Breadcrumbs
$breadcrumbs_bg_color: #fbfbfb;
$breadcrumbs_border_color: #ddd;
// ----- Navigation
$navigation_max_width: 300px;
$navigation_bg_color: #fbfbfb;
$navigation_border_color: #ddd;
$navigation_title_color: rgba(0, 0, 0, 0.5);
$navigation_task_color: $link_color;
$section_name_color: $navigation_title_color;
$section_name_color: $color_darkblue;
// ----- Content
$declaration_title_language_color: #4183c4;
$declaration_language_border: 5px solid #cde9f4;
$declaration_language_border: 4px solid $color_brightblue;
$declaration_bg_color: #fdfeff;
$declaration_border_color: #ddd;
$aside_color: #aaa;
$aside_border: 5px solid lighten($aside_color, 20%);
$aside_border: 4px solid lighten($aside_color, 20%);
$aside_warning_color: #ff0000;
$aside_warning_border: 5px solid lighten($aside_warning_color, 20%);
$aside_warning_border: 4px solid lighten($aside_warning_color, 20%);
// ----- Footer
@@ -86,9 +83,8 @@ $footer_link_color: #555;
body {
margin: 0;
background: $body_background;
color: $text_color;
color: $color_darkblue;
font: $body_font;
letter-spacing: .2px;
-webkit-font-smoothing: antialiased;
box-sizing: border-box;
}
@@ -99,16 +95,16 @@ body {
font-family: $header_font;
font-size: $font-size;
font-weight: $header_weight;
color: $header_color;
color: $color_darkblue;
margin: $margin;
}
h1 {
@include heading(2.0rem, 0.5em 0 0.6em);
@include heading(1.7rem, 0.5em 0 0.6em);
}
h1 a {
color: $header_color;
color: $color_darkblue;
}
h2 {
@@ -116,7 +112,7 @@ h2 {
}
h3 {
@include heading(1rem, 1em 0 0.3em);
@include heading(14px, 1em 0 0.3em);
}
h4 {
@@ -132,10 +128,19 @@ p {
}
ul, ol {
padding: 0 0 0 2em;
padding: 0 0 0 1.5em;
margin: 0 0 0.85em;
}
ul.item-container {
padding: 0px;
}
ul:first-of-type,
ol:first-of-type {
margin: 0px;
}
blockquote {
margin: 0 0 0.85em;
padding: 0 15px;
@@ -153,11 +158,9 @@ img {
a {
color: $link_color;
text-decoration: none;
&:hover, &:focus {
color: $link_hover_color;
> *:hover, &:hover, &:focus {
opacity: 0.7;
}
&:focus {
box-shadow:inset 0 0 0 1px rgba(0,0,0,0.05);
}
@@ -168,21 +171,17 @@ a {
table {
background: $body_background;
width: 100%;
font-size: 13px;
line-height: 23px;
border-collapse: collapse;
border-spacing: 0;
overflow: auto;
margin: 0 0 0.85em;
}
tr {
&:nth-child(2n) {
background-color: $table_alt_row_color;
}
}
th, td {
padding: 6px 13px;
border: 1px solid $table_border_color;
border: 1px solid $keyline_color;
}
@@ -192,29 +191,33 @@ pre {
margin: 0 0 1.275em;
padding: .85em 1em;
overflow: auto;
background: $code_bg_color;
background: $color_light;
font-family: $code_font;
border-radius: 4px;
}
code {
font-family: $code_font;
font-size: .85em;
font-size: 13px;
line-height: .85em;
}
p, li {
> code {
background: $code_bg_color;
padding: .2em;
background: $color_light;
padding: 0.1em 0.2em;
font-weight: bold;
border: 1px solid #D5D5D5;
border-radius: 4px;
&:before, &:after {
letter-spacing: -.35em;
content: "\00a0";
}
}
}
td > code,
.graybox code {
font-weight: bold;
font-size: 12px;
}
pre code {
padding: 0;
white-space: pre;
@@ -234,7 +237,14 @@ pre code {
flex-direction: row;
}
}
.limiter {
max-width: 1360px;
margin: auto;
padding: 0px 30px;
}
.space-right2 {
margin-right: 20px;
}
// ===========================================================================
//
@@ -242,17 +252,31 @@ pre code {
//
// ===========================================================================
.header-container {
background: $color_brightblue;
}
.header {
display: flex;
padding: $gutter/2;
font-size: 0.875em;
background: $header_bg_color;
padding: 12px 0px;
font-size: 12px;
color: $doc_coverage_color;
@media (max-width: 768px) {
display: block;
}
}
.header-tag {
vertical-align: text-top;
line-height: 10px;
background: rgba(255, 255, 255, 0.1);
border-radius: 4px;
padding: 2px 5px;
margin-left: 5px;
opacity: 0.9;
}
.header-col {
margin: 0;
padding: 0 $gutter/2
margin: 5px 0 0 0;
padding: 0
}
.header-col--primary {
@@ -260,11 +284,12 @@ pre code {
}
.header-link {
font-family: $header_font;
color: $header_link_color;
}
.header-image, .header-icon {
padding-right: 6px;
padding-right: 2px;
vertical-align: -4px;
height: 16px;
}
@@ -276,11 +301,11 @@ pre code {
// ===========================================================================
.breadcrumbs {
font-size: 0.875em;
padding: $gutter / 2 $gutter;
font-size: 13px;
padding: $gutter / 2 0px;
margin: 0;
background: $breadcrumbs_bg_color;
border-bottom: 1px solid $breadcrumbs_border_color;
background: $color_light;
border-bottom: 1px solid $keyline_color;
}
.carat {
@@ -297,18 +322,17 @@ pre code {
.navigation {
order: 2;
font-size: 13px;
padding-top: 20px;
@media (min-width: 768px) {
order: 1;
width: 25%;
min-width: $navigation_min_width;
max-width: $navigation_max_width;
padding-bottom: $gutter*4;
font-size: 12px;
line-height: 20px;
overflow: hidden;
background: $navigation_bg_color;
border-right: 1px solid $navigation_border_color;
border-right: 1px solid $keyline_color;
}
}
@@ -318,18 +342,20 @@ pre code {
}
.nav-group-name {
border-bottom: 1px solid $navigation_border_color;
padding: $gutter/2 0 $gutter/2 $gutter;
padding: $gutter/2 0 $gutter/2 0px;
}
.nav-group-name-link {
.small-heading, h4 {
font-size: 13px;
font-family: $header_font;
color: $navigation_title_color;
text-transform: uppercase;
color: $color_darkblue;
letter-spacing: 1px;
}
.nav-group-tasks {
margin: $gutter/2 0;
padding: 0 0 0 $gutter/2;
padding: 0 0 0 0;
}
.nav-group-task {
@@ -341,10 +367,14 @@ pre code {
color: $navigation_task_color;
}
.nav-group-name > .small-heading,
.nav-group-task-link {
color: $navigation_task_color;
display: block;
}
.nav-group-task-link {
color: $color_darkblue_lighten;
}
// ===========================================================================
//
// Content
@@ -362,18 +392,20 @@ pre code {
}
.section {
padding: 0 $gutter * 2;
border-bottom: 1px solid $navigation_border_color;
padding: 0px 20px;
@media (max-width: 768px) {
padding: inherit;
}
}
.section-content {
margin: 0 auto;
padding: $gutter 0;
border-bottom: 1px solid $keyline_color;
}
.section-content img {
margin: 0 auto;
display: block;
}
.section-name {
@@ -381,14 +413,29 @@ pre code {
display: block;
}
.anchor-icon {
margin-left: 4px;
opacity: 0.7;
display: inline-block;
background: url("../img/link.svg");
background-repeat: no-repeat;
width: 10px;
height: 10px;
}
h1 > .anchor-icon { margin-bottom: 2px; }
.declaration .highlight {
font-size: 15px;
overflow-x: initial; // This allows the scrollbar to show up inside declarations
padding: $gutter/2 0;
line-height: 20px;
margin: 0;
background-color: transparent;
border: none;
}
.highlight a { text-decoration: underline; }
.task-group-section {
border-top: $gray_border;
}
@@ -406,10 +453,7 @@ pre code {
}
}
.item-container { }
.item {
padding-top: 8px;
width: 100%;
list-style-type: none;
@@ -421,19 +465,42 @@ pre code {
}
.token {
padding-left: 3px;
margin-left: 0px;
font-size: 1em;
word-break: break-all;
font-size: 13px;
display: flex;
padding: 5px 0px;
line-height: 14px;
}
.token-name {
display: inline-block;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.token-icon {
background: url('../img/plus.svg');
width: 17px;
display: inline-block;
vertical-align: middle;
height: 13px;
opacity: 1;
margin-left: 5px;
background-repeat: no-repeat;
}
.token-icon-minus {
background: url('../img/minus.svg');
background-repeat: no-repeat;
}
.declaration-note {
font-size: .85em;
font-size: 13px;
color: #808080;
font-style: italic;
}
}
.pointer-container {
border-bottom: $gray_border;
left: -23px;
@@ -462,9 +529,10 @@ pre code {
overflow: hidden;
.section {
background: $declaration_bg_color;
border: $gray_border;
border-top-width: 0;
padding: $gutter / 1.5 $gutter;
border: 1px solid $keyline_color;
padding: 15px 20px;
border-radius: 4px;
margin: 10px 0px 30px;
}
}
@@ -474,12 +542,14 @@ pre code {
border-left: $aside_border;
overflow-y: hidden;
.aside-title {
font-size: 9px;
font-size: 10px;
font-family: $header_font;
letter-spacing: 2px;
text-transform: uppercase;
padding-bottom: 0;
padding: 2px 8px;
display: inline;
border-radius: 4px;
margin: 0;
color: $aside_color;
-webkit-user-select: none;
}
p:last-child {
@@ -488,9 +558,16 @@ pre code {
}
.language {
background: $color_light;
border-radius: 4px;
border-left: $declaration_language_border;
}
.aside.aside-see, .aside.aside-note, {
background: $color_light;
border-radius: 4px;
.aside-title {
color: $declaration_title_language_color;
padding-left: 0px;
}
}
@@ -502,15 +579,17 @@ pre code {
}
.graybox {
border-collapse: collapse;
width: 100%;
border-collapse:separate;
border:solid $keyline_color 1px;
border-radius:6px;
-moz-border-radius:6px;
p {
margin: 0;
word-break: break-word;
min-width: 50px;
}
td {
border: $gray_border;
padding: 5px 25px 5px 10px;
vertical-align: middle;
}
@@ -520,15 +599,19 @@ pre code {
vertical-align: top;
word-break: normal;
width: 40px;
border-left: none;
border-top: none;
}
th, td {
border-right:none;
border-top: none;
}
td:first-child, th:first-child {
border-left: none;
}
tr:last-of-type td {
border-bottom: none;
}
}
.slightly-smaller {
font-size: 0.9em;
}
.show-on-github {
font-variant: small-caps;
}
.show-on-github-icon {
@@ -538,6 +621,12 @@ pre code {
padding-left: 2px;
}
.show-on-github a {
margin: 10px 0 10px;
display: inline-block;
font-size: 13px;
}
// ===========================================================================
//
@@ -546,10 +635,9 @@ pre code {
// ===========================================================================
.footer {
border-top: 1px $navigation_border_color solid;
border-top: 1px $keyline_color solid;
padding: $gutter/2 $gutter;
color: $footer_text_color;
font-size: 0.8em;
p {
display: inline;
@@ -598,3 +686,11 @@ html.dash {
src:url('../fonts/opensans-bold.eot#iefix') format('embedded-opentype'),
url('../fonts/opensans-bold.woff') format('woff');
}
.strong { font-family: $header_font;}
.text-purple { color: $purple; }
.text-blue { color: $blue; }
.keyline-purple { border-color: $purple; }
.keyline-blue { border-color: $blue; }

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg viewBox="0 0 33 33" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<path stroke="none" fill="#555" fill-rule="evenodd" d="M16.6,0.4 C7.6,0.4 0.3,7.7 0.3,16.7 C0.3,23.9 5,30 11.4,32.2 C12.2,32.3 12.5,31.8 12.5,31.4 L12.5,28.6 C8,29.6 7,26.4 7,26.4 C6.3,24.5 5.2,24 5.2,24 C3.7,23 5.3,23 5.3,23 C6.9,23.1 7.8,24.7 7.8,24.7 C9.3,27.2 11.6,26.5 12.5,26.1 C12.6,25 13.1,24.3 13.5,23.9 C9.9,23.5 6.1,22.1 6.1,15.8 C6.1,14 6.7,12.6 7.8,11.4 C7.6,11 7.1,9.3 8,7.1 C8,7.1 9.4,6.7 12.5,8.8 C13.8,8.4 15.2,8.3 16.6,8.3 C18,8.3 19.4,8.5 20.7,8.8 C23.8,6.7 25.2,7.1 25.2,7.1 C26.1,9.3 25.5,11 25.4,11.4 C26.4,12.5 27.1,14 27.1,15.8 C27.1,22.1 23.3,23.4 19.7,23.8 C20.3,24.3 20.8,25.3 20.8,26.8 L20.8,31.3 C20.8,31.7 21.1,32.2 21.9,32.1 C28.4,29.9 33,23.8 33,16.6 C32.9,7.7 25.6,0.4 16.6,0.4 L16.6,0.4 Z"></path>
<path stroke="none" fill="#3887BE" fill-rule="evenodd" d="M16.6,0.4 C7.6,0.4 0.3,7.7 0.3,16.7 C0.3,23.9 5,30 11.4,32.2 C12.2,32.3 12.5,31.8 12.5,31.4 L12.5,28.6 C8,29.6 7,26.4 7,26.4 C6.3,24.5 5.2,24 5.2,24 C3.7,23 5.3,23 5.3,23 C6.9,23.1 7.8,24.7 7.8,24.7 C9.3,27.2 11.6,26.5 12.5,26.1 C12.6,25 13.1,24.3 13.5,23.9 C9.9,23.5 6.1,22.1 6.1,15.8 C6.1,14 6.7,12.6 7.8,11.4 C7.6,11 7.1,9.3 8,7.1 C8,7.1 9.4,6.7 12.5,8.8 C13.8,8.4 15.2,8.3 16.6,8.3 C18,8.3 19.4,8.5 20.7,8.8 C23.8,6.7 25.2,7.1 25.2,7.1 C26.1,9.3 25.5,11 25.4,11.4 C26.4,12.5 27.1,14 27.1,15.8 C27.1,22.1 23.3,23.4 19.7,23.8 C20.3,24.3 20.8,25.3 20.8,26.8 L20.8,31.3 C20.8,31.7 21.1,32.2 21.9,32.1 C28.4,29.9 33,23.8 33,16.6 C32.9,7.7 25.6,0.4 16.6,0.4 L16.6,0.4 Z"></path>
</svg>

Before

Width:  |  Height:  |  Size: 916 B

After

Width:  |  Height:  |  Size: 919 B

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="10px" height="10px" viewBox="0 0 10 10" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 41.2 (35397) - http://www.bohemiancoding.com/sketch -->
<title>Page 1 Copy</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" opacity="0.461229011">
<g id="Desktop-Copy" transform="translate(-251.000000, -309.000000)" fill="#071B32">
<path d="M255.260269,316.616571 L254.592518,317.284675 C254.075101,317.80176 253.233025,317.80176 252.715608,317.284675 C252.19819,316.766905 252.19819,315.925161 252.715608,315.407433 L254.592518,313.530854 C255.110267,313.013105 255.951679,313.013105 256.469097,313.530854 C256.630773,313.69253 256.736069,313.887591 256.796969,314.093309 C256.846216,314.064798 256.896791,314.04147 256.938262,313.999999 L257.810446,313.128146 C257.698992,312.93827 257.5707,312.755526 257.407407,312.592565 C256.371266,311.556133 254.69039,311.556133 253.653918,312.592565 L251.777339,314.469143 C250.740887,315.505927 250.740887,317.18618 251.777339,318.222964 C252.813791,319.259084 254.494355,319.259084 255.530828,318.222964 L256.953171,316.800601 C256.384848,316.884186 255.801346,316.827163 255.260269,316.616571 M260.222897,313.530854 L258.345675,315.407412 C257.309534,316.444196 255.628659,316.444196 254.592518,315.407412 C254.429225,315.244782 254.301576,315.061375 254.189458,314.872162 L255.061663,313.999978 C255.103134,313.958154 255.15433,313.934204 255.203246,313.906004 C255.263504,314.112096 255.3688,314.307115 255.530807,314.469123 C256.048225,314.986851 256.89028,314.986208 257.407386,314.469123 L259.283965,312.592544 C259.801714,312.074774 259.801714,311.233051 259.283965,310.715613 C258.766838,310.198195 257.925135,310.198195 257.407386,310.715613 L256.739925,311.383716 C256.198558,311.172772 255.615036,311.116081 255.047065,311.199355 L256.469076,309.777323 C257.50586,308.740892 259.186092,308.740892 260.222876,309.777323 C261.259038,310.813817 261.259038,312.494402 260.222897,313.530854" id="Page-1-Copy"></path>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="13px" height="13px" viewBox="0 0 13 13" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" opacity="0.68516791">
<g id="Desktop-Copy" transform="translate(-633.000000, -419.000000)" fill="#3887BE">
<g id="Page-1" transform="translate(633.000000, 419.000000)">
<path d="M6.49003164,12.5026484 C9.77303945,12.5107734 12.477852,9.82012891 12.5025824,6.52148047 C12.5272621,3.23964063 9.80929727,0.507914063 6.50892227,0.497351563 C3.22951992,0.486890625 0.516836328,3.18535547 0.497336328,6.47735156 C0.477836328,9.76472656 3.19280508,12.4944727 6.49003164,12.5026484 M-1.5234375e-05,6.49233203 C8.6328125e-05,2.89442969 2.92752383,-0.00116796875 6.56371523,2.52575739e-14 C10.1085004,0.0011171875 13.0018637,2.95516406 12.9999848,6.57124609 C12.9981566,10.111918 10.0405551,13.0024883 6.42218789,13 C2.91340664,12.9976133 -0.000116796875,10.045293 -1.5234375e-05,6.49233203" id="Fill-1"></path>
<path d="M6.50034531,6.75380469 C5.4769,6.75380469 4.45345469,6.75385547 3.43000938,6.75370312 C3.37084922,6.75365234 3.2953375,6.77437109 3.25577891,6.74593359 C3.16254453,6.67885156 3.08637266,6.58795312 3.00329453,6.50665234 C3.09033359,6.42057812 3.17204063,6.32769922 3.26750938,6.2521875 C3.29904453,6.22720312 3.36592344,6.24624609 3.41665391,6.24624609 C5.47197422,6.24614453 7.52734531,6.24614453 9.58261484,6.24624609 C9.63334531,6.24624609 9.70017344,6.22720312 9.73186094,6.25213672 C9.82748203,6.32744531 9.90944297,6.42012109 9.99673594,6.50604297 C9.90543125,6.58810547 9.81905234,6.67697266 9.72013047,6.74852344 C9.68656406,6.77274609 9.62136094,6.75375391 9.57063047,6.75375391 C8.54723594,6.75380469 7.52373984,6.75380469 6.50034531,6.75380469" id="Fill-4"></path>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="13px" height="13px" viewBox="0 0 13 13" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Desktop-Copy" transform="translate(-664.000000, -384.000000)" fill="#3887BE">
<g id="Page-1-Copy-2" transform="translate(664.000000, 384.000000)">
<path d="M6.50560625,12.5026484 C9.79216875,12.4978242 12.4953055,9.79478906 12.502618,6.50583984 C12.5098797,3.21653516 9.78231719,0.489378906 6.49331719,0.497402344 C3.20421563,0.505425781 0.503719531,3.20576953 0.497321094,6.49294141 C0.490973438,9.78478516 3.21295,12.5074219 6.50560625,12.5026484 M2.03125001e-05,6.49563281 C7.10937501e-05,2.89549609 2.92552813,-0.00106640625 6.56045,2.10942375e-14 C10.1069109,0.001015625 13.0016961,2.95353906 13.0000203,6.56799609 C12.9982938,10.1104453 10.0425203,13.0021836 6.42547344,13 C2.91501641,12.9978672 -3.04687499e-05,10.0470195 2.03125001e-05,6.49563281" id="Fill-1"></path>
<path d="M6.75167695,6.75167187 L6.75167695,8.89296484 C6.75167695,9.13833984 6.74700508,9.38386719 6.75320039,9.62908984 C6.75797383,9.81850391 6.71440352,9.99253125 6.49934492,9.992125 C6.28459102,9.99161719 6.24574336,9.81753906 6.24655586,9.62817578 C6.25046602,8.68151172 6.2483332,7.73484766 6.2483332,6.75167187 L5.96527852,6.75167187 C5.14450117,6.75167187 4.32367305,6.75030078 3.5028957,6.75273828 C3.31896602,6.75329687 3.14113008,6.73039453 3.13772773,6.5040625 C3.13432539,6.27828906 3.30662617,6.2465 3.49405977,6.24700781 C4.39877852,6.24980078 5.30354805,6.24832812 6.2483332,6.24832812 L6.2483332,5.96999609 C6.2483332,5.19151953 6.25061836,4.41304297 6.24665742,3.63456641 C6.24569258,3.44982422 6.26976289,3.26711328 6.4872082,3.25975 C6.72288398,3.25172656 6.75416523,3.43834766 6.75320039,3.63456641 C6.74949336,4.4045625 6.75167695,5.17455859 6.75167695,5.94455469 L6.75167695,6.24832812 L7.06900898,6.24832812 C7.88130586,6.24832812 8.69365352,6.24980078 9.50595039,6.24716016 C9.69302852,6.24660156 9.86598945,6.27925391 9.86213008,6.50482422 C9.85821992,6.73080078 9.68002852,6.75339844 9.49609883,6.75278906 C8.68380195,6.75025 7.87150508,6.75167187 7.0592082,6.75167187 L6.75167695,6.75167187 Z" id="Fill-4"></path>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@@ -22,9 +22,11 @@ $(".token").click(function(event) {
return;
}
var link = $(this);
var linkIcon = link.find('.token-icon');
var animationDuration = 300;
var tokenOffset = "-15px";
var tokenOffset = "0px";
var original = link.css('marginLeft') == tokenOffset;
linkIcon.toggleClass('token-icon-minus');
link.animate({'margin-left':original ? "0px" : tokenOffset}, animationDuration);
$content = link.parent().parent().next();
$content.slideToggle(animationDuration);

View File

@@ -8,6 +8,15 @@
<script src="{{path_to_root}}js/jquery.min.js" defer></script>
<script src="{{path_to_root}}js/jazzy.js" defer></script>
{{{custom_head}}}
<style type="text/css">
.nav-group-name[data-name="{{name}}"] > .small-heading,
.nav-group-task[data-name="{{name}}"] {
background-color: #f5f8fc;
font-family: "Open Sans Bold";
border-left: 3px solid #3a68d8;
padding-left: 5px
}
</style>
</head>
<body>
@@ -19,19 +28,21 @@
{{> header}}
<p class="breadcrumbs">
<a class="breadcrumb" href="{{path_to_root}}index.html">{{module_name}} Reference</a>
<img class="carat" src="{{path_to_root}}img/carat.png" />
{{name}} {{kind}} Reference
</p>
<div class="breadcrumbs">
<div class="limiter">
<a class="breadcrumb" href="{{path_to_root}}index.html">{{module_name}} Reference</a>
<img class="carat" src="{{path_to_root}}img/carat.png" />
{{name}} {{kind}} Reference
</div>
</div>
<div class="content-wrapper">
<div class="content-wrapper limiter">
{{> nav}}
<article class="main-content">
<section class="section">
<div class="section-content">
{{^hide_name}}<h1>{{name}}</h1>{{/hide_name}}
{{^hide_name}}<a href="#/{{name}}"><h1 id="{{name}}">{{name}}<span class="anchor-icon" /></h1></a>{{/hide_name}}
{{#declaration}}
<div class="declaration">
<div class="language">

View File

@@ -1,3 +1,3 @@
<section class="footer">
<section class="footer limiter">
{{{copyright}}} Generated by <a class="link" href="https://github.com/realm/jazzy" target="_blank" rel="external">jazzy ♪♫ v{{jazzy_version}}</a>, a <a class="link" href="http://realm.io" target="_blank" rel="external">Realm</a> project.
</section>

View File

@@ -1,28 +1,33 @@
<header class="header">
<p class="header-col header-col--primary">
<a class="header-link" href="{{path_to_root}}index.html">
<img class="header-icon" src="{{path_to_root}}img/mapbox.svg" alt="{{module_name}} Docs"/>
</a>
{{#doc_coverage}} ({{doc_coverage}}% documented){{/doc_coverage}}
</p>
{{#github_url}}
<p class="header-col header-col--secondary">
<a class="header-link" href="{{github_url}}">
<svg class="header-icon" viewBox="0 0 33 33" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<path stroke="none" stroke-width="1" fill="white" fill-rule="evenodd" d="M16.6,0.4 C7.6,0.4 0.3,7.7 0.3,16.7 C0.3,23.9 5,30 11.4,32.2 C12.2,32.3 12.5,31.8 12.5,31.4 L12.5,28.6 C8,29.6 7,26.4 7,26.4 C6.3,24.5 5.2,24 5.2,24 C3.7,23 5.3,23 5.3,23 C6.9,23.1 7.8,24.7 7.8,24.7 C9.3,27.2 11.6,26.5 12.5,26.1 C12.6,25 13.1,24.3 13.5,23.9 C9.9,23.5 6.1,22.1 6.1,15.8 C6.1,14 6.7,12.6 7.8,11.4 C7.6,11 7.1,9.3 8,7.1 C8,7.1 9.4,6.7 12.5,8.8 C13.8,8.4 15.2,8.3 16.6,8.3 C18,8.3 19.4,8.5 20.7,8.8 C23.8,6.7 25.2,7.1 25.2,7.1 C26.1,9.3 25.5,11 25.4,11.4 C26.4,12.5 27.1,14 27.1,15.8 C27.1,22.1 23.3,23.4 19.7,23.8 C20.3,24.3 20.8,25.3 20.8,26.8 L20.8,31.3 C20.8,31.7 21.1,32.2 21.9,32.1 C28.4,29.9 33,23.8 33,16.6 C32.9,7.7 25.6,0.4 16.6,0.4 L16.6,0.4 Z"></path>
</svg>
View on GitHub
<header class="header-container">
<div class="limiter">
<div class="header">
<p class="header-col header-col--primary">
<a class="header-link" href="{{path_to_root}}index.html">
<img style="height: 25px;" class="header-icon" src="{{path_to_root}}img/mapbox.svg" alt="{{module_name}} Docs"/>
<span class='header-tag'>BRANDLESS_DOCSET_TITLE Reference</span>
</a>
{{#doc_coverage}} ({{doc_coverage}}% documented){{/doc_coverage}}
</p>
{{/github_url}}
{{#dash_url}}
<p class="header-col header-col--secondary">
<a class="header-link" href="{{dash_url}}">
<img class="header-icon" src="{{path_to_root}}img/dash.png"/>
Install in Dash
</a>
</p>
{{/dash_url}}
{{#github_url}}
<p class="header-col header-col--secondary">
<a class="header-link space-right2" href="{{github_url}}">
<svg style="margin-bottom: 1px;" class="header-icon" viewBox="0 0 33 33" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<path stroke="none" stroke-width="1" fill="white" fill-rule="evenodd" d="M16.6,0.4 C7.6,0.4 0.3,7.7 0.3,16.7 C0.3,23.9 5,30 11.4,32.2 C12.2,32.3 12.5,31.8 12.5,31.4 L12.5,28.6 C8,29.6 7,26.4 7,26.4 C6.3,24.5 5.2,24 5.2,24 C3.7,23 5.3,23 5.3,23 C6.9,23.1 7.8,24.7 7.8,24.7 C9.3,27.2 11.6,26.5 12.5,26.1 C12.6,25 13.1,24.3 13.5,23.9 C9.9,23.5 6.1,22.1 6.1,15.8 C6.1,14 6.7,12.6 7.8,11.4 C7.6,11 7.1,9.3 8,7.1 C8,7.1 9.4,6.7 12.5,8.8 C13.8,8.4 15.2,8.3 16.6,8.3 C18,8.3 19.4,8.5 20.7,8.8 C23.8,6.7 25.2,7.1 25.2,7.1 C26.1,9.3 25.5,11 25.4,11.4 C26.4,12.5 27.1,14 27.1,15.8 C27.1,22.1 23.3,23.4 19.7,23.8 C20.3,24.3 20.8,25.3 20.8,26.8 L20.8,31.3 C20.8,31.7 21.1,32.2 21.9,32.1 C28.4,29.9 33,23.8 33,16.6 C32.9,7.7 25.6,0.4 16.6,0.4 L16.6,0.4 Z"></path>
</svg>
View on GitHub
</a>
</p>
{{/github_url}}
{{#dash_url}}
<p class="header-col header-col--secondary">
<a class="header-link bold" href="{{dash_url}}">
<img style="margin-bottom: 1px;" class="header-icon" src="{{path_to_root}}img/dash.png"/>
Install in Dash
</a>
</p>
{{/dash_url}}
</div>
</div>
</header>

View File

@@ -1,12 +1,12 @@
<nav class="navigation">
<ul class="nav-groups">
{{#structure}}
<li class="nav-group-name">
<a class="nav-group-name-link" href="{{path_to_root}}{{section}}.html">{{section}}</a>
<li class="nav-group-name" data-name="{{section}}">
<a class="small-heading" href="{{path_to_root}}{{section}}.html">{{section}}<span class="anchor-icon" /></a>
<ul class="nav-group-tasks">
{{#children}}
<li class="nav-group-task">
<a class="nav-group-task-link" href="{{path_to_root}}{{url}}">{{name}}</a>
<li class="nav-group-task" data-name="{{name}}">
<a title="{{name}}" class="nav-group-task-link" href="{{path_to_root}}{{url}}">{{name}}</a>
</li>
{{/children}}
</ul>

View File

@@ -1,7 +1,7 @@
<tr>
<td>
<code>
<em>{{name}}</em>
{{name}}
</code>
</td>
<td>

View File

@@ -4,7 +4,7 @@
<a name="/{{uid}}"></a>
<a name="//apple_ref/{{language_stub}}/Section/{{name}}" class="dashAnchor"></a>
<a href="#/{{uid}}">
<h3 class="section-name">{{name}}</h3>
<h3 id="{{uid}}" class="section-name">{{name}}<span class="anchor-icon" /></h3>
</a>
</div>
{{/name}}
@@ -15,7 +15,7 @@
<code>
<a name="/{{usr}}"></a>
<a name="//apple_ref/{{language_stub}}/{{dash_type}}/{{name}}" class="dashAnchor"></a>
<a class="token" href="#/{{usr}}">{{name}}</a>
<a class="token" href="#/{{usr}}"><span class="token-name">{{name}}</span><span class="token-icon" /></a>
</code>
{{#default_impl_abstract}}
<span class="declaration-note">
@@ -29,9 +29,7 @@
{{/from_protocol_extension}}
</div>
<div class="height-container">
<div class="pointer-container"></div>
<section class="section">
<div class="pointer"></div>
{{#abstract}}
<div class="abstract">
{{{abstract}}}
@@ -49,13 +47,13 @@
{{#declaration}}
<div class="declaration">
<h4>Declaration</h4>
<div class="language">
<p class="aside-title">{{language}}</p>
<div class="language keyline-blue">
<p style="background: rgba(65, 131, 196, 0.15);" class="aside-title text-blue">{{language}}</p>
{{{declaration}}}
</div>
{{#other_language_declaration}}
<div class="language">
<p class="aside-title">Swift</p>
<div class="language keyline-purple">
<p style="background: rgba(149, 149, 209, 0.21);" class="aside-title text-purple">Swift</p>
{{{other_language_declaration}}}
</div>
{{/other_language_declaration}}
@@ -80,10 +78,10 @@
</div>
{{/return}}
{{#github_token_url}}
<div class="slightly-smaller show-on-github">
<div class="show-on-github">
<a href="{{{github_token_url}}}">
show on github
<img class="show-on-github-icon" src="{{{path_to_root}}}img/github.svg"/>
<img style="margin-bottom: 1px;" class="show-on-github-icon" src="{{{path_to_root}}}img/github.svg"/>
View Source on GitHub
</a>
</div>
{{/github_token_url}}

View File

@@ -15,9 +15,37 @@ const suffix = 'StyleLayer';
// Rename properties and keep `original` for use with setters and getters
_.forOwn(cocoaConventions, function (properties, kind) {
_.forOwn(properties, function (newName, oldName) {
spec[kind][newName] = spec[kind][oldName];
spec[kind][newName].original = oldName;
let property = spec[kind][oldName];
if (newName.startsWith('is-')) {
property.getter = newName;
newName = newName.substr(3);
}
if (newName !== oldName) {
property.original = oldName;
}
delete spec[kind][oldName];
spec[kind][newName] = property;
// Update requirements in other properties.
let updateRequirements = function (property, name) {
let requires = property.requires || [];
for (let i = 0; i < requires.length; i++) {
if (requires[i] === oldName) {
property.requires[i] = newName;
}
if (typeof requires[i] !== 'string') {
let prop = name;
_.forOwn(requires[i], function (values, name, require) {
if (name === oldName) {
require[newName] = values;
delete require[name];
}
});
}
}
};
_.forOwn(spec[kind.replace(/^layout_/, 'paint_')], updateRequirements);
_.forOwn(spec[kind.replace(/^paint_/, 'layout_')], updateRequirements);
})
});
@@ -25,12 +53,16 @@ global.objCName = function (property) {
return camelizeWithLeadingLowercase(property.name);
}
global.objCGetter = function (property) {
return camelizeWithLeadingLowercase(property.getter || property.name);
}
global.objCType = function (layerType, propertyName) {
return `${prefix}${camelize(propertyName)}`;
}
global.arrayType = function (property) {
return property.type === 'array' ? property.name.split('-').pop() : false;
return property.type === 'array' ? originalPropertyName(property).split('-').pop() : false;
};
global.testImplementation = function (property, layerType, isFunction) {
@@ -123,7 +155,7 @@ global.propertyDoc = function (propertyName, property, layerType) {
return doc.replace(/(p)ixel/gi, '$1oint').replace(/(\d)px\b/g, '$1pt');
};
global.propertyReqs = function (property, layoutPropertiesByName, type) {
global.propertyReqs = function (property, propertiesByName, type) {
return 'This property is only applied to the style if ' + property.requires.map(function (req) {
if (typeof req === 'string') {
return '`' + camelizeWithLeadingLowercase(req) + '` is non-`nil`';
@@ -131,7 +163,7 @@ global.propertyReqs = function (property, layoutPropertiesByName, type) {
return '`' + camelizeWithLeadingLowercase(req['!']) + '` is set to `nil`';
} else {
let name = Object.keys(req)[0];
return '`' + camelizeWithLeadingLowercase(name) + '` is set to an `MGLStyleValue` object containing ' + describeValue(req[name], layoutPropertiesByName[name], type);
return '`' + camelizeWithLeadingLowercase(name) + '` is set to an `MGLStyleValue` object containing ' + describeValue(req[name], propertiesByName[name], type);
}
}).join(', and ') + '. Otherwise, it is ignored.';
};
@@ -292,11 +324,11 @@ global.setSourceLayer = function() {
}
global.mbglType = function(property) {
let mbglType = camelize(property.name) + 'Type';
if (/-translate-anchor$/.test(property.name)) {
let mbglType = camelize(originalPropertyName(property)) + 'Type';
if (/-translate-anchor$/.test(originalPropertyName(property))) {
mbglType = 'TranslateAnchorType';
}
if (/-(rotation|pitch)-alignment$/.test(property.name)) {
if (/-(rotation|pitch)-alignment$/.test(originalPropertyName(property))) {
mbglType = 'AlignmentType';
}
return mbglType;
@@ -304,7 +336,7 @@ global.mbglType = function(property) {
const layerH = ejs.compile(fs.readFileSync('platform/darwin/src/MGLStyleLayer.h.ejs', 'utf8'), { strict: true });
const layerM = ejs.compile(fs.readFileSync('platform/darwin/src/MGLStyleLayer.mm.ejs', 'utf8'), { strict: true});
const testLayers = ejs.compile(fs.readFileSync('platform/darwin/src/MGLRuntimeStylingTests.m.ejs', 'utf8'), { strict: true});
const testLayers = ejs.compile(fs.readFileSync('platform/darwin/test/MGLStyleLayerTests.m.ejs', 'utf8'), { strict: true});
const categoryH = ejs.compile(fs.readFileSync('platform/darwin/src/NSValue+MGLStyleEnumAttributeAdditions.h.ejs', 'utf8'), { strict: true});
const categoryM = ejs.compile(fs.readFileSync('platform/darwin/src/NSValue+MGLStyleEnumAttributeAdditions.mm.ejs', 'utf8'), { strict: true});

View File

@@ -1,9 +1,31 @@
{
"layout_symbol": {
"icon-image": "icon-image-name"
"icon-allow-overlap": "icon-allows-overlap",
"icon-image": "icon-image-name",
"icon-ignore-placement": "icon-ignores-placement",
"icon-keep-upright": "keeps-icon-upright",
"icon-optional": "is-icon-optional",
"icon-rotate": "icon-rotation",
"icon-size": "icon-scale",
"symbol-avoid-edges": "symbol-avoids-edges",
"text-allow-overlap": "text-allows-overlap",
"text-ignore-placement": "text-ignores-placement",
"text-justify": "text-justification",
"text-keep-upright": "keeps-text-upright",
"text-max-angle": "maximum-text-angle",
"text-max-width": "maximum-text-width",
"text-optional": "is-text-optional",
"text-rotate": "text-rotation"
},
"paint_raster": {
"raster-brightness-min": "minimum-raster-brightness",
"raster-brightness-max": "maximum-raster-brightness"
"raster-brightness-max": "maximum-raster-brightness",
"raster-hue-rotate": "raster-hue-rotation"
},
"paint_line": {
"line-dasharray": "line-dash-pattern"
},
"paint_fill": {
"fill-antialias": "is-fill-antialiased"
}
}

View File

@@ -45,6 +45,12 @@
}
},
"paint_symbol": {
"icon-color": {
"doc": "The tint color to apply to the icon. The `icon-image-name` property must be set to a template image."
},
"icon-halo-color": {
"doc": "The color of the icon’s halo. The `icon-image-name` property must be set to a template image."
},
"icon-translate": {
"doc": "Distance that the icon's anchor is moved from its original placement."
},

View File

@@ -0,0 +1,62 @@
#import <Foundation/Foundation.h>
#import <CoreGraphics/CoreGraphics.h>
#import <CoreLocation/CoreLocation.h>
#import "MGLTypes.h"
NS_ASSUME_NONNULL_BEGIN
/**
Information about an attribution statement, usually a copyright or trademark
statement, associated with a map content source.
*/
@interface MGLAttributionInfo : NSObject
/**
Returns an initialized attribution info object with the given title and URL.
@param title The attribution statement’s title.
@param URL A URL to more information about the entity named in the attribution.
@return An initialized attribution info object.
*/
- (instancetype)initWithTitle:(NSAttributedString *)title URL:(nullable NSURL *)URL;
/**
The attribution statement’s attributed title text.
*/
@property (nonatomic) NSAttributedString *title;
/**
The URL to more information about the entity named in the attribution.
If this property is set, the attribution statement should be displayed as a
hyperlink or action button. Otherwise, if it is `nil`, the attribution
statement should be displayed as plain text.
*/
@property (nonatomic, nullable) NSURL *URL;
/**
A Boolean value indicating whether the attribution statement is a shortcut to a
feedback tool.
If this property is set, the statement should be treated as a way for the user
to provide feedback rather than an attribution statement.
*/
@property (nonatomic, getter=isFeedbackLink) BOOL feedbackLink;
/**
Returns a copy of the `URL` property modified to account for the given center
coordinate and zoom level.
@param centerCoordinate The map’s center coordinate.
@param zoomLevel The map’s zoom level. See `MGLMapView`’s `zoomLevel` property
for more information.
@return A modified URL containing a fragment that points to the specified
viewport. If the `feedbackLink` property is set to `NO`, this method returns
`nil`.
*/
- (nullable NSURL *)feedbackURLAtCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate zoomLevel:(double)zoomLevel;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,195 @@
#import "MGLAttributionInfo_Private.h"
#if TARGET_OS_IPHONE
#import <UIKit/UIKit.h>
#else
#import <Cocoa/Cocoa.h>
#endif
#import "MGLMapCamera.h"
#import "NSArray+MGLAdditions.h"
#import "NSString+MGLAdditions.h"
#include <string>
@implementation MGLAttributionInfo
+ (NS_ARRAY_OF(MGLAttributionInfo *) *)attributionInfosFromHTMLString:(nullable NSString *)htmlString fontSize:(CGFloat)fontSize linkColor:(nullable MGLColor *)linkColor {
if (!htmlString) {
return @[];
}
NSDictionary *options = @{
NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType,
NSCharacterEncodingDocumentAttribute: @(NSUTF8StringEncoding),
};
// Apply a bogus, easily detectable style rule to any feedback link, since
// NSAttributedString doesn’t preserve the class attribute.
NSMutableString *css = [NSMutableString stringWithString:
@".mapbox-improve-map { -webkit-text-stroke-width: 1000px; }"];
if (fontSize) {
[css appendFormat:@"html { font-size: %.1fpx; }", fontSize];
}
if (linkColor) {
CGFloat red;
CGFloat green;
CGFloat blue;
CGFloat alpha;
#if !TARGET_OS_IPHONE
linkColor = [linkColor colorUsingColorSpaceName:NSCalibratedRGBColorSpace];
#endif
[linkColor getRed:&red green:&green blue:&blue alpha:&alpha];
[css appendFormat:
@"a:link { color: rgba(%f%%, %f%%, %f%%, %f); }",
red * 100, green * 100, blue * 100, alpha];
}
NSString *styledHTML = [NSString stringWithFormat:@"<style type='text/css'>%@</style>%@", css, htmlString];
NSData *htmlData = [styledHTML dataUsingEncoding:NSUTF8StringEncoding];
#if TARGET_OS_IPHONE
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithData:htmlData
options:options
documentAttributes:nil
error:NULL];
#else
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithHTML:htmlData
options:options
documentAttributes:nil];
#endif
NSMutableArray *infos = [NSMutableArray array];
[attributedString enumerateAttribute:NSLinkAttributeName
inRange:attributedString.mgl_wholeRange
options:0
usingBlock:
^(id _Nullable value, NSRange range, BOOL * _Nonnull stop) {
NSCAssert(!value || [value isKindOfClass:[NSURL class]], @"If present, URL attribute must be an NSURL.");
// Detect feedback links by the bogus style rule applied above.
NSNumber *strokeWidth = [attributedString attribute:NSStrokeWidthAttributeName
atIndex:range.location
effectiveRange:NULL];
BOOL isFeedbackLink = NO;
if ([strokeWidth floatValue] > 100) {
isFeedbackLink = YES;
[attributedString removeAttribute:NSStrokeWidthAttributeName range:range];
}
// Omit whitespace-only strings.
NSAttributedString *title = [[attributedString attributedSubstringFromRange:range]
mgl_attributedStringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
if (!title.length) {
return;
}
MGLAttributionInfo *info = [[MGLAttributionInfo alloc] initWithTitle:title URL:value];
info.feedbackLink = isFeedbackLink;
[infos addObject:info];
}];
return infos;
}
+ (NSAttributedString *)attributedStringForAttributionInfos:(NS_ARRAY_OF(MGLAttributionInfo *) *)attributionInfos {
NSMutableArray *titles = [NSMutableArray arrayWithCapacity:attributionInfos.count];
for (MGLAttributionInfo *info in attributionInfos) {
NSMutableAttributedString *title = info.title.mutableCopy;
if (info.URL) {
[title addAttribute:NSLinkAttributeName value:info.URL range:title.mgl_wholeRange];
}
[titles addObject:title];
}
return [titles mgl_attributedComponentsJoinedByString:@" "];
}
- (instancetype)initWithTitle:(NSAttributedString *)title URL:(NSURL *)URL {
if (self = [super init]) {
_title = title;
_URL = URL;
}
return self;
}
- (nullable NSURL *)feedbackURLAtCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate zoomLevel:(double)zoomLevel {
if (!self.feedbackLink) {
return nil;
}
NSURLComponents *components = [NSURLComponents componentsWithURL:self.URL resolvingAgainstBaseURL:NO];
components.fragment = [NSString stringWithFormat:@"/%.5f/%.5f/%i",
centerCoordinate.longitude, centerCoordinate.latitude, (int)round(zoomLevel + 1)];
return components.URL;
}
- (BOOL)isEqual:(id)object {
return [object isKindOfClass:[self class]] && [[object title] isEqual:self.title] && [[object URL] isEqual:self.URL];
}
- (NSUInteger)hash {
return self.title.hash + self.URL.hash;
}
/**
Returns whether the given attribution info object overlaps with the receiver by
its plain text title.
@return `NSOrderedAscending` if the given object is a superset of the receiver,
`NSOrderedDescending` if it is a subset of the receiver, or `NSOrderedSame`
if there is no overlap.
*/
- (NSComparisonResult)subsetCompare:(MGLAttributionInfo *)otherInfo {
NSString *title = self.title.string;
NSString *otherTitle = otherInfo.title.string;
if ([title containsString:otherTitle]) {
return NSOrderedDescending;
}
if ([otherTitle containsString:title]) {
return NSOrderedAscending;
}
return NSOrderedSame;
}
@end
@implementation NSMutableArray (MGLAttributionInfoAdditions)
- (void)growArrayByAddingAttributionInfo:(MGLAttributionInfo *)info {
__block BOOL didInsertInfo = NO;
__block BOOL shouldAddInfo = YES;
[self enumerateObjectsUsingBlock:^(MGLAttributionInfo * _Nonnull existingInfo, NSUInteger idx, BOOL * _Nonnull stop) {
switch ([info subsetCompare:existingInfo]) {
case NSOrderedDescending:
// The existing info object is a subset of the one we’re adding.
// Replace the existing object the first time we find a subset;
// remove the existing object every time after that.
if (didInsertInfo) {
[self removeObjectAtIndex:idx];
} else {
[self replaceObjectAtIndex:idx withObject:info];
didInsertInfo = YES;
}
break;
case NSOrderedAscending:
// The info object we’re adding is a subset of the existing one.
// Don’t add the object and stop looking.
shouldAddInfo = NO;
*stop = YES;
break;
default:
break;
}
}];
if (shouldAddInfo && !didInsertInfo) {
// No overlapping infos were found, so append the info object.
[self addObject:info];
}
}
- (void)growArrayByAddingAttributionInfosFromArray:(NS_ARRAY_OF(MGLAttributionInfo *) *)infos {
for (MGLAttributionInfo *info in infos) {
[self growArrayByAddingAttributionInfo:info];
}
}
@end

View File

@@ -0,0 +1,48 @@
#import <Foundation/Foundation.h>
#import <CoreGraphics/CoreGraphics.h>
#import <CoreLocation/CoreLocation.h>
#import "MGLAttributionInfo.h"
NS_ASSUME_NONNULL_BEGIN
@interface MGLAttributionInfo (Private)
/**
Parses and returns the attribution infos contained in the given HTML source
code string.
@param htmlString The HTML source code to parse.
@param fontSize The default text size in points.
@param linkColor The default link color.
*/
+ (NS_ARRAY_OF(MGLAttributionInfo *) *)attributionInfosFromHTMLString:(nullable NSString *)htmlString fontSize:(CGFloat)fontSize linkColor:(nullable MGLColor *)linkColor;
+ (NSAttributedString *)attributedStringForAttributionInfos:(NS_ARRAY_OF(MGLAttributionInfo *) *)attributionInfos;
@end
@interface NSMutableArray (MGLAttributionInfoAdditions)
/**
Adds the given attribution info object to the receiver as long as it isn’t
redundant to any object already in the receiver. Any existing object that is
redundant to the given object is replaced by the given object.
@param info The info object to add to the receiver.
@return True if the given info object was added to the receiver.
*/
- (void)growArrayByAddingAttributionInfo:(MGLAttributionInfo *)info;
/**
Adds each of the given attribution info objects to the receiver as long as it
isn’t redundant to any object already in the receiver. Any existing object that
is redundant to the given object is replaced by the given object.
@param infos An array of info objects to add to the receiver.
*/
- (void)growArrayByAddingAttributionInfosFromArray:(NS_ARRAY_OF(MGLAttributionInfo *) *)infos;
@end
NS_ASSUME_NONNULL_END

View File

@@ -26,14 +26,24 @@
if (self = [super initWithIdentifier:identifier]) {
auto layer = std::make_unique<mbgl::style::BackgroundLayer>(identifier.UTF8String);
_pendingLayer = std::move(layer);
_rawLayer = _pendingLayer.get();
self.rawLayer = _pendingLayer.get();
}
return self;
}
#pragma mark - Adding to and removing from a map view
- (mbgl::style::BackgroundLayer *)rawLayer
{
return (mbgl::style::BackgroundLayer *)super.rawLayer;
}
- (void)addToMapView:(MGLMapView *)mapView
- (void)setRawLayer:(mbgl::style::BackgroundLayer *)rawLayer
{
super.rawLayer = rawLayer;
}
#pragma mark - Adding to and removing from a map view
- (void)addToMapView:(MGLMapView *)mapView belowLayer:(MGLStyleLayer *)otherLayer
{
if (_pendingLayer == nullptr) {
[NSException raise:@"MGLRedundantLayerException"
@@ -41,11 +51,6 @@
"to the style more than once is invalid.", self, mapView.style];
}
[self addToMapView:mapView belowLayer:nil];
}
- (void)addToMapView:(MGLMapView *)mapView belowLayer:(MGLStyleLayer *)otherLayer
{
if (otherLayer) {
const mbgl::optional<std::string> belowLayerId{otherLayer.identifier.UTF8String};
mapView.mbglMap->addLayer(std::move(_pendingLayer), belowLayerId);
@@ -57,7 +62,7 @@
- (void)removeFromMapView:(MGLMapView *)mapView
{
_pendingLayer = nullptr;
_rawLayer = nullptr;
self.rawLayer = nullptr;
auto removedLayer = mapView.mbglMap->removeLayer(self.identifier.UTF8String);
if (!removedLayer) {
@@ -72,7 +77,7 @@
removedLayer.release();
_pendingLayer = std::unique_ptr<mbgl::style::BackgroundLayer>(layer);
_rawLayer = _pendingLayer.get();
self.rawLayer = _pendingLayer.get();
}
#pragma mark - Accessing the Paint Attributes
@@ -81,13 +86,13 @@
MGLAssertStyleLayerIsValid();
auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toPropertyValue(backgroundColor);
_rawLayer->setBackgroundColor(mbglValue);
self.rawLayer->setBackgroundColor(mbglValue);
}
- (MGLStyleValue<MGLColor *> *)backgroundColor {
MGLAssertStyleLayerIsValid();
auto propertyValue = _rawLayer->getBackgroundColor() ?: _rawLayer->getDefaultBackgroundColor();
auto propertyValue = self.rawLayer->getBackgroundColor() ?: self.rawLayer->getDefaultBackgroundColor();
return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toStyleValue(propertyValue);
}
@@ -95,13 +100,13 @@
MGLAssertStyleLayerIsValid();
auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(backgroundOpacity);
_rawLayer->setBackgroundOpacity(mbglValue);
self.rawLayer->setBackgroundOpacity(mbglValue);
}
- (MGLStyleValue<NSNumber *> *)backgroundOpacity {
MGLAssertStyleLayerIsValid();
auto propertyValue = _rawLayer->getBackgroundOpacity() ?: _rawLayer->getDefaultBackgroundOpacity();
auto propertyValue = self.rawLayer->getBackgroundOpacity() ?: self.rawLayer->getDefaultBackgroundOpacity();
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
}
@@ -109,13 +114,13 @@
MGLAssertStyleLayerIsValid();
auto mbglValue = MGLStyleValueTransformer<std::string, NSString *>().toPropertyValue(backgroundPattern);
_rawLayer->setBackgroundPattern(mbglValue);
self.rawLayer->setBackgroundPattern(mbglValue);
}
- (MGLStyleValue<NSString *> *)backgroundPattern {
MGLAssertStyleLayerIsValid();
auto propertyValue = _rawLayer->getBackgroundPattern() ?: _rawLayer->getDefaultBackgroundPattern();
auto propertyValue = self.rawLayer->getBackgroundPattern() ?: self.rawLayer->getDefaultBackgroundPattern();
return MGLStyleValueTransformer<std::string, NSString *>().toStyleValue(propertyValue);
}

View File

@@ -39,15 +39,26 @@ namespace mbgl {
if (self = [super initWithIdentifier:identifier source:source]) {
auto layer = std::make_unique<mbgl::style::CircleLayer>(identifier.UTF8String, source.identifier.UTF8String);
_pendingLayer = std::move(layer);
_rawLayer = _pendingLayer.get();
self.rawLayer = _pendingLayer.get();
}
return self;
}
- (mbgl::style::CircleLayer *)rawLayer
{
return (mbgl::style::CircleLayer *)super.rawLayer;
}
- (void)setRawLayer:(mbgl::style::CircleLayer *)rawLayer
{
super.rawLayer = rawLayer;
}
- (NSString *)sourceLayerIdentifier
{
MGLAssertStyleLayerIsValid();
auto layerID = _rawLayer->getSourceLayer();
auto layerID = self.rawLayer->getSourceLayer();
return layerID.empty() ? nil : @(layerID.c_str());
}
@@ -55,25 +66,26 @@ namespace mbgl {
{
MGLAssertStyleLayerIsValid();
_rawLayer->setSourceLayer(sourceLayerIdentifier.UTF8String ?: "");
self.rawLayer->setSourceLayer(sourceLayerIdentifier.UTF8String ?: "");
}
- (void)setPredicate:(NSPredicate *)predicate
{
MGLAssertStyleLayerIsValid();
_rawLayer->setFilter(predicate.mgl_filter);
self.rawLayer->setFilter(predicate.mgl_filter);
}
- (NSPredicate *)predicate
{
MGLAssertStyleLayerIsValid();
return [NSPredicate mgl_predicateWithFilter:_rawLayer->getFilter()];
return [NSPredicate mgl_predicateWithFilter:self.rawLayer->getFilter()];
}
#pragma mark - Adding to and removing from a map view
- (void)addToMapView:(MGLMapView *)mapView
#pragma mark - Adding to and removing from a map view
- (void)addToMapView:(MGLMapView *)mapView belowLayer:(MGLStyleLayer *)otherLayer
{
if (_pendingLayer == nullptr) {
[NSException raise:@"MGLRedundantLayerException"
@@ -81,11 +93,6 @@ namespace mbgl {
"to the style more than once is invalid.", self, mapView.style];
}
[self addToMapView:mapView belowLayer:nil];
}
- (void)addToMapView:(MGLMapView *)mapView belowLayer:(MGLStyleLayer *)otherLayer
{
if (otherLayer) {
const mbgl::optional<std::string> belowLayerId{otherLayer.identifier.UTF8String};
mapView.mbglMap->addLayer(std::move(_pendingLayer), belowLayerId);
@@ -97,7 +104,7 @@ namespace mbgl {
- (void)removeFromMapView:(MGLMapView *)mapView
{
_pendingLayer = nullptr;
_rawLayer = nullptr;
self.rawLayer = nullptr;
auto removedLayer = mapView.mbglMap->removeLayer(self.identifier.UTF8String);
if (!removedLayer) {
@@ -112,7 +119,7 @@ namespace mbgl {
removedLayer.release();
_pendingLayer = std::unique_ptr<mbgl::style::CircleLayer>(layer);
_rawLayer = _pendingLayer.get();
self.rawLayer = _pendingLayer.get();
}
#pragma mark - Accessing the Paint Attributes
@@ -121,13 +128,13 @@ namespace mbgl {
MGLAssertStyleLayerIsValid();
auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(circleBlur);
_rawLayer->setCircleBlur(mbglValue);
self.rawLayer->setCircleBlur(mbglValue);
}
- (MGLStyleValue<NSNumber *> *)circleBlur {
MGLAssertStyleLayerIsValid();
auto propertyValue = _rawLayer->getCircleBlur() ?: _rawLayer->getDefaultCircleBlur();
auto propertyValue = self.rawLayer->getCircleBlur() ?: self.rawLayer->getDefaultCircleBlur();
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
}
@@ -135,13 +142,13 @@ namespace mbgl {
MGLAssertStyleLayerIsValid();
auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toPropertyValue(circleColor);
_rawLayer->setCircleColor(mbglValue);
self.rawLayer->setCircleColor(mbglValue);
}
- (MGLStyleValue<MGLColor *> *)circleColor {
MGLAssertStyleLayerIsValid();
auto propertyValue = _rawLayer->getCircleColor() ?: _rawLayer->getDefaultCircleColor();
auto propertyValue = self.rawLayer->getCircleColor() ?: self.rawLayer->getDefaultCircleColor();
return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toStyleValue(propertyValue);
}
@@ -149,13 +156,13 @@ namespace mbgl {
MGLAssertStyleLayerIsValid();
auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(circleOpacity);
_rawLayer->setCircleOpacity(mbglValue);
self.rawLayer->setCircleOpacity(mbglValue);
}
- (MGLStyleValue<NSNumber *> *)circleOpacity {
MGLAssertStyleLayerIsValid();
auto propertyValue = _rawLayer->getCircleOpacity() ?: _rawLayer->getDefaultCircleOpacity();
auto propertyValue = self.rawLayer->getCircleOpacity() ?: self.rawLayer->getDefaultCircleOpacity();
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
}
@@ -163,13 +170,13 @@ namespace mbgl {
MGLAssertStyleLayerIsValid();
auto mbglValue = MGLStyleValueTransformer<mbgl::style::CirclePitchScaleType, NSValue *, mbgl::style::CirclePitchScaleType, MGLCirclePitchScale>().toEnumPropertyValue(circlePitchScale);
_rawLayer->setCirclePitchScale(mbglValue);
self.rawLayer->setCirclePitchScale(mbglValue);
}
- (MGLStyleValue<NSValue *> *)circlePitchScale {
MGLAssertStyleLayerIsValid();
auto propertyValue = _rawLayer->getCirclePitchScale() ?: _rawLayer->getDefaultCirclePitchScale();
auto propertyValue = self.rawLayer->getCirclePitchScale() ?: self.rawLayer->getDefaultCirclePitchScale();
return MGLStyleValueTransformer<mbgl::style::CirclePitchScaleType, NSValue *, mbgl::style::CirclePitchScaleType, MGLCirclePitchScale>().toEnumStyleValue(propertyValue);
}
@@ -177,13 +184,13 @@ namespace mbgl {
MGLAssertStyleLayerIsValid();
auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(circleRadius);
_rawLayer->setCircleRadius(mbglValue);
self.rawLayer->setCircleRadius(mbglValue);
}
- (MGLStyleValue<NSNumber *> *)circleRadius {
MGLAssertStyleLayerIsValid();
auto propertyValue = _rawLayer->getCircleRadius() ?: _rawLayer->getDefaultCircleRadius();
auto propertyValue = self.rawLayer->getCircleRadius() ?: self.rawLayer->getDefaultCircleRadius();
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
}
@@ -191,13 +198,13 @@ namespace mbgl {
MGLAssertStyleLayerIsValid();
auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toPropertyValue(circleStrokeColor);
_rawLayer->setCircleStrokeColor(mbglValue);
self.rawLayer->setCircleStrokeColor(mbglValue);
}
- (MGLStyleValue<MGLColor *> *)circleStrokeColor {
MGLAssertStyleLayerIsValid();
auto propertyValue = _rawLayer->getCircleStrokeColor() ?: _rawLayer->getDefaultCircleStrokeColor();
auto propertyValue = self.rawLayer->getCircleStrokeColor() ?: self.rawLayer->getDefaultCircleStrokeColor();
return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toStyleValue(propertyValue);
}
@@ -205,13 +212,13 @@ namespace mbgl {
MGLAssertStyleLayerIsValid();
auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(circleStrokeOpacity);
_rawLayer->setCircleStrokeOpacity(mbglValue);
self.rawLayer->setCircleStrokeOpacity(mbglValue);
}
- (MGLStyleValue<NSNumber *> *)circleStrokeOpacity {
MGLAssertStyleLayerIsValid();
auto propertyValue = _rawLayer->getCircleStrokeOpacity() ?: _rawLayer->getDefaultCircleStrokeOpacity();
auto propertyValue = self.rawLayer->getCircleStrokeOpacity() ?: self.rawLayer->getDefaultCircleStrokeOpacity();
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
}
@@ -219,13 +226,13 @@ namespace mbgl {
MGLAssertStyleLayerIsValid();
auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(circleStrokeWidth);
_rawLayer->setCircleStrokeWidth(mbglValue);
self.rawLayer->setCircleStrokeWidth(mbglValue);
}
- (MGLStyleValue<NSNumber *> *)circleStrokeWidth {
MGLAssertStyleLayerIsValid();
auto propertyValue = _rawLayer->getCircleStrokeWidth() ?: _rawLayer->getDefaultCircleStrokeWidth();
auto propertyValue = self.rawLayer->getCircleStrokeWidth() ?: self.rawLayer->getDefaultCircleStrokeWidth();
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
}
@@ -233,13 +240,13 @@ namespace mbgl {
MGLAssertStyleLayerIsValid();
auto mbglValue = MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toPropertyValue(circleTranslate);
_rawLayer->setCircleTranslate(mbglValue);
self.rawLayer->setCircleTranslate(mbglValue);
}
- (MGLStyleValue<NSValue *> *)circleTranslate {
MGLAssertStyleLayerIsValid();
auto propertyValue = _rawLayer->getCircleTranslate() ?: _rawLayer->getDefaultCircleTranslate();
auto propertyValue = self.rawLayer->getCircleTranslate() ?: self.rawLayer->getDefaultCircleTranslate();
return MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toStyleValue(propertyValue);
}
@@ -247,13 +254,13 @@ namespace mbgl {
MGLAssertStyleLayerIsValid();
auto mbglValue = MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLCircleTranslateAnchor>().toEnumPropertyValue(circleTranslateAnchor);
_rawLayer->setCircleTranslateAnchor(mbglValue);
self.rawLayer->setCircleTranslateAnchor(mbglValue);
}
- (MGLStyleValue<NSValue *> *)circleTranslateAnchor {
MGLAssertStyleLayerIsValid();
auto propertyValue = _rawLayer->getCircleTranslateAnchor() ?: _rawLayer->getDefaultCircleTranslateAnchor();
auto propertyValue = self.rawLayer->getCircleTranslateAnchor() ?: self.rawLayer->getDefaultCircleTranslateAnchor();
return MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLCircleTranslateAnchor>().toEnumStyleValue(propertyValue);
}

View File

@@ -19,7 +19,7 @@ NS_ASSUME_NONNULL_BEGIN
using `-[MGLMapView visibleFeaturesAtPoint:]` and related methods. Each feature
object associates a shape with an identifier and attributes as specified by the
source. Like ordinary `MGLAnnotation` objects, some kinds of `MGLFeature`
objects can also be added to a map view using an `MGLGeoJSONSource` or
objects can also be added to a map view using an `MGLShapeSource` or
`-[MGLMapView addAnnotations:]` and related methods.
*/
@protocol MGLFeature <MGLAnnotation>
@@ -52,7 +52,7 @@ NS_ASSUME_NONNULL_BEGIN
layer reference. Note that while it is possible to change this value on feature
instances obtained from `-[MGLMapView visibleFeaturesAtPoint:]` and related
methods, there will be no effect on the map. Setting this value can be useful
when the feature instance is used to initialize an `MGLGeoJSONSource` and that
when the feature instance is used to initialize an `MGLShapeSource` and that
source is added to the map and styled.
*/
@property (nonatomic, copy, nullable) id identifier;
@@ -87,7 +87,7 @@ NS_ASSUME_NONNULL_BEGIN
layer references. Note that while it is possible to change this value on feature
instances obtained from `-[MGLMapView visibleFeaturesAtPoint:]` and related
methods, there will be no effect on the map. Setting this value can be useful
when the feature instance is used to initialize an `MGLGeoJSONSource` and that
when the feature instance is used to initialize an `MGLShapeSource` and that
source is added to the map and styled.
*/
@property (nonatomic, copy) NS_DICTIONARY_OF(NSString *, id) *attributes;

View File

@@ -14,9 +14,10 @@
#import "NSExpression+MGLAdditions.h"
#import <mbgl/util/geometry.hpp>
#import <mbgl/style/conversion/geojson.hpp>
#import <mapbox/geometry/feature.hpp>
@interface MGLPointFeature () <MGLFeaturePrivate>
@interface MGLPointFeature ()
@end
@implementation MGLPointFeature
@@ -32,13 +33,13 @@
return NSDictionaryFeatureForGeometry([super geoJSONDictionary], self.attributes, self.identifier);
}
- (mbgl::Feature)mbglFeature {
return mbglFeature([self featureObject], identifier, self.attributes);
- (mbgl::GeoJSON)geoJSONObject {
return mbglFeature({[self geometryObject]}, identifier, self.attributes);
}
@end
@interface MGLPolylineFeature () <MGLFeaturePrivate>
@interface MGLPolylineFeature ()
@end
@implementation MGLPolylineFeature
@@ -54,13 +55,13 @@
return NSDictionaryFeatureForGeometry([super geoJSONDictionary], self.attributes, self.identifier);
}
- (mbgl::Feature)mbglFeature {
return mbglFeature([self featureObject], identifier, self.attributes);
- (mbgl::GeoJSON)geoJSONObject {
return mbglFeature({[self geometryObject]}, identifier, self.attributes);
}
@end
@interface MGLPolygonFeature () <MGLFeaturePrivate>
@interface MGLPolygonFeature ()
@end
@implementation MGLPolygonFeature
@@ -76,13 +77,13 @@
return NSDictionaryFeatureForGeometry([super geoJSONDictionary], self.attributes, self.identifier);
}
- (mbgl::Feature)mbglFeature {
return mbglFeature([self featureObject], identifier, self.attributes);
- (mbgl::GeoJSON)geoJSONObject {
return mbglFeature({[self geometryObject]}, identifier, self.attributes);
}
@end
@interface MGLPointCollectionFeature () <MGLFeaturePrivate>
@interface MGLPointCollectionFeature ()
@end
@implementation MGLPointCollectionFeature
@@ -98,13 +99,13 @@
return NSDictionaryFeatureForGeometry([super geoJSONDictionary], self.attributes, self.identifier);
}
- (mbgl::Feature)mbglFeature {
return mbglFeature([self featureObject], identifier, self.attributes);
- (mbgl::GeoJSON)geoJSONObject {
return mbglFeature({[self geometryObject]}, identifier, self.attributes);
}
@end
@interface MGLMultiPolylineFeature () <MGLFeaturePrivate>
@interface MGLMultiPolylineFeature ()
@end
@implementation MGLMultiPolylineFeature
@@ -120,13 +121,13 @@
return NSDictionaryFeatureForGeometry([super geoJSONDictionary], self.attributes, self.identifier);
}
- (mbgl::Feature)mbglFeature {
return mbglFeature([self featureObject], identifier, self.attributes);
- (mbgl::GeoJSON)geoJSONObject {
return mbglFeature({[self geometryObject]}, identifier, self.attributes);
}
@end
@interface MGLMultiPolygonFeature () <MGLFeaturePrivate>
@interface MGLMultiPolygonFeature ()
@end
@implementation MGLMultiPolygonFeature
@@ -142,13 +143,13 @@
return NSDictionaryFeatureForGeometry([super geoJSONDictionary], self.attributes, self.identifier);
}
- (mbgl::Feature)mbglFeature {
return mbglFeature([self featureObject], identifier, self.attributes);
- (mbgl::GeoJSON)geoJSONObject {
return mbglFeature({[self geometryObject]}, identifier, self.attributes);
}
@end
@interface MGLShapeCollectionFeature () <MGLFeaturePrivate>
@interface MGLShapeCollectionFeature ()
@end
@implementation MGLShapeCollectionFeature
@@ -170,10 +171,15 @@
return NSDictionaryFeatureForGeometry([super geoJSONDictionary], self.attributes, self.identifier);
}
- (mbgl::Feature)mbglFeature {
[NSException raise:@"Method unavailable" format:@"%s is not available on %@.", __PRETTY_FUNCTION__, [self class]];
mbgl::Polygon<double> geometry;
return mbgl::Feature{geometry};
- (mbgl::GeoJSON)geoJSONObject {
mbgl::FeatureCollection featureCollection;
featureCollection.reserve(self.shapes.count);
for (MGLShape <MGLFeature> *feature in self.shapes) {
auto geoJSONObject = feature.geoJSONObject;
NSAssert(geoJSONObject.is<mbgl::Feature>(), @"Feature collection must only contain features.");
featureCollection.push_back(geoJSONObject.get<mbgl::Feature>());
}
return featureCollection;
}
@end
@@ -185,27 +191,27 @@
template <typename T>
class GeometryEvaluator {
public:
MGLShape <MGLFeaturePrivate> * operator()(const mbgl::Point<T> &geometry) const {
MGLShape <MGLFeature> * operator()(const mbgl::Point<T> &geometry) const {
MGLPointFeature *feature = [[MGLPointFeature alloc] init];
feature.coordinate = toLocationCoordinate2D(geometry);
return feature;
}
MGLShape <MGLFeaturePrivate> * operator()(const mbgl::LineString<T> &geometry) const {
MGLShape <MGLFeature> * operator()(const mbgl::LineString<T> &geometry) const {
std::vector<CLLocationCoordinate2D> coordinates = toLocationCoordinates2D(geometry);
return [MGLPolylineFeature polylineWithCoordinates:&coordinates[0] count:coordinates.size()];
}
MGLShape <MGLFeaturePrivate> * operator()(const mbgl::Polygon<T> &geometry) const {
MGLShape <MGLFeature> * operator()(const mbgl::Polygon<T> &geometry) const {
return toShape<MGLPolygonFeature>(geometry);
}
MGLShape <MGLFeaturePrivate> * operator()(const mbgl::MultiPoint<T> &geometry) const {
MGLShape <MGLFeature> * operator()(const mbgl::MultiPoint<T> &geometry) const {
std::vector<CLLocationCoordinate2D> coordinates = toLocationCoordinates2D(geometry);
return [[MGLPointCollectionFeature alloc] initWithCoordinates:&coordinates[0] count:coordinates.size()];
}
MGLShape <MGLFeaturePrivate> * operator()(const mbgl::MultiLineString<T> &geometry) const {
MGLShape <MGLFeature> * operator()(const mbgl::MultiLineString<T> &geometry) const {
NSMutableArray *polylines = [NSMutableArray arrayWithCapacity:geometry.size()];
for (auto &lineString : geometry) {
std::vector<CLLocationCoordinate2D> coordinates = toLocationCoordinates2D(lineString);
@@ -216,7 +222,7 @@ public:
return [MGLMultiPolylineFeature multiPolylineWithPolylines:polylines];
}
MGLShape <MGLFeaturePrivate> * operator()(const mbgl::MultiPolygon<T> &geometry) const {
MGLShape <MGLFeature> * operator()(const mbgl::MultiPolygon<T> &geometry) const {
NSMutableArray *polygons = [NSMutableArray arrayWithCapacity:geometry.size()];
for (auto &polygon : geometry) {
[polygons addObject:toShape(polygon)];
@@ -225,11 +231,11 @@ public:
return [MGLMultiPolygonFeature multiPolygonWithPolygons:polygons];
}
MGLShape <MGLFeaturePrivate> * operator()(const mapbox::geometry::geometry_collection<T> &collection) const {
MGLShape <MGLFeature> * operator()(const mapbox::geometry::geometry_collection<T> &collection) const {
NSMutableArray *shapes = [NSMutableArray arrayWithCapacity:collection.size()];
for (auto &geometry : collection) {
// This is very much like the transformation that happens in MGLFeaturesFromMBGLFeatures(), but these are raw geometries with no associated feature IDs or attributes.
MGLShape <MGLFeaturePrivate> *shape = mapbox::geometry::geometry<T>::visit(geometry, *this);
MGLShape <MGLFeature> *shape = mapbox::geometry::geometry<T>::visit(geometry, *this);
[shapes addObject:shape];
}
return [MGLShapeCollectionFeature shapeCollectionWithShapes:shapes];
@@ -266,27 +272,60 @@ private:
}
};
template <typename T>
class GeoJSONEvaluator {
public:
MGLShape <MGLFeature> * operator()(const mbgl::Geometry<T> &geometry) const {
GeometryEvaluator<T> evaluator;
MGLShape <MGLFeature> *shape = mapbox::geometry::geometry<T>::visit(geometry, evaluator);
return shape;
}
MGLShape <MGLFeature> * operator()(const mbgl::Feature &feature) const {
MGLShape <MGLFeature> *shape = (MGLShape <MGLFeature> *)MGLFeatureFromMBGLFeature(feature);
return shape;
}
MGLShape <MGLFeature> * operator()(const mbgl::FeatureCollection &collection) const {
NSMutableArray *shapes = [NSMutableArray arrayWithCapacity:collection.size()];
for (const auto &feature : collection) {
[shapes addObject:MGLFeatureFromMBGLFeature(feature)];
}
return [MGLShapeCollectionFeature shapeCollectionWithShapes:shapes];
}
};
NS_ARRAY_OF(MGLShape <MGLFeature> *) *MGLFeaturesFromMBGLFeatures(const std::vector<mbgl::Feature> &features) {
NSMutableArray *shapes = [NSMutableArray arrayWithCapacity:features.size()];
for (const auto &feature : features) {
NSMutableDictionary *attributes = [NSMutableDictionary dictionaryWithCapacity:feature.properties.size()];
for (auto &pair : feature.properties) {
auto &value = pair.second;
ValueEvaluator evaluator;
attributes[@(pair.first.c_str())] = mbgl::Value::visit(value, evaluator);
}
GeometryEvaluator<double> evaluator;
MGLShape <MGLFeaturePrivate> *shape = mapbox::geometry::geometry<double>::visit(feature.geometry, evaluator);
if (feature.id) {
shape.identifier = mbgl::FeatureIdentifier::visit(*feature.id, ValueEvaluator());
}
shape.attributes = attributes;
[shapes addObject:shape];
[shapes addObject:MGLFeatureFromMBGLFeature(feature)];
}
return shapes;
}
id <MGLFeature> MGLFeatureFromMBGLFeature(const mbgl::Feature &feature) {
NSMutableDictionary *attributes = [NSMutableDictionary dictionaryWithCapacity:feature.properties.size()];
for (auto &pair : feature.properties) {
auto &value = pair.second;
ValueEvaluator evaluator;
attributes[@(pair.first.c_str())] = mbgl::Value::visit(value, evaluator);
}
GeometryEvaluator<double> evaluator;
MGLShape <MGLFeature> *shape = mapbox::geometry::geometry<double>::visit(feature.geometry, evaluator);
if (feature.id) {
shape.identifier = mbgl::FeatureIdentifier::visit(*feature.id, ValueEvaluator());
}
shape.attributes = attributes;
return shape;
}
MGLShape* MGLShapeFromGeoJSON(const mapbox::geojson::geojson &geojson) {
GeoJSONEvaluator<double> evaluator;
MGLShape *shape = mapbox::geojson::geojson::visit(geojson, evaluator);
return shape;
}
mbgl::Feature mbglFeature(mbgl::Feature feature, id identifier, NSDictionary *attributes)
{
if (identifier) {

View File

@@ -3,6 +3,7 @@
#import <mbgl/util/geo.hpp>
#import <mbgl/util/feature.hpp>
#import <mbgl/style/conversion/geojson.hpp>
NS_ASSUME_NONNULL_BEGIN
@@ -12,6 +13,17 @@ NS_ASSUME_NONNULL_BEGIN
*/
NS_ARRAY_OF(MGLShape <MGLFeature> *) *MGLFeaturesFromMBGLFeatures(const std::vector<mbgl::Feature> &features);
/**
Returns an `MGLFeature` object converted from the given mbgl::Feature
*/
id <MGLFeature> MGLFeatureFromMBGLFeature(const mbgl::Feature &feature);
/**
Returns an `MGLShape` representing the given geojson. The shape can be
a feature, a collection of features, or a geometry.
*/
MGLShape* MGLShapeFromGeoJSON(const mapbox::geojson::geojson &geojson);
/**
Takes an `mbgl::Feature` object, an identifer, and attributes dictionary and
returns the feature object with converted `mbgl::FeatureIdentifier` and
@@ -24,10 +36,4 @@ mbgl::Feature mbglFeature(mbgl::Feature feature, id identifier, NSDictionary *at
*/
NS_DICTIONARY_OF(NSString *, id) *NSDictionaryFeatureForGeometry(NSDictionary *geometry, NSDictionary *attributes, id identifier);
@protocol MGLFeaturePrivate <MGLFeature>
- (mbgl::Feature)mbglFeature;
@end
NS_ASSUME_NONNULL_END

View File

@@ -36,8 +36,13 @@ typedef NS_ENUM(NSUInteger, MGLFillTranslateAnchor) {
Whether or not the fill should be antialiased.
The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing `YES`. Set this property to `nil` to reset it to the default value.
This attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-fill-antialias"><code>fill-antialias</code></a> paint property in the Mapbox Style Specification.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *fillAntialias;
@property (nonatomic, null_resettable, getter=isFillAntialiased) MGLStyleValue<NSNumber *> *fillAntialiased;
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *fillAntialias __attribute__((unavailable("Use fillAntialiased instead.")));
#if TARGET_OS_IPHONE
/**
@@ -69,7 +74,7 @@ typedef NS_ENUM(NSUInteger, MGLFillTranslateAnchor) {
/**
The outline color of the fill. Matches the value of `fillColor` if unspecified.
This property is only applied to the style if `fillPattern` is set to `nil`, and `fillAntialias` is set to an `MGLStyleValue` object containing an `NSNumber` object containing `YES`. Otherwise, it is ignored.
This property is only applied to the style if `fillPattern` is set to `nil`, and `fillAntialiased` is set to an `MGLStyleValue` object containing an `NSNumber` object containing `YES`. Otherwise, it is ignored.
*/
@property (nonatomic, null_resettable) MGLStyleValue<MGLColor *> *fillOutlineColor;

View File

@@ -34,15 +34,26 @@ namespace mbgl {
if (self = [super initWithIdentifier:identifier source:source]) {
auto layer = std::make_unique<mbgl::style::FillLayer>(identifier.UTF8String, source.identifier.UTF8String);
_pendingLayer = std::move(layer);
_rawLayer = _pendingLayer.get();
self.rawLayer = _pendingLayer.get();
}
return self;
}
- (mbgl::style::FillLayer *)rawLayer
{
return (mbgl::style::FillLayer *)super.rawLayer;
}
- (void)setRawLayer:(mbgl::style::FillLayer *)rawLayer
{
super.rawLayer = rawLayer;
}
- (NSString *)sourceLayerIdentifier
{
MGLAssertStyleLayerIsValid();
auto layerID = _rawLayer->getSourceLayer();
auto layerID = self.rawLayer->getSourceLayer();
return layerID.empty() ? nil : @(layerID.c_str());
}
@@ -50,25 +61,26 @@ namespace mbgl {
{
MGLAssertStyleLayerIsValid();
_rawLayer->setSourceLayer(sourceLayerIdentifier.UTF8String ?: "");
self.rawLayer->setSourceLayer(sourceLayerIdentifier.UTF8String ?: "");
}
- (void)setPredicate:(NSPredicate *)predicate
{
MGLAssertStyleLayerIsValid();
_rawLayer->setFilter(predicate.mgl_filter);
self.rawLayer->setFilter(predicate.mgl_filter);
}
- (NSPredicate *)predicate
{
MGLAssertStyleLayerIsValid();
return [NSPredicate mgl_predicateWithFilter:_rawLayer->getFilter()];
return [NSPredicate mgl_predicateWithFilter:self.rawLayer->getFilter()];
}
#pragma mark - Adding to and removing from a map view
- (void)addToMapView:(MGLMapView *)mapView
#pragma mark - Adding to and removing from a map view
- (void)addToMapView:(MGLMapView *)mapView belowLayer:(MGLStyleLayer *)otherLayer
{
if (_pendingLayer == nullptr) {
[NSException raise:@"MGLRedundantLayerException"
@@ -76,11 +88,6 @@ namespace mbgl {
"to the style more than once is invalid.", self, mapView.style];
}
[self addToMapView:mapView belowLayer:nil];
}
- (void)addToMapView:(MGLMapView *)mapView belowLayer:(MGLStyleLayer *)otherLayer
{
if (otherLayer) {
const mbgl::optional<std::string> belowLayerId{otherLayer.identifier.UTF8String};
mapView.mbglMap->addLayer(std::move(_pendingLayer), belowLayerId);
@@ -92,7 +99,7 @@ namespace mbgl {
- (void)removeFromMapView:(MGLMapView *)mapView
{
_pendingLayer = nullptr;
_rawLayer = nullptr;
self.rawLayer = nullptr;
auto removedLayer = mapView.mbglMap->removeLayer(self.identifier.UTF8String);
if (!removedLayer) {
@@ -107,36 +114,41 @@ namespace mbgl {
removedLayer.release();
_pendingLayer = std::unique_ptr<mbgl::style::FillLayer>(layer);
_rawLayer = _pendingLayer.get();
self.rawLayer = _pendingLayer.get();
}
#pragma mark - Accessing the Paint Attributes
- (void)setFillAntialias:(MGLStyleValue<NSNumber *> *)fillAntialias {
- (void)setFillAntialiased:(MGLStyleValue<NSNumber *> *)fillAntialiased {
MGLAssertStyleLayerIsValid();
auto mbglValue = MGLStyleValueTransformer<bool, NSNumber *>().toPropertyValue(fillAntialias);
_rawLayer->setFillAntialias(mbglValue);
auto mbglValue = MGLStyleValueTransformer<bool, NSNumber *>().toPropertyValue(fillAntialiased);
self.rawLayer->setFillAntialias(mbglValue);
}
- (MGLStyleValue<NSNumber *> *)fillAntialias {
- (MGLStyleValue<NSNumber *> *)isFillAntialiased {
MGLAssertStyleLayerIsValid();
auto propertyValue = _rawLayer->getFillAntialias() ?: _rawLayer->getDefaultFillAntialias();
auto propertyValue = self.rawLayer->getFillAntialias() ?: self.rawLayer->getDefaultFillAntialias();
return MGLStyleValueTransformer<bool, NSNumber *>().toStyleValue(propertyValue);
}
- (void)setFillAntialias:(MGLStyleValue<NSNumber *> *)fillAntialias {
NSAssert(NO, @"Use -setFillAntialiased: instead.");
}
- (void)setFillColor:(MGLStyleValue<MGLColor *> *)fillColor {
MGLAssertStyleLayerIsValid();
auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toPropertyValue(fillColor);
_rawLayer->setFillColor(mbglValue);
self.rawLayer->setFillColor(mbglValue);
}
- (MGLStyleValue<MGLColor *> *)fillColor {
MGLAssertStyleLayerIsValid();
auto propertyValue = _rawLayer->getFillColor() ?: _rawLayer->getDefaultFillColor();
auto propertyValue = self.rawLayer->getFillColor() ?: self.rawLayer->getDefaultFillColor();
return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toStyleValue(propertyValue);
}
@@ -144,13 +156,13 @@ namespace mbgl {
MGLAssertStyleLayerIsValid();
auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(fillOpacity);
_rawLayer->setFillOpacity(mbglValue);
self.rawLayer->setFillOpacity(mbglValue);
}
- (MGLStyleValue<NSNumber *> *)fillOpacity {
MGLAssertStyleLayerIsValid();
auto propertyValue = _rawLayer->getFillOpacity() ?: _rawLayer->getDefaultFillOpacity();
auto propertyValue = self.rawLayer->getFillOpacity() ?: self.rawLayer->getDefaultFillOpacity();
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
}
@@ -158,13 +170,13 @@ namespace mbgl {
MGLAssertStyleLayerIsValid();
auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toPropertyValue(fillOutlineColor);
_rawLayer->setFillOutlineColor(mbglValue);
self.rawLayer->setFillOutlineColor(mbglValue);
}
- (MGLStyleValue<MGLColor *> *)fillOutlineColor {
MGLAssertStyleLayerIsValid();
auto propertyValue = _rawLayer->getFillOutlineColor() ?: _rawLayer->getDefaultFillOutlineColor();
auto propertyValue = self.rawLayer->getFillOutlineColor() ?: self.rawLayer->getDefaultFillOutlineColor();
return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toStyleValue(propertyValue);
}
@@ -172,13 +184,13 @@ namespace mbgl {
MGLAssertStyleLayerIsValid();
auto mbglValue = MGLStyleValueTransformer<std::string, NSString *>().toPropertyValue(fillPattern);
_rawLayer->setFillPattern(mbglValue);
self.rawLayer->setFillPattern(mbglValue);
}
- (MGLStyleValue<NSString *> *)fillPattern {
MGLAssertStyleLayerIsValid();
auto propertyValue = _rawLayer->getFillPattern() ?: _rawLayer->getDefaultFillPattern();
auto propertyValue = self.rawLayer->getFillPattern() ?: self.rawLayer->getDefaultFillPattern();
return MGLStyleValueTransformer<std::string, NSString *>().toStyleValue(propertyValue);
}
@@ -186,13 +198,13 @@ namespace mbgl {
MGLAssertStyleLayerIsValid();
auto mbglValue = MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toPropertyValue(fillTranslate);
_rawLayer->setFillTranslate(mbglValue);
self.rawLayer->setFillTranslate(mbglValue);
}
- (MGLStyleValue<NSValue *> *)fillTranslate {
MGLAssertStyleLayerIsValid();
auto propertyValue = _rawLayer->getFillTranslate() ?: _rawLayer->getDefaultFillTranslate();
auto propertyValue = self.rawLayer->getFillTranslate() ?: self.rawLayer->getDefaultFillTranslate();
return MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toStyleValue(propertyValue);
}
@@ -200,13 +212,13 @@ namespace mbgl {
MGLAssertStyleLayerIsValid();
auto mbglValue = MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLFillTranslateAnchor>().toEnumPropertyValue(fillTranslateAnchor);
_rawLayer->setFillTranslateAnchor(mbglValue);
self.rawLayer->setFillTranslateAnchor(mbglValue);
}
- (MGLStyleValue<NSValue *> *)fillTranslateAnchor {
MGLAssertStyleLayerIsValid();
auto propertyValue = _rawLayer->getFillTranslateAnchor() ?: _rawLayer->getDefaultFillTranslateAnchor();
auto propertyValue = self.rawLayer->getFillTranslateAnchor() ?: self.rawLayer->getDefaultFillTranslateAnchor();
return MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLFillTranslateAnchor>().toEnumStyleValue(propertyValue);
}

View File

@@ -1,144 +0,0 @@
#import "MGLSource.h"
#import "MGLTypes.h"
NS_ASSUME_NONNULL_BEGIN
@protocol MGLFeature;
/**
Options for `MGLGeoJSONSource` objects.
*/
typedef NSString *MGLGeoJSONSourceOption NS_STRING_ENUM;
/**
An `NSNumber` object containing a Boolean enabling or disabling clustering.
If the `features` property contains point features, setting this option to
`YES` clusters the points by radius into groups. The default value is `NO`.
*/
extern const MGLGeoJSONSourceOption MGLGeoJSONSourceOptionClustered;
/**
An `NSNumber` object containing an integer; specifies the radius of each
cluster if clustering is enabled. A value of 512 produces a radius equal to
the width of a tile. The default value is 50.
*/
extern const MGLGeoJSONSourceOption MGLGeoJSONSourceOptionClusterRadius;
/**
An `NSNumber` object containing an integer; specifies the maximum zoom level at
which to cluster points if clustering is enabled. Defaults to one zoom level
less than the value of `MGLGeoJSONSourceOptionMaximumZoomLevel` so that, at the
maximum zoom level, the features are not clustered.
*/
extern const MGLGeoJSONSourceOption MGLGeoJSONSourceOptionMaximumZoomLevelForClustering;
/**
An `NSNumber` object containing an integer; specifies the maximum zoom level at
which to create vector tiles. A greater value produces greater detail at high
zoom levels. The default value is 18.
*/
extern const MGLGeoJSONSourceOption MGLGeoJSONSourceOptionMaximumZoomLevel;
/**
An `NSNumber` object containing an integer; specifies the size of the tile
buffer on each side. A value of 0 produces no buffer. A value of 512 produces a
buffer as wide as the tile itself. Larger values produce fewer rendering
artifacts near tile edges and slower performance. The default value is 128.
*/
extern const MGLGeoJSONSourceOption MGLGeoJSONSourceOptionBuffer;
/**
An `NSNumber` object containing a double; specifies the Douglas-Peucker
simplification tolerance. A greater value produces simpler geometries and
improves performance. The default value is 0.375.
*/
extern const MGLGeoJSONSourceOption MGLGeoJSONSourceOptionSimplificationTolerance;
/**
A GeoJSON source.
@see <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-geojson">The
style specification.</a>
*/
@interface MGLGeoJSONSource : MGLSource
#pragma mark Initializing a Source
/**
Returns a GeoJSON source initialized with an identifier, GeoJSON data, and a
dictionary of options for the source according to the
<a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-geojson">style
specification</a>.
@param identifier A string that uniquely identifies the source.
@param geoJSONData An `NSData` object representing GeoJSON source code.
@param options An `NSDictionary` of options for this source.
@return An initialized GeoJSON source.
*/
- (instancetype)initWithIdentifier:(NSString *)identifier geoJSONData:(NSData *)data options:(nullable NS_DICTIONARY_OF(MGLGeoJSONSourceOption, id) *)options NS_DESIGNATED_INITIALIZER;
/**
Returns a GeoJSON source with an identifier, URL, and dictionary of options for
the source according to the
<a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-geojson">style
specification</a>.
@param identifier A string that uniquely identifies the source.
@param URL An HTTP(S) URL, absolute file URL, or local file URL relative to the
current application’s resource bundle.
@param options An `NSDictionary` of options for this source.
@return An initialized GeoJSON source.
*/
- (instancetype)initWithIdentifier:(NSString *)identifier URL:(NSURL *)url options:(nullable NS_DICTIONARY_OF(MGLGeoJSONSourceOption, id) *)options NS_DESIGNATED_INITIALIZER;
/**
Returns a GeoJSON source with an identifier, features dictionary, and dictionary
of options for the source according to the
<a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-geojson">style
specification</a>.
@param identifier A string that uniquely identifies the source.
@param features An array of features that conform to the `MGLFeature` protocol.
@param options An `NSDictionary` of options for this source.
@return An initialized GeoJSON source.
*/
- (instancetype)initWithIdentifier:(NSString *)identifier features:(NSArray<id<MGLFeature>> *)features options:(nullable NS_DICTIONARY_OF(MGLGeoJSONSourceOption, id) *)options NS_DESIGNATED_INITIALIZER;
#pragma mark Accessing a Source’s Content
/**
The contents of the source.
If the receiver was initialized using `-initWithIdentifier:URL:options:`, this property
is set to `nil`. This property is unavailable until the receiver is passed into
`-[MGLStyle addSource]`.
*/
@property (nonatomic, nullable) NS_ARRAY_OF(id <MGLFeature>) *features;
/**
A GeoJSON representation of the contents of the source.
Use the `features` property instead to get an object representation of the
contents. Alternatively, use `NSJSONSerialization` with the value of this
property to transform it into Foundation types.
If the receiver was initialized using `-initWithIdentifier:URL:options` or
`-initWithIdentifier:features:options`, this property is set to `nil`.
This property is unavailable until the receiver is passed
into `-[MGLStyle addSource]`.
*/
@property (nonatomic, nullable, copy) NSData *geoJSONData;
/**
The URL to the GeoJSON document that specifies the contents of the source.
If the receiver was initialized using `-initWithIdentifier:geoJSONData:options`, this
property is set to `nil`.
*/
@property (nonatomic, nullable) NSURL *URL;
@end
NS_ASSUME_NONNULL_END

View File

@@ -1,207 +0,0 @@
#import "MGLGeoJSONSource_Private.h"
#import "MGLMapView_Private.h"
#import "MGLSource_Private.h"
#import "MGLFeature_Private.h"
#import "NSURL+MGLAdditions.h"
#include <mbgl/style/sources/geojson_source.hpp>
const MGLGeoJSONSourceOption MGLGeoJSONSourceOptionClustered = @"MGLGeoJSONSourceOptionClustered";
const MGLGeoJSONSourceOption MGLGeoJSONSourceOptionClusterRadius = @"MGLGeoJSONSourceOptionClusterRadius";
const MGLGeoJSONSourceOption MGLGeoJSONSourceOptionMaximumZoomLevelForClustering = @"MGLGeoJSONSourceOptionMaximumZoomLevelForClustering";
const MGLGeoJSONSourceOption MGLGeoJSONSourceOptionMaximumZoomLevel = @"MGLGeoJSONSourceOptionMaximumZoomLevel";
const MGLGeoJSONSourceOption MGLGeoJSONSourceOptionBuffer = @"MGLGeoJSONSourceOptionBuffer";
const MGLGeoJSONSourceOption MGLGeoJSONSourceOptionSimplificationTolerance = @"MGLGeoJSONSourceOptionSimplificationTolerance";
@interface MGLGeoJSONSource ()
@property (nonatomic, readwrite) NSDictionary *options;
@property (nonatomic) mbgl::style::GeoJSONSource *rawSource;
@end
@implementation MGLGeoJSONSource
{
std::unique_ptr<mbgl::style::GeoJSONSource> _pendingSource;
}
- (instancetype)initWithIdentifier:(NSString *)identifier geoJSONData:(NSData *)data options:(NS_DICTIONARY_OF(NSString *, id) *)options
{
if (self = [super initWithIdentifier:identifier])
{
_geoJSONData = data;
_options = options;
[self commonInit];
}
return self;
}
- (instancetype)initWithIdentifier:(NSString *)identifier URL:(NSURL *)url options:(NS_DICTIONARY_OF(NSString *, id) *)options
{
if (self = [super initWithIdentifier:identifier])
{
_URL = url;
_options = options;
[self commonInit];
}
return self;
}
- (instancetype)initWithIdentifier:(NSString *)identifier features:(NSArray<id<MGLFeature>> *)features options:(NS_DICTIONARY_OF(NSString *,id) *)options {
if (self = [super initWithIdentifier:identifier]) {
_features = features;
_options = options;
[self commonInit];
}
return self;
}
- (void)addToMapView:(MGLMapView *)mapView
{
if (_pendingSource == nullptr) {
[NSException raise:@"MGLRedundantSourceException"
format:@"This instance %@ was already added to %@. Adding the same source instance " \
"to the style more than once is invalid.", self, mapView.style];
}
mapView.mbglMap->addSource(std::move(_pendingSource));
}
- (void)removeFromMapView:(MGLMapView *)mapView
{
auto removedSource = mapView.mbglMap->removeSource(self.identifier.UTF8String);
_pendingSource = std::move(reinterpret_cast<std::unique_ptr<mbgl::style::GeoJSONSource> &>(removedSource));
self.rawSource = _pendingSource.get();
}
- (void)commonInit
{
auto source = std::make_unique<mbgl::style::GeoJSONSource>(self.identifier.UTF8String, self.geoJSONOptions);
if (self.URL) {
NSURL *url = self.URL.mgl_URLByStandardizingScheme;
source->setURL(url.absoluteString.UTF8String);
_features = nil;
} else if (self.geoJSONData) {
NSString *string = [[NSString alloc] initWithData:self.geoJSONData encoding:NSUTF8StringEncoding];
const auto geojson = mapbox::geojson::parse(string.UTF8String).get<mapbox::geojson::feature_collection>();
source->setGeoJSON(geojson);
_features = MGLFeaturesFromMBGLFeatures(geojson);
} else {
mbgl::FeatureCollection featureCollection;
featureCollection.reserve(self.features.count);
for (id <MGLFeaturePrivate> feature in self.features) {
featureCollection.push_back([feature mbglFeature]);
}
const auto geojson = mbgl::GeoJSON{featureCollection};
source->setGeoJSON(geojson);
_features = MGLFeaturesFromMBGLFeatures(featureCollection);
}
_pendingSource = std::move(source);
self.rawSource = _pendingSource.get();
}
- (mbgl::style::GeoJSONOptions)geoJSONOptions
{
auto mbglOptions = mbgl::style::GeoJSONOptions();
if (id value = self.options[MGLGeoJSONSourceOptionMaximumZoomLevel]) {
[self validateValue:value];
mbglOptions.maxzoom = [value integerValue];
}
if (id value = self.options[MGLGeoJSONSourceOptionBuffer]) {
[self validateValue:value];
mbglOptions.buffer = [value integerValue];
}
if (id value = self.options[MGLGeoJSONSourceOptionSimplificationTolerance]) {
[self validateValue:value];
mbglOptions.tolerance = [value doubleValue];
}
if (id value = self.options[MGLGeoJSONSourceOptionClusterRadius]) {
[self validateValue:value];
mbglOptions.clusterRadius = [value integerValue];
}
if (id value = self.options[MGLGeoJSONSourceOptionMaximumZoomLevelForClustering]) {
[self validateValue:value];
mbglOptions.clusterMaxZoom = [value integerValue];
}
if (id value = self.options[MGLGeoJSONSourceOptionClustered]) {
[self validateValue:value];
mbglOptions.cluster = [value boolValue];
}
return mbglOptions;
}
- (void)validateValue:(id)value
{
if (! [value isKindOfClass:[NSNumber class]])
{
[NSException raise:@"Value not handled" format:@"%@ is not an NSNumber", value];
}
}
- (void)setGeoJSONData:(NSData *)geoJSONData
{
_geoJSONData = geoJSONData;
if (self.rawSource == NULL)
{
[self commonInit];
}
NSString *string = [[NSString alloc] initWithData:_geoJSONData encoding:NSUTF8StringEncoding];
const auto geojson = mapbox::geojson::parse(string.UTF8String).get<mapbox::geojson::feature_collection>();
self.rawSource->setGeoJSON(geojson);
_features = MGLFeaturesFromMBGLFeatures(geojson);
}
- (void)setURL:(NSURL *)URL
{
_URL = URL;
if (self.rawSource == NULL)
{
[self commonInit];
}
NSURL *url = self.URL.mgl_URLByStandardizingScheme;
self.rawSource->setURL(url.absoluteString.UTF8String);
}
- (void)setFeatures:(NSArray *)features
{
if (self.rawSource == NULL)
{
[self commonInit];
}
mbgl::FeatureCollection featureCollection;
featureCollection.reserve(features.count);
for (id <MGLFeaturePrivate> feature in features) {
featureCollection.push_back([feature mbglFeature]);
}
const auto geojson = mbgl::GeoJSON{featureCollection};
self.rawSource->setGeoJSON(geojson);
_features = MGLFeaturesFromMBGLFeatures(featureCollection);
}
- (NSString *)description
{
return [NSString stringWithFormat:@"<%@: %p; identifier = %@; URL = %@; geoJSONData = %@; features = %@>",
NSStringFromClass([self class]), (void *)self, self.identifier, self.URL, self.geoJSONData, self.features];
}
@end

View File

@@ -1,10 +0,0 @@
#import "MGLGeoJSONSource.h"
#import "MGLGeoJSONSource_Private.h"
#include <mbgl/style/sources/geojson_source.hpp>
@interface MGLGeoJSONSource (Private)
- (mbgl::style::GeoJSONOptions)geoJSONOptions;
@end

View File

@@ -62,6 +62,14 @@ NS_INLINE BOOL MGLCoordinateBoundsEqualToCoordinateBounds(MGLCoordinateBounds bo
bounds1.ne.longitude == bounds2.ne.longitude);
}
/** Returns `YES` if the two coordinate bounds intersect. */
NS_INLINE BOOL MGLCoordinateBoundsIntersectsCoordinateBounds(MGLCoordinateBounds bounds1, MGLCoordinateBounds bounds2) {
return (bounds1.ne.latitude > bounds2.sw.latitude &&
bounds1.sw.latitude < bounds2.ne.latitude &&
bounds1.ne.longitude > bounds2.sw.longitude &&
bounds1.sw.longitude < bounds2.ne.longitude);
}
/** Returns `YES` if the coordinate is within the coordinate bounds. */
NS_INLINE BOOL MGLCoordinateInCoordinateBounds(CLLocationCoordinate2D coordinate, MGLCoordinateBounds bounds) {
return (coordinate.latitude >= bounds.sw.latitude &&

View File

@@ -141,8 +141,13 @@ typedef NS_ENUM(NSUInteger, MGLLineTranslateAnchor) {
This property is measured in line widths.
This property is only applied to the style if `linePattern` is set to `nil`. Otherwise, it is ignored.
This attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-line-dasharray"><code>line-dasharray</code></a> paint property in the Mapbox Style Specification.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSArray<NSNumber *> *> *lineDasharray;
@property (nonatomic, null_resettable) MGLStyleValue<NSArray<NSNumber *> *> *lineDashPattern;
@property (nonatomic, null_resettable) MGLStyleValue<NSArray<NSNumber *> *> *lineDasharray __attribute__((unavailable("Use lineDashPattern instead.")));
/**
Draws a line casing outside of a line's actual path. Value indicates the width of the inner gap.

View File

@@ -46,15 +46,26 @@ namespace mbgl {
if (self = [super initWithIdentifier:identifier source:source]) {
auto layer = std::make_unique<mbgl::style::LineLayer>(identifier.UTF8String, source.identifier.UTF8String);
_pendingLayer = std::move(layer);
_rawLayer = _pendingLayer.get();
self.rawLayer = _pendingLayer.get();
}
return self;
}
- (mbgl::style::LineLayer *)rawLayer
{
return (mbgl::style::LineLayer *)super.rawLayer;
}
- (void)setRawLayer:(mbgl::style::LineLayer *)rawLayer
{
super.rawLayer = rawLayer;
}
- (NSString *)sourceLayerIdentifier
{
MGLAssertStyleLayerIsValid();
auto layerID = _rawLayer->getSourceLayer();
auto layerID = self.rawLayer->getSourceLayer();
return layerID.empty() ? nil : @(layerID.c_str());
}
@@ -62,25 +73,26 @@ namespace mbgl {
{
MGLAssertStyleLayerIsValid();
_rawLayer->setSourceLayer(sourceLayerIdentifier.UTF8String ?: "");
self.rawLayer->setSourceLayer(sourceLayerIdentifier.UTF8String ?: "");
}
- (void)setPredicate:(NSPredicate *)predicate
{
MGLAssertStyleLayerIsValid();
_rawLayer->setFilter(predicate.mgl_filter);
self.rawLayer->setFilter(predicate.mgl_filter);
}
- (NSPredicate *)predicate
{
MGLAssertStyleLayerIsValid();
return [NSPredicate mgl_predicateWithFilter:_rawLayer->getFilter()];
return [NSPredicate mgl_predicateWithFilter:self.rawLayer->getFilter()];
}
#pragma mark - Adding to and removing from a map view
- (void)addToMapView:(MGLMapView *)mapView
#pragma mark - Adding to and removing from a map view
- (void)addToMapView:(MGLMapView *)mapView belowLayer:(MGLStyleLayer *)otherLayer
{
if (_pendingLayer == nullptr) {
[NSException raise:@"MGLRedundantLayerException"
@@ -88,11 +100,6 @@ namespace mbgl {
"to the style more than once is invalid.", self, mapView.style];
}
[self addToMapView:mapView belowLayer:nil];
}
- (void)addToMapView:(MGLMapView *)mapView belowLayer:(MGLStyleLayer *)otherLayer
{
if (otherLayer) {
const mbgl::optional<std::string> belowLayerId{otherLayer.identifier.UTF8String};
mapView.mbglMap->addLayer(std::move(_pendingLayer), belowLayerId);
@@ -104,7 +111,7 @@ namespace mbgl {
- (void)removeFromMapView:(MGLMapView *)mapView
{
_pendingLayer = nullptr;
_rawLayer = nullptr;
self.rawLayer = nullptr;
auto removedLayer = mapView.mbglMap->removeLayer(self.identifier.UTF8String);
if (!removedLayer) {
@@ -119,7 +126,7 @@ namespace mbgl {
removedLayer.release();
_pendingLayer = std::unique_ptr<mbgl::style::LineLayer>(layer);
_rawLayer = _pendingLayer.get();
self.rawLayer = _pendingLayer.get();
}
#pragma mark - Accessing the Layout Attributes
@@ -128,13 +135,13 @@ namespace mbgl {
MGLAssertStyleLayerIsValid();
auto mbglValue = MGLStyleValueTransformer<mbgl::style::LineCapType, NSValue *, mbgl::style::LineCapType, MGLLineCap>().toEnumPropertyValue(lineCap);
_rawLayer->setLineCap(mbglValue);
self.rawLayer->setLineCap(mbglValue);
}
- (MGLStyleValue<NSValue *> *)lineCap {
MGLAssertStyleLayerIsValid();
auto propertyValue = _rawLayer->getLineCap() ?: _rawLayer->getDefaultLineCap();
auto propertyValue = self.rawLayer->getLineCap() ?: self.rawLayer->getDefaultLineCap();
return MGLStyleValueTransformer<mbgl::style::LineCapType, NSValue *, mbgl::style::LineCapType, MGLLineCap>().toEnumStyleValue(propertyValue);
}
@@ -142,13 +149,13 @@ namespace mbgl {
MGLAssertStyleLayerIsValid();
auto mbglValue = MGLStyleValueTransformer<mbgl::style::LineJoinType, NSValue *, mbgl::style::LineJoinType, MGLLineJoin>().toEnumPropertyValue(lineJoin);
_rawLayer->setLineJoin(mbglValue);
self.rawLayer->setLineJoin(mbglValue);
}
- (MGLStyleValue<NSValue *> *)lineJoin {
MGLAssertStyleLayerIsValid();
auto propertyValue = _rawLayer->getLineJoin() ?: _rawLayer->getDefaultLineJoin();
auto propertyValue = self.rawLayer->getLineJoin() ?: self.rawLayer->getDefaultLineJoin();
return MGLStyleValueTransformer<mbgl::style::LineJoinType, NSValue *, mbgl::style::LineJoinType, MGLLineJoin>().toEnumStyleValue(propertyValue);
}
@@ -156,13 +163,13 @@ namespace mbgl {
MGLAssertStyleLayerIsValid();
auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(lineMiterLimit);
_rawLayer->setLineMiterLimit(mbglValue);
self.rawLayer->setLineMiterLimit(mbglValue);
}
- (MGLStyleValue<NSNumber *> *)lineMiterLimit {
MGLAssertStyleLayerIsValid();
auto propertyValue = _rawLayer->getLineMiterLimit() ?: _rawLayer->getDefaultLineMiterLimit();
auto propertyValue = self.rawLayer->getLineMiterLimit() ?: self.rawLayer->getDefaultLineMiterLimit();
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
}
@@ -170,13 +177,13 @@ namespace mbgl {
MGLAssertStyleLayerIsValid();
auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(lineRoundLimit);
_rawLayer->setLineRoundLimit(mbglValue);
self.rawLayer->setLineRoundLimit(mbglValue);
}
- (MGLStyleValue<NSNumber *> *)lineRoundLimit {
MGLAssertStyleLayerIsValid();
auto propertyValue = _rawLayer->getLineRoundLimit() ?: _rawLayer->getDefaultLineRoundLimit();
auto propertyValue = self.rawLayer->getLineRoundLimit() ?: self.rawLayer->getDefaultLineRoundLimit();
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
}
@@ -186,13 +193,13 @@ namespace mbgl {
MGLAssertStyleLayerIsValid();
auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(lineBlur);
_rawLayer->setLineBlur(mbglValue);
self.rawLayer->setLineBlur(mbglValue);
}
- (MGLStyleValue<NSNumber *> *)lineBlur {
MGLAssertStyleLayerIsValid();
auto propertyValue = _rawLayer->getLineBlur() ?: _rawLayer->getDefaultLineBlur();
auto propertyValue = self.rawLayer->getLineBlur() ?: self.rawLayer->getDefaultLineBlur();
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
}
@@ -200,41 +207,46 @@ namespace mbgl {
MGLAssertStyleLayerIsValid();
auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toPropertyValue(lineColor);
_rawLayer->setLineColor(mbglValue);
self.rawLayer->setLineColor(mbglValue);
}
- (MGLStyleValue<MGLColor *> *)lineColor {
MGLAssertStyleLayerIsValid();
auto propertyValue = _rawLayer->getLineColor() ?: _rawLayer->getDefaultLineColor();
auto propertyValue = self.rawLayer->getLineColor() ?: self.rawLayer->getDefaultLineColor();
return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toStyleValue(propertyValue);
}
- (void)setLineDasharray:(MGLStyleValue<NSArray<NSNumber *> *> *)lineDasharray {
- (void)setLineDashPattern:(MGLStyleValue<NSArray<NSNumber *> *> *)lineDashPattern {
MGLAssertStyleLayerIsValid();
auto mbglValue = MGLStyleValueTransformer<std::vector<float>, NSArray<NSNumber *> *, float>().toPropertyValue(lineDasharray);
_rawLayer->setLineDasharray(mbglValue);
auto mbglValue = MGLStyleValueTransformer<std::vector<float>, NSArray<NSNumber *> *, float>().toPropertyValue(lineDashPattern);
self.rawLayer->setLineDasharray(mbglValue);
}
- (MGLStyleValue<NSArray<NSNumber *> *> *)lineDasharray {
- (MGLStyleValue<NSArray<NSNumber *> *> *)lineDashPattern {
MGLAssertStyleLayerIsValid();
auto propertyValue = _rawLayer->getLineDasharray() ?: _rawLayer->getDefaultLineDasharray();
auto propertyValue = self.rawLayer->getLineDasharray() ?: self.rawLayer->getDefaultLineDasharray();
return MGLStyleValueTransformer<std::vector<float>, NSArray<NSNumber *> *, float>().toStyleValue(propertyValue);
}
- (void)setLineDasharray:(MGLStyleValue<NSArray<NSNumber *> *> *)lineDasharray {
NSAssert(NO, @"Use -setLineDashPattern: instead.");
}
- (void)setLineGapWidth:(MGLStyleValue<NSNumber *> *)lineGapWidth {
MGLAssertStyleLayerIsValid();
auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(lineGapWidth);
_rawLayer->setLineGapWidth(mbglValue);
self.rawLayer->setLineGapWidth(mbglValue);
}
- (MGLStyleValue<NSNumber *> *)lineGapWidth {
MGLAssertStyleLayerIsValid();
auto propertyValue = _rawLayer->getLineGapWidth() ?: _rawLayer->getDefaultLineGapWidth();
auto propertyValue = self.rawLayer->getLineGapWidth() ?: self.rawLayer->getDefaultLineGapWidth();
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
}
@@ -242,13 +254,13 @@ namespace mbgl {
MGLAssertStyleLayerIsValid();
auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(lineOffset);
_rawLayer->setLineOffset(mbglValue);
self.rawLayer->setLineOffset(mbglValue);
}
- (MGLStyleValue<NSNumber *> *)lineOffset {
MGLAssertStyleLayerIsValid();
auto propertyValue = _rawLayer->getLineOffset() ?: _rawLayer->getDefaultLineOffset();
auto propertyValue = self.rawLayer->getLineOffset() ?: self.rawLayer->getDefaultLineOffset();
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
}
@@ -256,13 +268,13 @@ namespace mbgl {
MGLAssertStyleLayerIsValid();
auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(lineOpacity);
_rawLayer->setLineOpacity(mbglValue);
self.rawLayer->setLineOpacity(mbglValue);
}
- (MGLStyleValue<NSNumber *> *)lineOpacity {
MGLAssertStyleLayerIsValid();
auto propertyValue = _rawLayer->getLineOpacity() ?: _rawLayer->getDefaultLineOpacity();
auto propertyValue = self.rawLayer->getLineOpacity() ?: self.rawLayer->getDefaultLineOpacity();
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
}
@@ -270,13 +282,13 @@ namespace mbgl {
MGLAssertStyleLayerIsValid();
auto mbglValue = MGLStyleValueTransformer<std::string, NSString *>().toPropertyValue(linePattern);
_rawLayer->setLinePattern(mbglValue);
self.rawLayer->setLinePattern(mbglValue);
}
- (MGLStyleValue<NSString *> *)linePattern {
MGLAssertStyleLayerIsValid();
auto propertyValue = _rawLayer->getLinePattern() ?: _rawLayer->getDefaultLinePattern();
auto propertyValue = self.rawLayer->getLinePattern() ?: self.rawLayer->getDefaultLinePattern();
return MGLStyleValueTransformer<std::string, NSString *>().toStyleValue(propertyValue);
}
@@ -284,13 +296,13 @@ namespace mbgl {
MGLAssertStyleLayerIsValid();
auto mbglValue = MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toPropertyValue(lineTranslate);
_rawLayer->setLineTranslate(mbglValue);
self.rawLayer->setLineTranslate(mbglValue);
}
- (MGLStyleValue<NSValue *> *)lineTranslate {
MGLAssertStyleLayerIsValid();
auto propertyValue = _rawLayer->getLineTranslate() ?: _rawLayer->getDefaultLineTranslate();
auto propertyValue = self.rawLayer->getLineTranslate() ?: self.rawLayer->getDefaultLineTranslate();
return MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toStyleValue(propertyValue);
}
@@ -298,13 +310,13 @@ namespace mbgl {
MGLAssertStyleLayerIsValid();
auto mbglValue = MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLLineTranslateAnchor>().toEnumPropertyValue(lineTranslateAnchor);
_rawLayer->setLineTranslateAnchor(mbglValue);
self.rawLayer->setLineTranslateAnchor(mbglValue);
}
- (MGLStyleValue<NSValue *> *)lineTranslateAnchor {
MGLAssertStyleLayerIsValid();
auto propertyValue = _rawLayer->getLineTranslateAnchor() ?: _rawLayer->getDefaultLineTranslateAnchor();
auto propertyValue = self.rawLayer->getLineTranslateAnchor() ?: self.rawLayer->getDefaultLineTranslateAnchor();
return MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLLineTranslateAnchor>().toEnumStyleValue(propertyValue);
}
@@ -312,13 +324,13 @@ namespace mbgl {
MGLAssertStyleLayerIsValid();
auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(lineWidth);
_rawLayer->setLineWidth(mbglValue);
self.rawLayer->setLineWidth(mbglValue);
}
- (MGLStyleValue<NSNumber *> *)lineWidth {
MGLAssertStyleLayerIsValid();
auto propertyValue = _rawLayer->getLineWidth() ?: _rawLayer->getDefaultLineWidth();
auto propertyValue = self.rawLayer->getLineWidth() ?: self.rawLayer->getDefaultLineWidth();
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
}

View File

@@ -7,67 +7,133 @@ NS_ASSUME_NONNULL_BEGIN
/**
The `MGLMultiPoint` class is an abstract superclass used to define shapes
composed of multiple points. You should not create instances of this class
composed of multiple vertices. You should not create instances of this class
directly. Instead, you should create instances of the `MGLPolyline` or
`MGLPolygon` classes. However, you can use the method and properties of this
class to access information about the specific points associated with the line
or polygon.
class to access information about the vertices of the line or polygon.
*/
@interface MGLMultiPoint : MGLShape
/**
The array of coordinates associated with the shape.
The array of vertices associated with the shape.
This C array is a pointer to a structure inside the multipoint object,
which may have a lifetime shorter than the multipoint object and will
certainly not have a longer lifetime. Therefore, you should copy the C
array if it needs to be stored outside of the memory context in which you
use this property.
This C array is a pointer to a structure inside the multipoint object, which
may have a lifetime shorter than the multipoint object and will certainly not
have a longer lifetime. Therefore, you should copy the C array if it needs to
be stored outside of the memory context in which you use this property.
*/
@property (nonatomic, readonly) CLLocationCoordinate2D *coordinates NS_RETURNS_INNER_POINTER;
/** The number of coordinates associated with the shape. (read-only) */
/** The number of vertices in the shape. */
@property (nonatomic, readonly) NSUInteger pointCount;
/**
Retrieves one or more coordinates associated with the shape.
Retrieves the vertices of part of the shape.
@param coords On input, you must provide a C array of structures large enough
to hold the desired number of coordinates. On output, this structure
contains the requested coordinate data.
@param range The range of points you want. The `location` field indicates the
first point you are requesting, with `0` being the first point, `1` being
the second point, and so on. The `length` field indicates the number of
points you want. The array in _`coords`_ must be large enough to accommodate
the number of requested coordinates.
@param coords On input, you must provide a C array of `CLLocationCoordinate2D`
structures large enough to hold the desired number of coordinates. On
output, this structure contains the requested coordinate data.
@param range The range of vertices you want. The `location` field indicates
the first vertex you are requesting, with `0` being the first vertex, `1`
being the second vertex, and so on. The `length` field indicates the number
of vertices you want. The array in `coords` must be large enough to
accommodate the number of requested coordinates.
*/
- (void)getCoordinates:(CLLocationCoordinate2D *)coords range:(NSRange)range;
/**
Updates one or more coordinates for the shape, which will instantaneously
cause the shape to be redrawn if it is currently visible on the map.
Sets the shape’s vertices to the given C array of vertices.
@param range The range of points to update. The `location` field indicates the
first point you are replacing, with `0` being the first point, `1` being
the second point, and so on. The `length` field indicates the number of
points to update. The array in _`coords`_ must be equal in number to the
length of the range. If you want to append to the existing coordinates
array use `-[MGLMultiPoint appendCoordinates:count:]`.
@param coords The array of coordinates defining the shape. The data in this
array is copied to the object.
array is copied to the shape’s `coordinates` property.
@param count The number of coordinates from the `coords` array.
*/
- (void)replaceCoordinatesInRange:(NSRange)range withCoordinates:(const CLLocationCoordinate2D *)coords;
- (void)setCoordinates:(CLLocationCoordinate2D *)coords count:(NSUInteger)count;
/**
Appends one or more coordinates for the shape, which will instantaneously
cause the shape to be redrawn if it is currently visible on the map.
Inserts the given vertices into the shape. If the shape is currently visible on
the map, it is redrawn immediately.
@param coords The array of coordinates to insert into the shape. The data in
this array is copied to the shape’s `coordinate` property.
@param count The number of items in the `coords` array.
@param index The zero-based index at which the first coordinate in `coords`
will appear in the `coordinates` property.
*/
- (void)insertCoordinates:(const CLLocationCoordinate2D *)coords count:(NSUInteger)count atIndex:(NSUInteger)index;
/**
Appends the given vertices to the shape. If the shape is currently visible on
the map, it is redrawn immediately.
@param coords The array of coordinates to add to the shape. The data in this
array is copied to the new object.
array is copied to the shape’s `coordinate` property.
@param count The number of items in the `coords` array.
*/
- (void)appendCoordinates:(const CLLocationCoordinate2D *)coords count:(NSUInteger)count;
/**
Replaces the vertices at the given range in the shape with the same number of
vertices from a given C array. If the shape is currently visible on the map, it
is redrawn immediately.
The number of coordinates in `coords` must be equal to the length of `range`.
If you want to insert or delete one or more vertices, use the
`-replaceCoordinatesInRange:withCoordinates:count:` method.
If `range` extends beyond the shape’s `coordinates` property, an
`NSRangeException` is raised. If you want to append new vertices to the shape,
use the `-appendCoordinates:count:` method.
@param range The range of vertices to replace. The `location` field indicates
the first vertex you are replacing, with `0` being the first vertex, `1`
being the second vertex, and so on. The `length` field indicates the number
of vertices to replace.
@param coords The array of coordinates defining part of the shape. The data in
this array is copied to the shape’s `coordinate` property.
*/
- (void)replaceCoordinatesInRange:(NSRange)range withCoordinates:(const CLLocationCoordinate2D *)coords;
/**
Replaces the vertices at the given range in the shape with the specified number
of vertices from a given C array. If the shape is currently visible on the map,
it is redrawn immediately.
If `count` is greater than the `length` field of `range`, some vertices will
effectively be inserted into the shape. On the other hand, if `count` is less
than the `length` field of `range`, some vertices will effectively be removed.
If `range` extends beyond the shape’s `coordinates` property, an
`NSRangeException` is raised. If you want to append new vertices to the shape,
use the `-appendCoordinates:count:` method.
@param range The range of vertices to replace. The `location` field indicates
the first vertex you are replacing, with `0` being the first vertex, `1`
being the second vertex, and so on. The `length` field indicates the number
of vertices to replace.
@param coords The array of coordinates defining part of the shape. The data in
this array is copied to the shape’s `coordinates` property.
@param count The number of coordinates from the `coords` array to insert in
place of the coordinates in `range`. The sum of `range`’s length and this
count must not exceed the number of items currently in the `coordinates`
property.
*/
- (void)replaceCoordinatesInRange:(NSRange)range withCoordinates:(const CLLocationCoordinate2D *)coords count:(NSUInteger)count;
/**
Removes the vertices at the given range from the shape. If the shape is
currently visible on the map, it is redrawn immediately.
If `range` extends beyond the shape’s `coordinates` property, an
`NSRangeException` is raised.
@param range The range of vertices to remove. The `location` field indicates
the first vertex you are removing, with `0` being the first vertex, `1`
being the second vertex, and so on. The `length` field indicates the number
of vertices to remove.
*/
- (void)removeCoordinatesInRange:(NSRange)range;
@end
NS_ASSUME_NONNULL_END

View File

@@ -2,19 +2,12 @@
#import "MGLGeometry_Private.h"
#import "MGLTypes.h"
#import <mbgl/util/geo.hpp>
mbgl::Color MGLColorObjectFromCGColorRef(CGColorRef cgColor)
{
if (!cgColor) return { 0, 0, 0, 0 };
NSCAssert(CGColorGetNumberOfComponents(cgColor) >= 4, @"Color must have at least 4 components");
const CGFloat *components = CGColorGetComponents(cgColor);
return { (float)components[0], (float)components[1], (float)components[2], (float)components[3] };
}
#include <mbgl/util/geo.hpp>
#include <mbgl/util/optional.hpp>
@implementation MGLMultiPoint
{
MGLCoordinateBounds _bounds;
mbgl::optional<mbgl::LatLngBounds> _bounds;
std::vector<CLLocationCoordinate2D> _coordinates;
}
@@ -24,9 +17,11 @@ mbgl::Color MGLColorObjectFromCGColorRef(CGColorRef cgColor)
if (self)
{
NSAssert(count > 0, @"A multipoint must have coordinates");
if (!count) {
[NSException raise:NSInvalidArgumentException
format:@"A multipoint must have at least one vertex."];
}
_coordinates = { coords, coords + count };
[self computeBounds];
}
return self;
@@ -65,52 +60,87 @@ mbgl::Color MGLColorObjectFromCGColorRef(CGColorRef cgColor)
std::copy(_coordinates.begin() + range.location, _coordinates.begin() + NSMaxRange(range), coords);
}
- (void)setCoordinates:(CLLocationCoordinate2D *)coords count:(NSUInteger)count {
if (!count) {
[NSException raise:NSInvalidArgumentException
format:@"A multipoint must have at least one vertex."];
}
[self willChangeValueForKey:@"coordinates"];
_coordinates = { coords, coords + count };
_bounds = {};
[self didChangeValueForKey:@"coordinates"];
}
- (void)insertCoordinates:(const CLLocationCoordinate2D *)coords count:(NSUInteger)count atIndex:(NSUInteger)index {
if (!count) {
return;
}
if (index > _coordinates.size()) {
[NSException raise:NSRangeException
format:@"Invalid index %lu for existing coordinate count %ld",
(unsigned long)index, (unsigned long)[self pointCount]];
}
[self willChangeValueForKey:@"coordinates"];
_coordinates.insert(_coordinates.begin() + index, count, *coords);
_bounds = {};
[self didChangeValueForKey:@"coordinates"];
}
- (void)appendCoordinates:(const CLLocationCoordinate2D *)coords count:(NSUInteger)count
{
[self willChangeValueForKey:@"coordinates"];
_coordinates.insert(_coordinates.end(), count, *coords);
[self computeBounds];
[self didChangeValueForKey:@"coordinates"];
[self insertCoordinates:coords count:count atIndex:_coordinates.size()];
}
- (void)replaceCoordinatesInRange:(NSRange)range withCoordinates:(const CLLocationCoordinate2D *)coords
{
if (range.length == 0)
{
[self replaceCoordinatesInRange:range withCoordinates:coords count:range.length];
}
- (void)replaceCoordinatesInRange:(NSRange)range withCoordinates:(const CLLocationCoordinate2D *)coords count:(NSUInteger)count {
if (!count && !range.length) {
return;
}
if (NSMaxRange(range) > _coordinates.size())
{
if (NSMaxRange(range) > _coordinates.size()) {
[NSException raise:NSRangeException
format:@"Invalid range %@ for existing coordinate count %ld",
NSStringFromRange(range), (unsigned long)[self pointCount]];
}
[self willChangeValueForKey:@"coordinates"];
std::copy(coords, coords + range.length, _coordinates.begin() + range.location);
[self computeBounds];
std::copy(coords, coords + MIN(count, range.length), _coordinates.begin() + range.location);
if (count >= range.length) {
_coordinates.insert(_coordinates.begin() + NSMaxRange(range), coords, coords + count - range.length);
} else {
_coordinates.erase(_coordinates.begin() + range.location + count, _coordinates.begin() + NSMaxRange(range));
}
_bounds = {};
[self didChangeValueForKey:@"coordinates"];
}
- (void)computeBounds
{
mbgl::LatLngBounds bounds = mbgl::LatLngBounds::empty();
for (auto coordinate : _coordinates)
{
bounds.extend(mbgl::LatLng(coordinate.latitude, coordinate.longitude));
}
_bounds = MGLCoordinateBoundsFromLatLngBounds(bounds);
- (void)removeCoordinatesInRange:(NSRange)range {
CLLocationCoordinate2D coords;
[self replaceCoordinatesInRange:range withCoordinates:&coords count:0];
}
- (MGLCoordinateBounds)overlayBounds
{
return _bounds;
if (!_bounds) {
mbgl::LatLngBounds bounds = mbgl::LatLngBounds::empty();
for (auto coordinate : _coordinates) {
bounds.extend(mbgl::LatLng(coordinate.latitude, coordinate.longitude));
}
_bounds = bounds;
}
return MGLCoordinateBoundsFromLatLngBounds(*_bounds);
}
- (BOOL)intersectsOverlayBounds:(MGLCoordinateBounds)overlayBounds
{
return MGLLatLngBoundsFromCoordinateBounds(_bounds).intersects(MGLLatLngBoundsFromCoordinateBounds(overlayBounds));
return MGLCoordinateBoundsIntersectsCoordinateBounds(self.overlayBounds, overlayBounds);
}
- (mbgl::Annotation)annotationObjectWithDelegate:(__unused id <MGLMultiPointDelegate>)delegate
@@ -122,7 +152,8 @@ mbgl::Color MGLColorObjectFromCGColorRef(CGColorRef cgColor)
- (NSString *)description
{
return [NSString stringWithFormat:@"<%@: %p; count = %lu; bounds = %@>",
NSStringFromClass([self class]), (void *)self, (unsigned long)[self pointCount], MGLStringFromCoordinateBounds(_bounds)];
NSStringFromClass([self class]), (void *)self, (unsigned long)[self pointCount],
MGLStringFromCoordinateBounds(self.overlayBounds)];
}
@end

View File

@@ -0,0 +1,34 @@
#import <Foundation/Foundation.h>
#import <CoreLocation/CoreLocation.h>
#import "MGLStyleValue.h"
#import "MGLStyleLayer.h"
NS_ASSUME_NONNULL_BEGIN
@class MGLMapView;
typedef struct MGLStyleLayerDrawingContext {
CGSize size;
CLLocationCoordinate2D centerCoordinate;
double zoomLevel;
CLLocationDirection direction;
CGFloat pitch;
CGFloat perspectiveSkew;
} MGLStyleLayerDrawingContext;
@interface MGLOpenGLStyleLayer : MGLStyleLayer
@property (nonatomic, weak, readonly) MGLMapView *mapView;
- (void)didMoveToMapView:(MGLMapView *)mapView;
- (void)willMoveFromMapView:(MGLMapView *)mapView;
- (void)drawInMapView:(MGLMapView *)mapView withContext:(MGLStyleLayerDrawingContext)context;
- (void)setNeedsDisplay;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,209 @@
#import "MGLOpenGLStyleLayer.h"
#import "MGLMapView_Private.h"
#import "MGLStyle_Private.h"
#import "MGLStyleLayer_Private.h"
#include <mbgl/style/layers/custom_layer.hpp>
#include <mbgl/math/wrap.hpp>
/**
Runs the preparation handler block contained in the given context, which is
implicitly an instance of `MGLOpenGLStyleLayer`.
@param context An `MGLOpenGLStyleLayer` instance that was provided as context
when creating an OpenGL style layer.
*/
void MGLPrepareCustomStyleLayer(void *context) {
MGLOpenGLStyleLayer *layer = (__bridge MGLOpenGLStyleLayer *)context;
[layer didMoveToMapView:layer.mapView];
}
/**
Runs the drawing handler block contained in the given context, which is
implicitly an instance of `MGLOpenGLStyleLayer`.
@param context An `MGLOpenGLStyleLayer` instance that was provided as context
when creating an OpenGL style layer.
*/
void MGLDrawCustomStyleLayer(void *context, const mbgl::style::CustomLayerRenderParameters &params) {
MGLOpenGLStyleLayer *layer = (__bridge MGLOpenGLStyleLayer *)context;
MGLStyleLayerDrawingContext drawingContext = {
.size = CGSizeMake(params.width, params.height),
.centerCoordinate = CLLocationCoordinate2DMake(params.latitude, params.longitude),
.zoomLevel = params.zoom,
.direction = mbgl::util::wrap(params.bearing, 0., 360.),
.pitch = static_cast<CGFloat>(params.pitch),
.perspectiveSkew = static_cast<CGFloat>(params.altitude),
};
[layer drawInMapView:layer.mapView withContext:drawingContext];
}
/**
Runs the completion handler block contained in the given context, which is
implicitly an instance of `MGLOpenGLStyleLayer`.
@param context An `MGLOpenGLStyleLayer` instance that was provided as context
when creating an OpenGL style layer.
*/
void MGLFinishCustomStyleLayer(void *context) {
MGLOpenGLStyleLayer *layer = (__bridge MGLOpenGLStyleLayer *)context;
[layer willMoveFromMapView:layer.mapView];
}
/**
An `MGLOpenGLStyleLayer` is a style layer that is rendered by OpenGL code in
Objective-C blocks or Swift closures that you specify. You may initialize a new
OpenGL style layer to add to an `MGLStyle` or obtain one from an `MGLMapView`’s
current style using the `-[MGLStyle layerWithIdentifier:]` method.
@warning This API is undocumented and therefore unsupported. It may change at
any time without notice.
*/
@interface MGLOpenGLStyleLayer ()
@property (nonatomic) mbgl::style::CustomLayer *rawLayer;
/**
The map view whose style currently contains the layer.
If the layer is not currently part of any map view’s style, this property is
set to `nil`.
*/
@property (nonatomic, weak, readwrite) MGLMapView *mapView;
@end
@implementation MGLOpenGLStyleLayer {
std::unique_ptr<mbgl::style::CustomLayer> _pendingLayer;
}
/**
Returns an OpenGL style layer object initialized with the given identifier.
After initializing and configuring the style layer, add it to a map view’s
style using the `-[MGLStyle addLayer:]` or
`-[MGLStyle insertLayer:belowLayer:]` method.
@param identifier A string that uniquely identifies the layer in the style to
which it is added.
@return An initialized OpenGL style layer.
*/
- (instancetype)initWithIdentifier:(NSString *)identifier {
if (self = [super initWithIdentifier:identifier]) {
auto layer = std::make_unique<mbgl::style::CustomLayer>(identifier.UTF8String,
MGLPrepareCustomStyleLayer,
MGLDrawCustomStyleLayer,
MGLFinishCustomStyleLayer,
(__bridge void *)self);
_pendingLayer = std::move(layer);
self.rawLayer = _pendingLayer.get();
}
return self;
}
- (mbgl::style::CustomLayer *)rawLayer {
return (mbgl::style::CustomLayer *)super.rawLayer;
}
- (void)setRawLayer:(mbgl::style::CustomLayer *)rawLayer {
super.rawLayer = rawLayer;
}
#pragma mark - Adding to and removing from a map view
- (void)setMapView:(MGLMapView *)mapView {
if (_mapView && mapView) {
[NSException raise:@"MGLLayerReuseException"
format:@"%@ cannot be added to more than one MGLStyle at a time.", self];
}
_mapView.style.openGLLayers[self.identifier] = nil;
_mapView = mapView;
_mapView.style.openGLLayers[self.identifier] = self;
}
- (void)addToMapView:(MGLMapView *)mapView belowLayer:(MGLStyleLayer *)otherLayer {
self.mapView = mapView;
if (otherLayer) {
const mbgl::optional<std::string> belowLayerId{ otherLayer.identifier.UTF8String };
mapView.mbglMap->addLayer(std::move(_pendingLayer), belowLayerId);
} else {
mapView.mbglMap->addLayer(std::move(_pendingLayer));
}
}
- (void)removeFromMapView:(MGLMapView *)mapView {
auto removedLayer = mapView.mbglMap->removeLayer(self.identifier.UTF8String);
self.mapView = nil;
if (!removedLayer) {
return;
}
_pendingLayer = std::move(reinterpret_cast<std::unique_ptr<mbgl::style::CustomLayer> &>(removedLayer));
self.rawLayer = _pendingLayer.get();
}
/**
Called immediately after a layer is added to a map view’s style.
This method is intended to be overridden in a subclass. You can use this method
to perform any setup work before the layer is used to draw a frame. For
example, you might use this method to compile an OpenGL shader. The default
implementation of this method does nothing.
Any resource acquired in this method must be released in
`-willMoveFromMapView:`.
@param mapView The map view to whose style the layer has been added.
*/
- (void)didMoveToMapView:(MGLMapView *)mapView {
}
/**
Called immediately before a layer is removed from a map view’s style.
This method is intended to be overridden in a subclass. You can use this method
to perform any teardown work once the layer has drawn its last frame and is
about to be removed from the style. The default implementation of this method
does nothing.
This method may be called even if `-didMoveToMapView:` has not been called.
@param mapView The map view from whose style the layer is about to be removed.
*/
- (void)willMoveFromMapView:(MGLMapView *)mapView {
}
/**
Called each time the layer needs to draw a new frame in a map view.
This method is intended to be overridden in a subclass. You can use this method
to draw the layer’s content. The default implementation of this method does
nothing.
Your implementation should not make any assumptions about the OpenGL state,
other than that the current OpenGL context is active. It may make changes to
the OpenGL state. It is not required to reset values such as the depth mask,
stencil mask, or corresponding test flags to their original values.
Be sure to draw your fragments with a <var>z</var> value of 1 to take advantage
of the opaque fragment culling, in case the style contains any opaque layers
above this layer.
@param mapView The map view to which the layer draws.
@param context A context structure with information defining the frame to draw.
*/
- (void)drawInMapView:(MGLMapView *)mapView withContext:(MGLStyleLayerDrawingContext)context {
}
/**
Forces the map view associated with this style to redraw the receiving layer,
causing the `-drawInMapView:withContext:` method to be called.
*/
- (void)setNeedsDisplay {
[self.mapView setNeedsGLDisplay];
}
@end

View File

@@ -17,14 +17,6 @@ NS_ASSUME_NONNULL_BEGIN
example, you could use an overlay to show the boundaries of a national park or
trace a bus route along city streets. This SDK defines several concrete classes
that conform to this protocol and define standard shapes.
Because overlays are also annotations, they have similar usage pattern to
annotations. When added to a map view using the `-addOverlay:` method, that
view detects whenever the overlay’s defined region intersects the visible
portion of the map. At that point, the map view asks its delegate to provide a
special overlay view to draw the visual representation of the overlay. If you
add an overlay to a map view as an annotation instead, it is treated as an
annotation with a single point.
*/
@protocol MGLOverlay <MGLAnnotation>

View File

@@ -24,10 +24,10 @@
@"coordinates": @[@(self.coordinate.longitude), @(self.coordinate.latitude)]};
}
- (mbgl::Feature)featureObject
- (mbgl::Geometry<double>)geometryObject
{
mbgl::Point<double> point = { self.coordinate.longitude, self.coordinate.latitude };
return mbgl::Feature {point};
return point;
}
@end

View File

@@ -11,7 +11,7 @@
@note `MGLPointCollection` objects cannot be added to a map view using
`-[MGLMapView addAnnotations:]` and related methods. However, when used in a
`MGLPointCollectionFeature` to initialize a `MGLGeoJSONSource` that is added
`MGLPointCollectionFeature` to initialize a `MGLShapeSource` that is added
to the map view's style, the point collection represents as a group of distinct
annotations.
*/

View File

@@ -1,17 +1,19 @@
#import "MGLPointCollection_Private.h"
#import "MGLGeometry_Private.h"
#import <mbgl/util/geojson.hpp>
#import <mbgl/util/geometry.hpp>
#import <mbgl/util/feature.hpp>
NS_ASSUME_NONNULL_BEGIN
@implementation MGLPointCollection
{
MGLCoordinateBounds _bounds;
MGLCoordinateBounds _overlayBounds;
std::vector<CLLocationCoordinate2D> _coordinates;
}
@synthesize overlayBounds = _overlayBounds;
+ (instancetype)pointCollectionWithCoordinates:(const CLLocationCoordinate2D *)coords count:(NSUInteger)count
{
return [[self alloc] initWithCoordinates:coords count:count];
@@ -28,7 +30,7 @@ NS_ASSUME_NONNULL_BEGIN
{
bounds.extend(mbgl::LatLng(coordinate.latitude, coordinate.longitude));
}
_bounds = MGLCoordinateBoundsFromLatLngBounds(bounds);
_overlayBounds = MGLCoordinateBoundsFromLatLngBounds(bounds);
}
return self;
}
@@ -61,17 +63,12 @@ NS_ASSUME_NONNULL_BEGIN
std::copy(_coordinates.begin() + range.location, _coordinates.begin() + NSMaxRange(range), coords);
}
- (MGLCoordinateBounds)overlayBounds
{
return _bounds;
}
- (BOOL)intersectsOverlayBounds:(MGLCoordinateBounds)overlayBounds
{
return MGLLatLngBoundsFromCoordinateBounds(_bounds).intersects(MGLLatLngBoundsFromCoordinateBounds(overlayBounds));
return MGLCoordinateBoundsIntersectsCoordinateBounds(_overlayBounds, overlayBounds);
}
- (mbgl::Feature)featureObject
- (mbgl::Geometry<double>)geometryObject
{
mbgl::MultiPoint<double> multiPoint;
multiPoint.reserve(self.pointCount);
@@ -79,7 +76,7 @@ NS_ASSUME_NONNULL_BEGIN
{
multiPoint.push_back(mbgl::Point<double>(self.coordinates[i].longitude, self.coordinates[i].latitude));
}
return mbgl::Feature {multiPoint};
return multiPoint;
}
- (NSDictionary *)geoJSONDictionary

View File

@@ -5,6 +5,8 @@
#import "MGLPolygon+MGLAdditions.h"
#import <mbgl/util/geojson.hpp>
@implementation MGLPolygon
@dynamic overlayBounds;
@@ -38,23 +40,22 @@
return result;
}
- (mbgl::Feature)featureObject {
- (mbgl::Polygon<double>)polygon {
mbgl::Polygon<double> geometry;
geometry.push_back(self.ring);
for (MGLPolygon *polygon in self.interiorPolygons) {
geometry.push_back(polygon.ring);
}
return mbgl::Feature{geometry};
return geometry;
}
- (mbgl::Geometry<double>)geometryObject {
return [self polygon];
}
- (mbgl::Annotation)annotationObjectWithDelegate:(id <MGLMultiPointDelegate>)delegate {
mbgl::Polygon<double> geometry;
geometry.push_back(self.ring);
for (MGLPolygon *polygon in self.interiorPolygons) {
geometry.push_back(polygon.ring);
}
mbgl::FillAnnotation annotation { geometry };
mbgl::FillAnnotation annotation { [self polygon] };
annotation.opacity = { static_cast<float>([delegate alphaForShapeAnnotation:self]) };
annotation.outlineColor = { [delegate strokeColorForShapeAnnotation:self] };
annotation.color = { [delegate fillColorForPolygonAnnotation:self] };
@@ -100,10 +101,10 @@
}
- (BOOL)intersectsOverlayBounds:(MGLCoordinateBounds)overlayBounds {
return MGLLatLngBoundsFromCoordinateBounds(_overlayBounds).intersects(MGLLatLngBoundsFromCoordinateBounds(overlayBounds));
return MGLCoordinateBoundsIntersectsCoordinateBounds(_overlayBounds, overlayBounds);
}
- (mbgl::Feature)featureObject {
- (mbgl::Geometry<double>)geometryObject {
mbgl::MultiPolygon<double> multiPolygon;
multiPolygon.reserve(self.polygons.count);
for (MGLPolygon *polygon in self.polygons) {
@@ -114,7 +115,7 @@
}
multiPolygon.push_back(geometry);
}
return mbgl::Feature {multiPolygon};
return multiPolygon;
}
- (NSDictionary *)geoJSONDictionary {

View File

@@ -5,6 +5,8 @@
#import "MGLPolyline+MGLAdditions.h"
#import <mbgl/util/geojson.hpp>
@implementation MGLPolyline
@dynamic overlayBounds;
@@ -37,8 +39,8 @@
return annotation;
}
- (mbgl::Feature)featureObject {
return mbgl::Feature {[self lineString]};
- (mbgl::Geometry<double>)geometryObject {
return [self lineString];
}
- (NSDictionary *)geoJSONDictionary {
@@ -79,16 +81,16 @@
}
- (BOOL)intersectsOverlayBounds:(MGLCoordinateBounds)overlayBounds {
return MGLLatLngBoundsFromCoordinateBounds(_overlayBounds).intersects(MGLLatLngBoundsFromCoordinateBounds(overlayBounds));
return MGLCoordinateBoundsIntersectsCoordinateBounds(_overlayBounds, overlayBounds);
}
- (mbgl::Feature)featureObject {
- (mbgl::Geometry<double>)geometryObject {
mbgl::MultiLineString<double> multiLineString;
multiLineString.reserve(self.polylines.count);
for (MGLPolyline *polyline in self.polylines) {
multiLineString.push_back([polyline lineString]);
}
return mbgl::Feature {multiLineString};
return multiLineString;
}
- (NSDictionary *)geoJSONDictionary {

View File

@@ -1,88 +1,94 @@
#import "MGLSource.h"
#import "MGLTypes.h"
#import "MGLTileSource.h"
#import <CoreGraphics/CoreGraphics.h>
@class MGLTileSet;
NS_ASSUME_NONNULL_BEGIN
/**
A raster tile source.
An `NSNumber` object containing a floating-point number that specifies the
width and height (measured in points) at which the map displays each raster
image tile when the map’s zoom level is an integer. The raster source scales
its images up or down when the map’s zoom level falls between two integers.
@see <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-raster">The
style specification.</a>
The default value for this option is 512. Version 4 of the
<a href="https://www.mapbox.com/api-documentation/#maps">Mapbox Maps API</a>
requires a value of 256, as do many third-party tile servers, so consult your
provider’s documentation for the correct value.
This option is only applicable to `MGLRasterSource` objects; it is ignored when
initializing `MGLVectorSource` objects.
*/
@interface MGLRasterSource : MGLSource
extern const MGLTileSourceOption MGLTileSourceOptionTileSize;
/**
`MGLRasterSource` is a map content source that supplies raster image tiles to
be shown on the map. The location of and metadata about the tiles are defined
either by an option dictionary or by an external file that conforms to the
<a href="https://github.com/mapbox/tilejson-spec/">TileJSON specification</a>.
A raster source is added to an `MGLStyle` object along with one or more
`MGLRasterStyleLayer` objects. Use a raster style layer to control the
appearance of content supplied by the raster source.
Each
<a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-raster"><code>raster</code></a>
source defined by the style JSON file is represented at runtime by an
`MGLRasterSource` object that you can use to initialize new style layers. You
can also add and remove sources dynamically using methods such as
`-[MGLStyle addSource:]` and `-[MGLStyle sourceWithIdentifier:]`.
*/
@interface MGLRasterSource : MGLTileSource
#pragma mark Initializing a Source
/**
Returns a raster source initialized with an identifier, TileJSON configuration
URL, and tile size.
Returns a raster source initialized with an identifier and configuration URL.
After initializing and configuring the source, add it to a map view’s style
using the `-[MGLStyle addSource:]` method.
The URL may be a full HTTP or HTTPS URL or, for tile sets hosted by Mapbox, a
Mapbox URL indicating a map identifier (`mapbox://<mapid>`). The URL should
point to a JSON file that conforms to the
<a href="https://github.com/mapbox/tilejson-spec/">TileJSON specification</a>.
If a Mapbox URL is specified, this source uses a tile size of 256. For all
other tile sets, the default value is 512. (See the
`MGLTileSourceOptionTileSize` documentation for more information about tile
sizes.) If you need to use a tile size other than the default, use the
`-initWithIdentifier:configurationURL:tileSize:` method.
@param identifier A string that uniquely identifies the source in the style to
which it is added.
@param url A URL to a TileJSON configuration file describing the source’s
contents and other metadata.
@param tileSize The height and width (measured in points) at which to display
each tile in this source when the map’s zoom level is an integer.
@param configurationURL A URL to a TileJSON configuration file describing the
source’s contents and other metadata.
@return An initialized raster source.
*/
- (instancetype)initWithIdentifier:(NSString *)identifier URL:(NSURL *)url tileSize:(CGFloat)tileSize NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithIdentifier:(NSString *)identifier configurationURL:(NSURL *)configurationURL;
/**
Returns a raster source initialized with the given identifier, tile size, and
tile set.
Returns a raster source initialized with an identifier, configuration URL, and
tile size.
After initializing and configuring the source, add it to a map view’s style
using the `-[MGLStyle addSource:]` method.
The URL may be a full HTTP or HTTPS URL or, for tile sets hosted by Mapbox, a
Mapbox URL indicating a map identifier (`mapbox://<mapid>`). The URL should
point to a JSON file that conforms to the
<a href="https://github.com/mapbox/tilejson-spec/">TileJSON specification</a>.
@param identifier A string that uniquely identifies the source in the style to
which it is added.
@param tileSet A tile set describing the source’s contents and other metadata.
@param tileSize The height and width (measured in points) at which to display
each tile in this source when the map’s zoom level is an integer.
@param configurationURL A URL to a TileJSON configuration file describing the
source’s contents and other metadata.
@param tileSize The width and height (measured in points) of each tiled image
in the raster source. See the `MGLTileSourceOptionTileSize` documentation
for details.
@return An initialized raster source.
*/
- (instancetype)initWithIdentifier:(NSString *)identifier tileSet:(MGLTileSet *)tileSet tileSize:(CGFloat)tileSize NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithIdentifier:(NSString *)identifier configurationURL:(NSURL *)configurationURL tileSize:(CGFloat)tileSize NS_DESIGNATED_INITIALIZER;
#pragma mark Accessing a Source’s Content
/**
A URL to a TileJSON configuration file describing the source’s contents and
other metadata.
The URL may be a full HTTP or HTTPS URL or a Mapbox URL indicating the tile
set’s map ID (`mapbox://<mapid>`).
@see <a href="https://www.mapbox.com/help/an-open-platform/#tilejson">The
TileJSON specification.</a>
*/
@property (nonatomic, readonly, copy) NSURL *URL;
/**
The height and width (measured in points) at which to display each tile in this
source when the map’s zoom level is an integer.
A tile may be scaled up or down when the zoom level is between two integers.
The default value of this property is 512 points.
*/
@property (nonatomic, readonly, assign) NSUInteger tileSize;
/**
The tile set used to locate and download tiles.
A tile set holds the raster tile URL template strings and associated
configuration for those strings. It can be passed in place of the URL
to TileJSON in order to create a source configured to download tiles
from ordinary web URLs.
*/
@property (nonatomic, readonly, nullable) MGLTileSet *tileSet;
- (instancetype)initWithIdentifier:(NSString *)identifier tileURLTemplates:(NS_ARRAY_OF(NSString *) *)tileURLTemplates options:(nullable NS_DICTIONARY_OF(MGLTileSourceOption, id) *)options NS_DESIGNATED_INITIALIZER;
@end

View File

@@ -1,90 +1,103 @@
#import "MGLRasterSource.h"
#import "MGLRasterSource_Private.h"
#import "MGLMapView_Private.h"
#import "MGLSource_Private.h"
#import "MGLTileSet_Private.h"
#import "MGLTileSource_Private.h"
#import "NSURL+MGLAdditions.h"
#include <mbgl/style/sources/raster_source.hpp>
const MGLTileSourceOption MGLTileSourceOptionTileSize = @"MGLTileSourceOptionTileSize";
static const CGFloat MGLRasterSourceClassicTileSize = 256;
static const CGFloat MGLRasterSourceRetinaTileSize = 512;
@interface MGLRasterSource ()
- (instancetype)initWithRawSource:(mbgl::style::RasterSource *)rawSource NS_DESIGNATED_INITIALIZER;
@property (nonatomic) mbgl::style::RasterSource *rawSource;
@end
@implementation MGLRasterSource
{
@implementation MGLRasterSource {
std::unique_ptr<mbgl::style::RasterSource> _pendingSource;
}
- (instancetype)initWithIdentifier:(NSString *)identifier URL:(NSURL *)url tileSize:(CGFloat)tileSize
{
if (self = [super initWithIdentifier:identifier]) {
_URL = url;
_tileSize = tileSize;
[self commonInit];
- (instancetype)initWithIdentifier:(NSString *)identifier configurationURL:(NSURL *)configurationURL {
// The style specification default is 512, but 256 is the expected value for
// any tile set that would be accessed through a mapbox: URL and therefore
// any tile URL that this option currently affects.
BOOL isMapboxURL = ([configurationURL.scheme isEqualToString:@"mapbox"]
&& [configurationURL.host containsString:@"."]
&& (!configurationURL.path.length || [configurationURL.path isEqualToString:@"/"]));
CGFloat tileSize = isMapboxURL ? MGLRasterSourceClassicTileSize : MGLRasterSourceRetinaTileSize;
return [self initWithIdentifier:identifier configurationURL:configurationURL tileSize:tileSize];
}
- (instancetype)initWithIdentifier:(NSString *)identifier configurationURL:(NSURL *)configurationURL tileSize:(CGFloat)tileSize {
if (self = [super initWithIdentifier:identifier configurationURL:configurationURL]) {
auto source = std::make_unique<mbgl::style::RasterSource>(identifier.UTF8String,
configurationURL.mgl_URLByStandardizingScheme.absoluteString.UTF8String,
uint16_t(round(tileSize)));
_pendingSource = std::move(source);
self.rawSource = _pendingSource.get();
}
return self;
}
- (instancetype)initWithIdentifier:(NSString *)identifier tileSet:(MGLTileSet *)tileSet tileSize:(CGFloat)tileSize;
{
if (self = [super initWithIdentifier:identifier])
{
_tileSet = tileSet;
_tileSize = tileSize;
[self commonInit];
- (instancetype)initWithIdentifier:(NSString *)identifier tileURLTemplates:(NS_ARRAY_OF(NSString *) *)tileURLTemplates options:(nullable NS_DICTIONARY_OF(MGLTileSourceOption, id) *)options {
if (self = [super initWithIdentifier:identifier tileURLTemplates:tileURLTemplates options:options]) {
mbgl::Tileset tileSet = MGLTileSetFromTileURLTemplates(tileURLTemplates, options);
uint16_t tileSize;
if (NSNumber *tileSizeNumber = options[MGLTileSourceOptionTileSize]) {
if (![tileSizeNumber isKindOfClass:[NSNumber class]]) {
[NSException raise:NSInvalidArgumentException
format:@"MGLTileSourceOptionTileSize must be set to an NSNumber."];
}
tileSize = static_cast<uint16_t>(round(tileSizeNumber.doubleValue));
}
auto source = std::make_unique<mbgl::style::RasterSource>(identifier.UTF8String, tileSet, tileSize);
_pendingSource = std::move(source);
self.rawSource = _pendingSource.get();
}
return self;
}
- (void)commonInit
{
std::unique_ptr<mbgl::style::RasterSource> source;
if (self.URL)
{
source = std::make_unique<mbgl::style::RasterSource>(self.identifier.UTF8String,
self.URL.mgl_URLByStandardizingScheme.absoluteString.UTF8String,
uint16_t(self.tileSize));
}
else
{
source = std::make_unique<mbgl::style::RasterSource>(self.identifier.UTF8String,
self.tileSet.mbglTileset,
uint16_t(self.tileSize));
}
_pendingSource = std::move(source);
self.rawSource = _pendingSource.get();
- (instancetype)initWithRawSource:(mbgl::style::RasterSource *)rawSource {
return [super initWithRawSource:rawSource];
}
- (void)addToMapView:(MGLMapView *)mapView
{
- (void)addToMapView:(MGLMapView *)mapView {
if (_pendingSource == nullptr) {
[NSException raise:@"MGLRedundantSourceException"
format:@"This instance %@ was already added to %@. Adding the same source instance " \
"to the style more than once is invalid.", self, mapView.style];
@"to the style more than once is invalid.", self, mapView.style];
}
mapView.mbglMap->addSource(std::move(_pendingSource));
}
- (void)removeFromMapView:(MGLMapView *)mapView
{
- (void)removeFromMapView:(MGLMapView *)mapView {
auto removedSource = mapView.mbglMap->removeSource(self.identifier.UTF8String);
_pendingSource = std::move(reinterpret_cast<std::unique_ptr<mbgl::style::RasterSource> &>(removedSource));
self.rawSource = _pendingSource.get();
}
- (NSString *)description
{
return [NSString stringWithFormat:
@"<%@: %p; identifier = %@; URL = %@; tileSet = %@; tileSize = %lu>",
NSStringFromClass([self class]), (void *)self, self.identifier, self.URL,
self.tileSet, (unsigned long)self.tileSize];
- (mbgl::style::RasterSource *)rawSource {
return (mbgl::style::RasterSource *)super.rawSource;
}
- (void)setRawSource:(mbgl::style::RasterSource *)rawSource {
super.rawSource = rawSource;
}
- (NSString *)attributionHTMLString {
auto attribution = self.rawSource->getAttribution();
return attribution ? @(attribution->c_str()) : nil;
}
@end

View File

@@ -0,0 +1,17 @@
#import "MGLRasterSource.h"
NS_ASSUME_NONNULL_BEGIN
namespace mbgl {
namespace style {
class RasterSource;
}
}
@interface MGLRasterSource (Private)
- (instancetype)initWithRawSource:(mbgl::style::RasterSource *)rawSource;
@end
NS_ASSUME_NONNULL_END

View File

@@ -20,16 +20,26 @@ NS_ASSUME_NONNULL_BEGIN
Increase or reduce the brightness of the image. The value is the maximum brightness.
The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `1`. Set this property to `nil` to reset it to the default value.
This attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-raster-brightness-max"><code>raster-brightness-max</code></a> paint property in the Mapbox Style Specification.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *maximumRasterBrightness;
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *rasterBrightnessMax __attribute__((unavailable("Use maximumRasterBrightness instead.")));
/**
Increase or reduce the brightness of the image. The value is the minimum brightness.
The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `0`. Set this property to `nil` to reset it to the default value.
This attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-raster-brightness-min"><code>raster-brightness-min</code></a> paint property in the Mapbox Style Specification.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *minimumRasterBrightness;
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *rasterBrightnessMin __attribute__((unavailable("Use minimumRasterBrightness instead.")));
/**
Increase or reduce the contrast of the image.
@@ -52,8 +62,13 @@ NS_ASSUME_NONNULL_BEGIN
This property is measured in degrees.
The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `0`. Set this property to `nil` to reset it to the default value.
This attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-raster-hue-rotate"><code>raster-hue-rotate</code></a> paint property in the Mapbox Style Specification.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *rasterHueRotate;
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *rasterHueRotation;
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *rasterHueRotate __attribute__((unavailable("Use rasterHueRotation instead.")));
/**
The opacity at which the image will be drawn.

View File

@@ -26,13 +26,24 @@
if (self = [super initWithIdentifier:identifier source:source]) {
auto layer = std::make_unique<mbgl::style::RasterLayer>(identifier.UTF8String, source.identifier.UTF8String);
_pendingLayer = std::move(layer);
_rawLayer = _pendingLayer.get();
self.rawLayer = _pendingLayer.get();
}
return self;
}
#pragma mark - Adding to and removing from a map view
- (void)addToMapView:(MGLMapView *)mapView
- (mbgl::style::RasterLayer *)rawLayer
{
return (mbgl::style::RasterLayer *)super.rawLayer;
}
- (void)setRawLayer:(mbgl::style::RasterLayer *)rawLayer
{
super.rawLayer = rawLayer;
}
#pragma mark - Adding to and removing from a map view
- (void)addToMapView:(MGLMapView *)mapView belowLayer:(MGLStyleLayer *)otherLayer
{
if (_pendingLayer == nullptr) {
[NSException raise:@"MGLRedundantLayerException"
@@ -40,11 +51,6 @@
"to the style more than once is invalid.", self, mapView.style];
}
[self addToMapView:mapView belowLayer:nil];
}
- (void)addToMapView:(MGLMapView *)mapView belowLayer:(MGLStyleLayer *)otherLayer
{
if (otherLayer) {
const mbgl::optional<std::string> belowLayerId{otherLayer.identifier.UTF8String};
mapView.mbglMap->addLayer(std::move(_pendingLayer), belowLayerId);
@@ -56,7 +62,7 @@
- (void)removeFromMapView:(MGLMapView *)mapView
{
_pendingLayer = nullptr;
_rawLayer = nullptr;
self.rawLayer = nullptr;
auto removedLayer = mapView.mbglMap->removeLayer(self.identifier.UTF8String);
if (!removedLayer) {
@@ -71,7 +77,7 @@
removedLayer.release();
_pendingLayer = std::unique_ptr<mbgl::style::RasterLayer>(layer);
_rawLayer = _pendingLayer.get();
self.rawLayer = _pendingLayer.get();
}
#pragma mark - Accessing the Paint Attributes
@@ -80,41 +86,51 @@
MGLAssertStyleLayerIsValid();
auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(maximumRasterBrightness);
_rawLayer->setRasterBrightnessMax(mbglValue);
self.rawLayer->setRasterBrightnessMax(mbglValue);
}
- (MGLStyleValue<NSNumber *> *)maximumRasterBrightness {
MGLAssertStyleLayerIsValid();
auto propertyValue = _rawLayer->getRasterBrightnessMax() ?: _rawLayer->getDefaultRasterBrightnessMax();
auto propertyValue = self.rawLayer->getRasterBrightnessMax() ?: self.rawLayer->getDefaultRasterBrightnessMax();
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
}
- (void)setRasterBrightnessMax:(MGLStyleValue<NSNumber *> *)rasterBrightnessMax {
NSAssert(NO, @"Use -setMaximumRasterBrightness: instead.");
}
- (void)setMinimumRasterBrightness:(MGLStyleValue<NSNumber *> *)minimumRasterBrightness {
MGLAssertStyleLayerIsValid();
auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(minimumRasterBrightness);
_rawLayer->setRasterBrightnessMin(mbglValue);
self.rawLayer->setRasterBrightnessMin(mbglValue);
}
- (MGLStyleValue<NSNumber *> *)minimumRasterBrightness {
MGLAssertStyleLayerIsValid();
auto propertyValue = _rawLayer->getRasterBrightnessMin() ?: _rawLayer->getDefaultRasterBrightnessMin();
auto propertyValue = self.rawLayer->getRasterBrightnessMin() ?: self.rawLayer->getDefaultRasterBrightnessMin();
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
}
- (void)setRasterBrightnessMin:(MGLStyleValue<NSNumber *> *)rasterBrightnessMin {
NSAssert(NO, @"Use -setMinimumRasterBrightness: instead.");
}
- (void)setRasterContrast:(MGLStyleValue<NSNumber *> *)rasterContrast {
MGLAssertStyleLayerIsValid();
auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(rasterContrast);
_rawLayer->setRasterContrast(mbglValue);
self.rawLayer->setRasterContrast(mbglValue);
}
- (MGLStyleValue<NSNumber *> *)rasterContrast {
MGLAssertStyleLayerIsValid();
auto propertyValue = _rawLayer->getRasterContrast() ?: _rawLayer->getDefaultRasterContrast();
auto propertyValue = self.rawLayer->getRasterContrast() ?: self.rawLayer->getDefaultRasterContrast();
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
}
@@ -122,41 +138,46 @@
MGLAssertStyleLayerIsValid();
auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(rasterFadeDuration);
_rawLayer->setRasterFadeDuration(mbglValue);
self.rawLayer->setRasterFadeDuration(mbglValue);
}
- (MGLStyleValue<NSNumber *> *)rasterFadeDuration {
MGLAssertStyleLayerIsValid();
auto propertyValue = _rawLayer->getRasterFadeDuration() ?: _rawLayer->getDefaultRasterFadeDuration();
auto propertyValue = self.rawLayer->getRasterFadeDuration() ?: self.rawLayer->getDefaultRasterFadeDuration();
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
}
- (void)setRasterHueRotation:(MGLStyleValue<NSNumber *> *)rasterHueRotation {
MGLAssertStyleLayerIsValid();
auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(rasterHueRotation);
self.rawLayer->setRasterHueRotate(mbglValue);
}
- (MGLStyleValue<NSNumber *> *)rasterHueRotation {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getRasterHueRotate() ?: self.rawLayer->getDefaultRasterHueRotate();
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
}
- (void)setRasterHueRotate:(MGLStyleValue<NSNumber *> *)rasterHueRotate {
MGLAssertStyleLayerIsValid();
auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(rasterHueRotate);
_rawLayer->setRasterHueRotate(mbglValue);
}
- (MGLStyleValue<NSNumber *> *)rasterHueRotate {
MGLAssertStyleLayerIsValid();
auto propertyValue = _rawLayer->getRasterHueRotate() ?: _rawLayer->getDefaultRasterHueRotate();
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
NSAssert(NO, @"Use -setRasterHueRotation: instead.");
}
- (void)setRasterOpacity:(MGLStyleValue<NSNumber *> *)rasterOpacity {
MGLAssertStyleLayerIsValid();
auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(rasterOpacity);
_rawLayer->setRasterOpacity(mbglValue);
self.rawLayer->setRasterOpacity(mbglValue);
}
- (MGLStyleValue<NSNumber *> *)rasterOpacity {
MGLAssertStyleLayerIsValid();
auto propertyValue = _rawLayer->getRasterOpacity() ?: _rawLayer->getDefaultRasterOpacity();
auto propertyValue = self.rawLayer->getRasterOpacity() ?: self.rawLayer->getDefaultRasterOpacity();
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
}
@@ -164,13 +185,13 @@
MGLAssertStyleLayerIsValid();
auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(rasterSaturation);
_rawLayer->setRasterSaturation(mbglValue);
self.rawLayer->setRasterSaturation(mbglValue);
}
- (MGLStyleValue<NSNumber *> *)rasterSaturation {
MGLAssertStyleLayerIsValid();
auto propertyValue = _rawLayer->getRasterSaturation() ?: _rawLayer->getDefaultRasterSaturation();
auto propertyValue = self.rawLayer->getRasterSaturation() ?: self.rawLayer->getDefaultRasterSaturation();
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
}

View File

@@ -13,6 +13,30 @@ NS_ASSUME_NONNULL_BEGIN
*/
@interface MGLShape : NSObject <MGLAnnotation>
#pragma mark Creating a Shape
/**
Returns an `MGLShape` object initialized with the given data interpreted as a
string containing a GeoJSON object.
If the GeoJSON object is a geometry, the returned value is a kind of
`MGLShape`. If it is a feature object, the returned value is a kind of
`MGLShape` that conforms to the `MGLFeature` protocol. If it is a feature
collection object, the returned value is an instance of
`MGLShapeCollectionFeature`.
@param data String data containing GeoJSON source code.
@param encoding The encoding used by `data`.
@param outError Upon return, if an error has occurred, a pointer to an
`NSError` object describing the error. Pass in `NULL` to ignore any error.
@return An `MGLShape` object representation of `data`, or `nil` if `data` could
not be parsed as valid GeoJSON source code. If `nil`, `outError` contains an
`NSError` object describing the problem.
*/
+ (nullable MGLShape *)shapeWithData:(NSData *)data encoding:(NSStringEncoding)encoding error:(NSError * _Nullable *)outError;
#pragma mark Accessing the Shape Attributes
/**
The title of the shape annotation. The default value of this property is `nil`.
*/
@@ -34,6 +58,17 @@ NS_ASSUME_NONNULL_BEGIN
#endif
#pragma mark Creating GeoJSON Data
/**
Returns the GeoJSON string representation of the shape encapsulated in a data
object.
@param encoding The string encoding to use.
@return A data object containing the shape’s GeoJSON string representation.
*/
- (NSData *)geoJSONDataUsingEncoding:(NSStringEncoding)encoding;
@end
NS_ASSUME_NONNULL_END

View File

@@ -1,14 +1,52 @@
#import "MGLShape.h"
#import "MGLShape_Private.h"
#import "MGLFeature_Private.h"
@implementation MGLShape
- (CLLocationCoordinate2D)coordinate
{
[[NSException exceptionWithName:@"MGLAbstractClassException"
reason:@"MGLShape is an abstract class"
userInfo:nil] raise];
+ (nullable MGLShape *)shapeWithData:(NSData *)data encoding:(NSStringEncoding)encoding error:(NSError * _Nullable *)outError {
NSString *string = [[NSString alloc] initWithData:data encoding:encoding];
if (!string) {
if (outError) {
*outError = [NSError errorWithDomain:MGLErrorDomain code:MGLErrorCodeUnknown userInfo:nil];
}
return nil;
}
try {
const auto geojson = mapbox::geojson::parse(string.UTF8String);
return MGLShapeFromGeoJSON(geojson);
} catch (std::runtime_error &err) {
if (outError) {
*outError = [NSError errorWithDomain:MGLErrorDomain code:MGLErrorCodeUnknown userInfo:@{
NSLocalizedFailureReasonErrorKey: @(err.what()),
}];
}
return nil;
}
}
return CLLocationCoordinate2DMake(MAXFLOAT, MAXFLOAT);
- (mbgl::GeoJSON)geoJSONObject {
return self.geometryObject;
}
- (mbgl::Geometry<double>)geometryObject {
[NSException raise:@"MGLAbstractClassException"
format:@"MGLShape is an abstract class"];
return mbgl::Point<double>();
}
- (NSData *)geoJSONDataUsingEncoding:(NSStringEncoding)encoding {
auto geometry = self.geoJSONObject;
NSString *string = @(mapbox::geojson::stringify(geometry).c_str());
return [string dataUsingEncoding:NSUTF8StringEncoding];
}
- (CLLocationCoordinate2D)coordinate {
[NSException raise:@"MGLAbstractClassException"
format:@"MGLShape is an abstract class"];
return kCLLocationCoordinate2DInvalid;
}
@end

View File

@@ -1,5 +1,9 @@
#import "MGLShapeCollection.h"
#import "MGLShape_Private.h"
#import <mbgl/style/conversion/geojson.hpp>
@implementation MGLShapeCollection
+ (instancetype)shapeCollectionWithShapes:(NS_ARRAY_OF(MGLShape *) *)shapes {
@@ -32,4 +36,13 @@
return [geometries copy];
}
- (mbgl::Geometry<double>)geometryObject {
mapbox::geojson::geometry_collection collection;
collection.reserve(self.shapes.count);
for (MGLShape *shape in self.shapes) {
collection.push_back([shape geometryObject]);
}
return collection;
}
@end

View File

@@ -0,0 +1,135 @@
#import "MGLSource.h"
#import "MGLTypes.h"
#import "MGLShape.h"
NS_ASSUME_NONNULL_BEGIN
@protocol MGLFeature;
/**
Options for `MGLShapeSource` objects.
*/
typedef NSString *MGLShapeSourceOption NS_STRING_ENUM;
/**
An `NSNumber` object containing a Boolean enabling or disabling clustering.
If the `shape` property contains point shapes, setting this option to
`YES` clusters the points by radius into groups. The default value is `NO`.
*/
extern const MGLShapeSourceOption MGLShapeSourceOptionClustered;
/**
An `NSNumber` object containing an integer; specifies the radius of each
cluster if clustering is enabled. A value of 512 produces a radius equal to
the width of a tile. The default value is 50.
*/
extern const MGLShapeSourceOption MGLShapeSourceOptionClusterRadius;
/**
An `NSNumber` object containing an integer; specifies the maximum zoom level at
which to cluster points if clustering is enabled. Defaults to one zoom level
less than the value of `MGLShapeSourceOptionMaximumZoomLevel` so that, at the
maximum zoom level, the shapes are not clustered.
*/
extern const MGLShapeSourceOption MGLShapeSourceOptionMaximumZoomLevelForClustering;
/**
An `NSNumber` object containing an integer; specifies the maximum zoom level at
which to create vector tiles. A greater value produces greater detail at high
zoom levels. The default value is 18.
*/
extern const MGLShapeSourceOption MGLShapeSourceOptionMaximumZoomLevel;
/**
An `NSNumber` object containing an integer; specifies the size of the tile
buffer on each side. A value of 0 produces no buffer. A value of 512 produces a
buffer as wide as the tile itself. Larger values produce fewer rendering
artifacts near tile edges and slower performance. The default value is 128.
*/
extern const MGLShapeSourceOption MGLShapeSourceOptionBuffer;
/**
An `NSNumber` object containing a double; specifies the Douglas-Peucker
simplification tolerance. A greater value produces simpler geometries and
improves performance. The default value is 0.375.
*/
extern const MGLShapeSourceOption MGLShapeSourceOptionSimplificationTolerance;
/**
`MGLShapeSource` is a map content source that supplies vector shapes to be
shown on the map. The shapes may be instances of `MGLShape` or `MGLFeature`,
or they may be defined by local or external
<a href="http://geojson.org/">GeoJSON</a> code. A shape source is added to an
`MGLStyle` object along with an `MGLVectorStyleLayer` object. The vector style
layer defines the appearance of any content supplied by the shape source.
Each
<a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-geojson"><code>geojson</code></a>
source defined by the style JSON file is represented at runtime by an
`MGLShapeSource` object that you can use to refine the map’s content and
initialize new style layers. You can also add and remove sources dynamically
using methods such as `-[MGLStyle addSource:]` and
`-[MGLStyle sourceWithIdentifier:]`.
Any vector style layer initialized with a shape source should have a `nil`
value in its `sourceLayerIdentifier` property.
*/
@interface MGLShapeSource : MGLSource
#pragma mark Initializing a Source
/**
Returns a shape source with an identifier, URL, and dictionary of options for
the source.
@param identifier A string that uniquely identifies the source.
@param URL An HTTP(S) URL, absolute file URL, or local file URL relative to the
current application’s resource bundle.
@param options An `NSDictionary` of options for this source.
@return An initialized shape source.
*/
- (instancetype)initWithIdentifier:(NSString *)identifier URL:(NSURL *)url options:(nullable NS_DICTIONARY_OF(MGLShapeSourceOption, id) *)options NS_DESIGNATED_INITIALIZER;
/**
Returns a shape source with an identifier, a shape, and dictionary of options
for the source.
To specify attributes about the shape, use an instance of an `MGLShape`
subclass that conforms to the `MGLFeature` protocol, such as `MGLPointFeature`.
To include multiple shapes in the source, use an `MGLShapeCollection` or
`MGLShapeCollectionFeature` object.
To create a shape from GeoJSON source code, use the
`+[MGLShape shapeWithData:encoding:error:]` method.
@param identifier A string that uniquely identifies the source.
@param shape A concrete subclass of `MGLShape`
@param options An `NSDictionary` of options for this source.
@return An initialized shape source.
*/
- (instancetype)initWithIdentifier:(NSString *)identifier shape:(nullable MGLShape *)shape options:(nullable NS_DICTIONARY_OF(MGLShapeSourceOption, id) *)options NS_DESIGNATED_INITIALIZER;
#pragma mark Accessing a Source’s Content
/**
The contents of the source. A shape can represent a GeoJSON geometry, a
feature, or a collection of features.
If the receiver was initialized using `-initWithIdentifier:URL:options:`, this
property is set to `nil`. This property is unavailable until the receiver is
passed into `-[MGLStyle addSource:]`.
*/
@property (nonatomic, copy, nullable) MGLShape *shape;
/**
The URL to the GeoJSON document that specifies the contents of the source.
If the receiver was initialized using `-initWithIdentifier:shape:options:`,
this property is set to `nil`.
*/
@property (nonatomic, copy, nullable) NSURL *URL;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,165 @@
#import "MGLShapeSource_Private.h"
#import "MGLMapView_Private.h"
#import "MGLSource_Private.h"
#import "MGLFeature_Private.h"
#import "MGLShape_Private.h"
#import "NSURL+MGLAdditions.h"
#include <mbgl/style/sources/geojson_source.hpp>
const MGLShapeSourceOption MGLShapeSourceOptionClustered = @"MGLShapeSourceOptionClustered";
const MGLShapeSourceOption MGLShapeSourceOptionClusterRadius = @"MGLShapeSourceOptionClusterRadius";
const MGLShapeSourceOption MGLShapeSourceOptionMaximumZoomLevelForClustering = @"MGLShapeSourceOptionMaximumZoomLevelForClustering";
const MGLShapeSourceOption MGLShapeSourceOptionMaximumZoomLevel = @"MGLShapeSourceOptionMaximumZoomLevel";
const MGLShapeSourceOption MGLShapeSourceOptionBuffer = @"MGLShapeSourceOptionBuffer";
const MGLShapeSourceOption MGLShapeSourceOptionSimplificationTolerance = @"MGLShapeSourceOptionSimplificationTolerance";
@interface MGLShapeSource ()
- (instancetype)initWithRawSource:(mbgl::style::GeoJSONSource *)rawSource NS_DESIGNATED_INITIALIZER;
@property (nonatomic, readwrite) NSDictionary *options;
@property (nonatomic) mbgl::style::GeoJSONSource *rawSource;
@end
@implementation MGLShapeSource {
std::unique_ptr<mbgl::style::GeoJSONSource> _pendingSource;
}
- (instancetype)initWithIdentifier:(NSString *)identifier URL:(NSURL *)url options:(NS_DICTIONARY_OF(NSString *, id) *)options {
if (self = [super initWithIdentifier:identifier]) {
auto geoJSONOptions = MGLGeoJSONOptionsFromDictionary(options);
auto source = std::make_unique<mbgl::style::GeoJSONSource>(identifier.UTF8String, geoJSONOptions);
_pendingSource = std::move(source);
self.rawSource = _pendingSource.get();
self.URL = url;
}
return self;
}
- (instancetype)initWithIdentifier:(NSString *)identifier shape:(nullable MGLShape *)shape options:(NS_DICTIONARY_OF(MGLShapeSourceOption, id) *)options {
if (self = [super initWithIdentifier:identifier]) {
auto geoJSONOptions = MGLGeoJSONOptionsFromDictionary(options);
auto source = std::make_unique<mbgl::style::GeoJSONSource>(identifier.UTF8String, geoJSONOptions);
_pendingSource = std::move(source);
self.rawSource = _pendingSource.get();
self.shape = shape;
}
return self;
}
- (instancetype)initWithRawSource:(mbgl::style::GeoJSONSource *)rawSource {
return [super initWithRawSource:rawSource];
}
- (void)addToMapView:(MGLMapView *)mapView {
if (_pendingSource == nullptr) {
[NSException raise:@"MGLRedundantSourceException"
format:@"This instance %@ was already added to %@. Adding the same source instance " \
"to the style more than once is invalid.", self, mapView.style];
}
mapView.mbglMap->addSource(std::move(_pendingSource));
}
- (void)removeFromMapView:(MGLMapView *)mapView {
auto removedSource = mapView.mbglMap->removeSource(self.identifier.UTF8String);
_pendingSource = std::move(reinterpret_cast<std::unique_ptr<mbgl::style::GeoJSONSource> &>(removedSource));
self.rawSource = _pendingSource.get();
}
- (mbgl::style::GeoJSONSource *)rawSource {
return (mbgl::style::GeoJSONSource *)super.rawSource;
}
- (void)setRawSource:(mbgl::style::GeoJSONSource *)rawSource {
super.rawSource = rawSource;
}
- (NSURL *)URL {
auto url = self.rawSource->getURL();
return url ? [NSURL URLWithString:@(url->c_str())] : nil;
}
- (void)setURL:(NSURL *)url {
if (url) {
self.rawSource->setURL(url.mgl_URLByStandardizingScheme.absoluteString.UTF8String);
_shape = nil;
} else {
self.shape = nil;
}
}
- (void)setShape:(MGLShape *)shape {
self.rawSource->setGeoJSON({ shape.geoJSONObject });
_shape = shape;
}
- (NSString *)description {
return [NSString stringWithFormat:@"<%@: %p; identifier = %@; URL = %@; shape = %@>",
NSStringFromClass([self class]), (void *)self, self.identifier, self.URL, self.shape];
}
@end
mbgl::style::GeoJSONOptions MGLGeoJSONOptionsFromDictionary(NS_DICTIONARY_OF(MGLShapeSourceOption, id) *options) {
auto geoJSONOptions = mbgl::style::GeoJSONOptions();
if (NSNumber *value = options[MGLShapeSourceOptionMaximumZoomLevel]) {
if (![value isKindOfClass:[NSNumber class]]) {
[NSException raise:NSInvalidArgumentException
format:@"MGLShapeSourceOptionMaximumZoomLevel must be an NSNumber."];
}
geoJSONOptions.maxzoom = value.integerValue;
}
if (NSNumber *value = options[MGLShapeSourceOptionBuffer]) {
if (![value isKindOfClass:[NSNumber class]]) {
[NSException raise:NSInvalidArgumentException
format:@"MGLShapeSourceOptionBuffer must be an NSNumber."];
}
geoJSONOptions.buffer = value.integerValue;
}
if (NSNumber *value = options[MGLShapeSourceOptionSimplificationTolerance]) {
if (![value isKindOfClass:[NSNumber class]]) {
[NSException raise:NSInvalidArgumentException
format:@"MGLShapeSourceOptionSimplificationTolerance must be an NSNumber."];
}
geoJSONOptions.tolerance = value.doubleValue;
}
if (NSNumber *value = options[MGLShapeSourceOptionClusterRadius]) {
if (![value isKindOfClass:[NSNumber class]]) {
[NSException raise:NSInvalidArgumentException
format:@"MGLShapeSourceOptionClusterRadius must be an NSNumber."];
}
geoJSONOptions.clusterRadius = value.integerValue;
}
if (NSNumber *value = options[MGLShapeSourceOptionMaximumZoomLevelForClustering]) {
if (![value isKindOfClass:[NSNumber class]]) {
[NSException raise:NSInvalidArgumentException
format:@"MGLShapeSourceOptionMaximumZoomLevelForClustering must be an NSNumber."];
}
geoJSONOptions.clusterMaxZoom = value.integerValue;
}
if (NSNumber *value = options[MGLShapeSourceOptionClustered]) {
if (![value isKindOfClass:[NSNumber class]]) {
[NSException raise:NSInvalidArgumentException
format:@"MGLShapeSourceOptionClustered must be an NSNumber."];
}
geoJSONOptions.cluster = value.boolValue;
}
return geoJSONOptions;
}

View File

@@ -0,0 +1,21 @@
#import "MGLShapeSource.h"
#import "MGLShapeSource_Private.h"
NS_ASSUME_NONNULL_BEGIN
namespace mbgl {
namespace style {
class GeoJSONOptions;
struct GeoJSONSource;
}
}
@interface MGLShapeSource (Private)
- (instancetype)initWithRawSource:(mbgl::style::GeoJSONSource *)rawSource;
@end
mbgl::style::GeoJSONOptions MGLGeoJSONOptionsFromDictionary(NS_DICTIONARY_OF(MGLShapeSourceOption, id) *options);
NS_ASSUME_NONNULL_END

View File

@@ -1,13 +1,19 @@
#import "MGLShape.h"
#import <mbgl/util/feature.hpp>
#import <mbgl/util/geojson.hpp>
#import <mbgl/util/geometry.hpp>
@interface MGLShape (Private)
/**
Returns an `mbgl::Feature` representation of the `MGLShape`.
Returns an `mbgl::GeoJSON` representation of the `MGLShape`.
*/
- (mbgl::Feature)featureObject;
- (mbgl::GeoJSON)geoJSONObject;
/**
Returns an `mbgl::Geometry<double>` representation of the `MGLShape`.
*/
- (mbgl::Geometry<double>)geometryObject;
/**
Returns a dictionary with the GeoJSON geometry member object.

View File

@@ -1,17 +1,29 @@
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
/**
A source supplies data to be shown on the map. Sources don't contain styling
details like color or width. Use subclasses of `MGLStyleLayer` to give visual
representation to sources.
`MGLSource` is an abstract base class for map content sources. A map content
source supplies content to be shown on the map. A source is added to an
`MGLStyle` object along with an `MGLForegroundStyleLayer` object. The
foreground style layer defines the appearance of any content supplied by the
source.
You should use the concrete subclasses of `MGLSource` to create vector,
raster, GeoJSON, and other source types.
Each source defined by the style JSON file is represented at runtime by an
`MGLSource` object that you can use to refine the map’s content. You can also
add and remove sources dynamically using methods such as
`-[MGLStyle addSource:]` and `-[MGLStyle sourceWithIdentifier:]`.
Do not create instances of this class directly, and do not create your own
subclasses of this class. Instead, create instances of `MGLShapeSource` and the
concrete subclasses of `MGLTileSource`.
*/
@interface MGLSource : NSObject
#pragma mark Initializing a Source
- (instancetype)init __attribute__((unavailable("Use -initWithIdentifier: instead.")));
/**
Returns a source initialized with an identifier.
@@ -32,3 +44,5 @@
@property (nonatomic, copy) NSString *identifier;
@end
NS_ASSUME_NONNULL_END

View File

@@ -20,6 +20,14 @@
return self;
}
- (instancetype)initWithRawSource:(mbgl::style::Source *)rawSource {
NSString *identifier = @(rawSource->getID().c_str());
if (self = [self initWithIdentifier:identifier]) {
_rawSource = rawSource;
}
return self;
}
- (void)addToMapView:(MGLMapView *)mapView {
[NSException raise:NSInvalidArgumentException format:
@"The source %@ cannot be added to the style. "

View File

@@ -1,11 +1,22 @@
#import "MGLSource.h"
#include <mbgl/style/source.hpp>
NS_ASSUME_NONNULL_BEGIN
namespace mbgl {
namespace style {
class Source;
}
}
@class MGLMapView;
@interface MGLSource (Private)
/**
Initializes and returns a source with a raw pointer to the backing store.
*/
- (instancetype)initWithRawSource:(mbgl::style::Source *)rawSource;
/**
A raw pointer to the mbgl object, which is always initialized, either to the
value returned by `mbgl::Map getSource`, or for independently created objects,
@@ -37,3 +48,5 @@
- (void)removeFromMapView:(MGLMapView *)mapView;
@end
NS_ASSUME_NONNULL_END

View File

@@ -30,14 +30,24 @@ NS_ASSUME_NONNULL_BEGIN
static const NSInteger MGLStyleDefaultVersion = 9;
/**
The proxy object for the current map style for customization purposes and a
set of convenience methods for creating style URLs of default styles provided
by Mapbox.
The proxy object for the current map style.
MGLStyle provides a set of convenience methods for changing Mapbox
default styles using `-[MGLMapView styleURL]`.
<a href="https://www.mapbox.com/maps/">Learn more about Mapbox default styles</a>.
It is also possible to directly manipulate the current map style
via `-[MGLMapView style]` by updating the style's data sources or layers.
@note Wait until the map style has finished loading before modifying a map's
style via any of the MGLStyle instance methods below.
You can use the `MGLMapViewDelegate` methods `-mapViewDidFinishLoadingMap:`
or `-mapView:didFinishLoadingStyle:` as indicators that it's safe
to modify the map's style.
*/
@interface MGLStyle : NSObject
#pragma mark Accessing Common Styles
#pragma mark Accessing Default Styles
/**
Returns the URL to version 8 of the
@@ -199,11 +209,11 @@ static const NSInteger MGLStyleDefaultVersion = 9;
/**
Adds a new source to the current style.
@note Adding the same source instance more than once will result in a
@note Adding the same source instance more than once will result in a
`MGLRedundantSourceException`. Reusing the same source identifier, even with
different source instances, will result in a
`MGLRedundantSourceIdentiferException`.
`MGLRedundantSourceIdentifierException`.
@param source The source to add to the current style.
*/
@@ -251,7 +261,7 @@ static const NSInteger MGLStyleDefaultVersion = 9;
/**
Adds a new layer on top of existing layers.
@note Adding the same layer instance more than once will result in a
`MGLRedundantLayerException`. Reusing the same layer identifer, even with
different layer instances, will also result in an exception.
@@ -371,11 +381,29 @@ static const NSInteger MGLStyleDefaultVersion = 9;
#pragma mark Managing a Style’s Images
/**
Returns the image associated with the given name in the style.
@note Names and their associated images are not guaranteed to exist across
styles or different versions of the same style. Applications that use this
API must first set the style URL to an explicitly versioned style using a
convenience method like `+[MGLStyle outdoorsStyleURLWithVersion:]`,
`MGLMapView`'s “Style URL” inspectable in Interface Builder, or a manually
constructed `NSURL`. This approach also avoids image name changes that will
occur in the default style over time.
@param name The name associated with the image you want to obtain.
@return The image associated with the given name, or `nil` if no image is
associated with that name.
*/
- (nullable MGLImage *)imageForName:(NSString *)name;
/**
Adds or overrides an image used by the style’s layers.
To use an image in a style layer, give it a unique name using this method, then
set the `iconImage` property of an `MGLSymbolStyleLayer` object to that name.
set the `iconImageName` property of an `MGLSymbolStyleLayer` object to that
name.
@param image The image for the name.
@param name The name of the image to set to the style.

View File

@@ -1,4 +1,4 @@
#import "MGLStyle.h"
#import "MGLStyle_Private.h"
#import "MGLMapView_Private.h"
#import "MGLStyleLayer.h"
@@ -8,6 +8,7 @@
#import "MGLSymbolStyleLayer.h"
#import "MGLRasterStyleLayer.h"
#import "MGLBackgroundStyleLayer.h"
#import "MGLOpenGLStyleLayer.h"
#import "MGLStyle_Private.h"
#import "MGLStyleLayer_Private.h"
@@ -16,9 +17,12 @@
#import "NSDate+MGLAdditions.h"
#import "MGLSource.h"
#import "MGLTileSource_Private.h"
#import "MGLVectorSource.h"
#import "MGLRasterSource.h"
#import "MGLGeoJSONSource.h"
#import "MGLShapeSource.h"
#import "MGLAttributionInfo_Private.h"
#include <mbgl/util/default_styles.hpp>
#include <mbgl/sprite/sprite_image.hpp>
@@ -28,6 +32,7 @@
#include <mbgl/style/layers/raster_layer.hpp>
#include <mbgl/style/layers/circle_layer.hpp>
#include <mbgl/style/layers/background_layer.hpp>
#include <mbgl/style/layers/custom_layer.hpp>
#include <mbgl/style/sources/geojson_source.hpp>
#include <mbgl/style/sources/vector_source.hpp>
#include <mbgl/style/sources/raster_source.hpp>
@@ -42,6 +47,7 @@
@property (nonatomic, readwrite, weak) MGLMapView *mapView;
@property (readonly, copy, nullable) NSURL *URL;
@property (nonatomic, readwrite, strong) NS_MUTABLE_DICTIONARY_OF(NSString *, MGLOpenGLStyleLayer *) *openGLLayers;
@end
@@ -108,6 +114,7 @@ static NSURL *MGLStyleURL_emerald;
- (instancetype)initWithMapView:(MGLMapView *)mapView {
if (self = [super init]) {
_mapView = mapView;
_openGLLayers = [NSMutableDictionary dictionary];
}
return self;
}
@@ -157,25 +164,18 @@ static NSURL *MGLStyleURL_emerald;
return rawSource ? [self sourceFromMBGLSource:rawSource] : nil;
}
- (MGLSource *)sourceFromMBGLSource:(mbgl::style::Source *)mbglSource {
NSString *identifier = @(mbglSource->getID().c_str());
- (MGLSource *)sourceFromMBGLSource:(mbgl::style::Source *)source {
// TODO: Fill in options specific to the respective source classes
// https://github.com/mapbox/mapbox-gl-native/issues/6584
MGLSource *source;
if (mbglSource->is<mbgl::style::VectorSource>()) {
source = [[MGLVectorSource alloc] initWithIdentifier:identifier];
} else if (mbglSource->is<mbgl::style::GeoJSONSource>()) {
source = [[MGLGeoJSONSource alloc] initWithIdentifier:identifier];
} else if (mbglSource->is<mbgl::style::RasterSource>()) {
source = [[MGLRasterSource alloc] initWithIdentifier:identifier];
if (auto vectorSource = source->as<mbgl::style::VectorSource>()) {
return [[MGLVectorSource alloc] initWithRawSource:vectorSource];
} else if (auto geoJSONSource = source->as<mbgl::style::GeoJSONSource>()) {
return [[MGLShapeSource alloc] initWithRawSource:geoJSONSource];
} else if (auto rasterSource = source->as<mbgl::style::RasterSource>()) {
return [[MGLRasterSource alloc] initWithRawSource:rasterSource];
} else {
source = [[MGLSource alloc] initWithIdentifier:identifier];
return [[MGLSource alloc] initWithRawSource:source];
}
source.rawSource = mbglSource;
return source;
}
- (void)addSource:(MGLSource *)source
@@ -190,7 +190,7 @@ static NSURL *MGLStyleURL_emerald;
try {
[source addToMapView:self.mapView];
} catch (std::runtime_error & err) {
[NSException raise:@"MGLRedundantSourceIdentiferException" format:@"%s", err.what()];
[NSException raise:@"MGLRedundantSourceIdentifierException" format:@"%s", err.what()];
}
}
@@ -205,6 +205,24 @@ static NSURL *MGLStyleURL_emerald;
[source removeFromMapView:self.mapView];
}
- (nullable NS_ARRAY_OF(MGLAttributionInfo *) *)attributionInfosWithFontSize:(CGFloat)fontSize linkColor:(nullable MGLColor *)linkColor {
// It’d be incredibly convenient to use -sources here, but this operation
// depends on the sources being sorted in ascending order by creation, as
// with the std::vector used in mbgl.
auto rawSources = self.mapView.mbglMap->getSources();
NSMutableArray *infos = [NSMutableArray arrayWithCapacity:rawSources.size()];
for (auto rawSource = rawSources.begin(); rawSource != rawSources.end(); ++rawSource) {
MGLTileSource *source = (MGLTileSource *)[self sourceFromMBGLSource:*rawSource];
if (![source isKindOfClass:[MGLTileSource class]]) {
continue;
}
NSArray *tileSetInfos = [source attributionInfosWithFontSize:fontSize linkColor:linkColor];
[infos growArrayByAddingAttributionInfosFromArray:tileSetInfos];
}
return infos;
}
#pragma mark Style layers
- (NS_MUTABLE_ARRAY_OF(MGLStyleLayer *) *)layers
@@ -272,7 +290,7 @@ static NSURL *MGLStyleURL_emerald;
format:@"Cannot insert style layer at out-of-bounds index %lu.", (unsigned long)index];
} else if (index == 0) {
try {
[styleLayer addToMapView:self.mapView];
[styleLayer addToMapView:self.mapView belowLayer:nil];
} catch (const std::runtime_error & err) {
[NSException raise:@"MGLRedundantLayerIdentifierException" format:@"%s", err.what()];
}
@@ -294,7 +312,8 @@ static NSURL *MGLStyleURL_emerald;
format:@"Cannot remove style layer at out-of-bounds index %lu.", (unsigned long)index];
}
auto layer = layers.at(layers.size() - 1 - index);
self.mapView.mbglMap->removeLayer(layer->getID());
MGLStyleLayer *styleLayer = [self layerFromMBGLLayer:layer];
[styleLayer removeFromMapView:self.mapView];
}
- (MGLStyleLayer *)layerFromMBGLLayer:(mbgl::style::Layer *)mbglLayer
@@ -318,8 +337,15 @@ static NSURL *MGLStyleURL_emerald;
} else if (auto circleLayer = mbglLayer->as<mbgl::style::CircleLayer>()) {
MGLSource *source = [self sourceWithIdentifier:@(circleLayer->getSourceID().c_str())];
styleLayer = [[MGLCircleStyleLayer alloc] initWithIdentifier:identifier source:source];
} else if (mbglLayer->as<mbgl::style::BackgroundLayer>()) {
} else if (mbglLayer->is<mbgl::style::BackgroundLayer>()) {
styleLayer = [[MGLBackgroundStyleLayer alloc] initWithIdentifier:identifier];
} else if (auto customLayer = mbglLayer->as<mbgl::style::CustomLayer>()) {
styleLayer = self.openGLLayers[identifier];
if (styleLayer) {
NSAssert(styleLayer.rawLayer == customLayer, @"%@ wraps a CustomLayer that differs from the one associated with the underlying style.", styleLayer);
return styleLayer;
}
styleLayer = [[MGLOpenGLStyleLayer alloc] initWithIdentifier:identifier];
} else {
NSAssert(NO, @"Unrecognized layer type");
return nil;
@@ -359,7 +385,7 @@ static NSURL *MGLStyleURL_emerald;
}
[self willChangeValueForKey:@"layers"];
try {
[layer addToMapView:self.mapView];
[layer addToMapView:self.mapView belowLayer:nil];
} catch (std::runtime_error & err) {
[NSException raise:@"MGLRedundantLayerIdentifierException" format:@"%s", err.what()];
}
@@ -430,7 +456,7 @@ static NSURL *MGLStyleURL_emerald;
sibling];
} else if (index + 1 == layers.size()) {
try {
[layer addToMapView:self.mapView];
[layer addToMapView:self.mapView belowLayer:nil];
} catch (std::runtime_error & err) {
[NSException raise:@"MGLRedundantLayerIdentifierException" format:@"%s", err.what()];
}
@@ -509,19 +535,39 @@ static NSURL *MGLStyleURL_emerald;
- (void)setImage:(MGLImage *)image forName:(NSString *)name
{
NSAssert(image, @"image is null");
NSAssert(name, @"name is null");
if (!image) {
[NSException raise:NSInvalidArgumentException
format:@"Cannot assign nil image to “%@”.", name];
}
if (!name) {
[NSException raise:NSInvalidArgumentException
format:@"Cannot assign image %@ to a nil name.", image];
}
self.mapView.mbglMap->addImage([name UTF8String], image.mgl_spriteImage);
}
- (void)removeImageForName:(NSString *)name
{
NSAssert(name, @"name is null");
if (!name) {
[NSException raise:NSInvalidArgumentException
format:@"Cannot remove image with nil name."];
}
self.mapView.mbglMap->removeImage([name UTF8String]);
}
- (MGLImage *)imageForName:(NSString *)name
{
if (!name) {
[NSException raise:NSInvalidArgumentException
format:@"Cannot get image with nil name."];
}
auto spriteImage = self.mapView.mbglMap->getImage([name UTF8String]);
return spriteImage ? [[MGLImage alloc] initWithMGLSpriteImage:spriteImage] : nil;
}
- (NSString *)description
{
return [NSString stringWithFormat:@"<%@: %p; name = %@, URL = %@>",

View File

@@ -90,10 +90,18 @@ typedef NS_ENUM(NSUInteger, MGL<%- camelize(property.name) %>) {
<% } if (property.requires) { -%>
<%- propertyReqs(property, layoutPropertiesByName, type) %>
<% } -%>
<% if (property.original) { -%>
This attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-<%- type -%>-<%- property.original -%>"><code><%- property.original -%></code></a> layout property in the Mapbox Style Specification.
<% } -%>
*/
@property (nonatomic<% if (!property.required) { %>, null_resettable<% } %>) MGLStyleValue<<%- propertyType(property, true) %>> *<%- camelizeWithLeadingLowercase(property.name) %>;
@property (nonatomic<% if (!property.required) { %>, null_resettable<% } if (property.getter) { %>, getter=<%- objCGetter(property) -%><% } %>) MGLStyleValue<<%- propertyType(property, true) %>> *<%- camelizeWithLeadingLowercase(property.name) %>;
<% if (property.original) { %>
@property (nonatomic<% if (!property.required) { %>, null_resettable<% } %>) MGLStyleValue<<%- propertyType(property, true) %>> *<%- camelizeWithLeadingLowercase(originalPropertyName(property)) %> __attribute__((unavailable("Use <%- camelizeWithLeadingLowercase(property.name) %> instead.")));
<% } -%>
<% } -%>
<% } -%>
<% if (paintProperties.length) { -%>
@@ -108,10 +116,18 @@ typedef NS_ENUM(NSUInteger, MGL<%- camelize(property.name) %>) {
<% } if (property.requires) { -%>
<%- propertyReqs(property, paintPropertiesByName, type) %>
<% } -%>
<% if (property.original) { -%>
This attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-<%- property.original -%>"><code><%- property.original -%></code></a> paint property in the Mapbox Style Specification.
<% } -%>
*/
@property (nonatomic<% if (!property.required) { %>, null_resettable<% } %>) MGLStyleValue<<%- propertyType(property, true) %>> *<%- camelizeWithLeadingLowercase(property.name) %>;
@property (nonatomic<% if (!property.required) { %>, null_resettable<% } if (property.getter) { %>, getter=<%- objCGetter(property) -%><% } %>) MGLStyleValue<<%- propertyType(property, true) %>> *<%- camelizeWithLeadingLowercase(property.name) %>;
<% if (property.original) { %>
@property (nonatomic<% if (!property.required) { %>, null_resettable<% } %>) MGLStyleValue<<%- propertyType(property, true) %>> *<%- camelizeWithLeadingLowercase(originalPropertyName(property)) %> __attribute__((unavailable("Use <%- camelizeWithLeadingLowercase(property.name) %> instead.")));
<% } -%>
<% } -%>
<% } -%>
@end

View File

@@ -3,6 +3,12 @@
#include <mbgl/style/layer.hpp>
@interface MGLStyleLayer ()
@property (nonatomic) mbgl::style::Layer *rawLayer;
@end
@implementation MGLStyleLayer
- (instancetype)initWithIdentifier:(NSString *)identifier

View File

@@ -21,9 +21,9 @@ namespace mbgl {
<% if (layoutProperties.length) { -%>
<% for (const property of layoutProperties) { -%>
<% if (property.type == "enum") { -%>
MBGL_DEFINE_ENUM(MGL<%- camelize(originalPropertyName(property)) %>, {
MBGL_DEFINE_ENUM(MGL<%- camelize(property.name) %>, {
<% for (const value in property.values) { -%>
{ MGL<%- camelize(originalPropertyName(property)) %><%- camelize(value) %>, "<%-value%>" },
{ MGL<%- camelize(property.name) %><%- camelize(value) %>, "<%-value%>" },
<% } -%>
});
@@ -33,9 +33,9 @@ namespace mbgl {
<% if (paintProperties.length) { -%>
<% for (const property of paintProperties) { -%>
<% if (property.type == "enum") { -%>
MBGL_DEFINE_ENUM(MGL<%- camelize(originalPropertyName(property)) %>, {
MBGL_DEFINE_ENUM(MGL<%- camelize(property.name) %>, {
<% for (const value in property.values) { -%>
{ MGL<%- camelize(originalPropertyName(property)) %><%- camelize(value) %>, "<%-value%>" },
{ MGL<%- camelize(property.name) %><%- camelize(value) %>, "<%-value%>" },
<% } -%>
});
@@ -62,7 +62,7 @@ namespace mbgl {
if (self = [super initWithIdentifier:identifier]) {
auto layer = std::make_unique<mbgl::style::<%- camelize(type) %>Layer>(identifier.UTF8String);
_pendingLayer = std::move(layer);
_rawLayer = _pendingLayer.get();
self.rawLayer = _pendingLayer.get();
}
return self;
}
@@ -73,17 +73,28 @@ namespace mbgl {
if (self = [super initWithIdentifier:identifier source:source]) {
auto layer = std::make_unique<mbgl::style::<%- camelize(type) %>Layer>(identifier.UTF8String, source.identifier.UTF8String);
_pendingLayer = std::move(layer);
_rawLayer = _pendingLayer.get();
self.rawLayer = _pendingLayer.get();
}
return self;
}
<% } -%>
- (mbgl::style::<%- camelize(type) %>Layer *)rawLayer
{
return (mbgl::style::<%- camelize(type) %>Layer *)super.rawLayer;
}
- (void)setRawLayer:(mbgl::style::<%- camelize(type) %>Layer *)rawLayer
{
super.rawLayer = rawLayer;
}
<% if (type !== 'background' && type !== 'raster') { -%>
- (NSString *)sourceLayerIdentifier
{
MGLAssertStyleLayerIsValid();
auto layerID = _rawLayer->getSourceLayer();
auto layerID = self.rawLayer->getSourceLayer();
return layerID.empty() ? nil : @(layerID.c_str());
}
@@ -91,26 +102,27 @@ namespace mbgl {
{
MGLAssertStyleLayerIsValid();
_rawLayer->setSourceLayer(sourceLayerIdentifier.UTF8String ?: "");
self.rawLayer->setSourceLayer(sourceLayerIdentifier.UTF8String ?: "");
}
- (void)setPredicate:(NSPredicate *)predicate
{
MGLAssertStyleLayerIsValid();
_rawLayer->setFilter(predicate.mgl_filter);
self.rawLayer->setFilter(predicate.mgl_filter);
}
- (NSPredicate *)predicate
{
MGLAssertStyleLayerIsValid();
return [NSPredicate mgl_predicateWithFilter:_rawLayer->getFilter()];
return [NSPredicate mgl_predicateWithFilter:self.rawLayer->getFilter()];
}
<% } -%>
#pragma mark - Adding to and removing from a map view
- (void)addToMapView:(MGLMapView *)mapView
<% } -%>
#pragma mark - Adding to and removing from a map view
- (void)addToMapView:(MGLMapView *)mapView belowLayer:(MGLStyleLayer *)otherLayer
{
if (_pendingLayer == nullptr) {
[NSException raise:@"MGLRedundantLayerException"
@@ -118,11 +130,6 @@ namespace mbgl {
"to the style more than once is invalid.", self, mapView.style];
}
[self addToMapView:mapView belowLayer:nil];
}
- (void)addToMapView:(MGLMapView *)mapView belowLayer:(MGLStyleLayer *)otherLayer
{
if (otherLayer) {
const mbgl::optional<std::string> belowLayerId{otherLayer.identifier.UTF8String};
mapView.mbglMap->addLayer(std::move(_pendingLayer), belowLayerId);
@@ -134,7 +141,7 @@ namespace mbgl {
- (void)removeFromMapView:(MGLMapView *)mapView
{
_pendingLayer = nullptr;
_rawLayer = nullptr;
self.rawLayer = nullptr;
auto removedLayer = mapView.mbglMap->removeLayer(self.identifier.UTF8String);
if (!removedLayer) {
@@ -149,7 +156,7 @@ namespace mbgl {
removedLayer.release();
_pendingLayer = std::unique_ptr<mbgl::style::<%- camelize(type) %>Layer>(layer);
_rawLayer = _pendingLayer.get();
self.rawLayer = _pendingLayer.get();
}
<% if (layoutProperties.length) { -%>
@@ -160,25 +167,35 @@ namespace mbgl {
MGLAssertStyleLayerIsValid();
<% if (property.type == "enum") { -%>
auto mbglValue = MGLStyleValueTransformer<mbgl::style::<%- mbglType(property) %>, NSValue *, mbgl::style::<%- mbglType(property) %>, MGL<%- camelize(originalPropertyName(property)) %>>().toEnumPropertyValue(<%- objCName(property) %>);
_rawLayer->set<%- camelize(originalPropertyName(property)) %>(mbglValue);
auto mbglValue = MGLStyleValueTransformer<mbgl::style::<%- mbglType(property) %>, NSValue *, mbgl::style::<%- mbglType(property) %>, MGL<%- camelize(property.name) %>>().toEnumPropertyValue(<%- objCName(property) %>);
self.rawLayer->set<%- camelize(originalPropertyName(property)) %>(mbglValue);
<% } else { -%>
auto mbglValue = MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toPropertyValue(<%- objCName(property) %>);
_rawLayer->set<%- camelize(originalPropertyName(property)) %>(mbglValue);
self.rawLayer->set<%- camelize(originalPropertyName(property)) %>(mbglValue);
<% } -%>
}
- (MGLStyleValue<<%- propertyType(property, true) %>> *)<%- objCName(property) %> {
- (MGLStyleValue<<%- propertyType(property, true) %>> *)<%- objCGetter(property) %> {
MGLAssertStyleLayerIsValid();
auto propertyValue = _rawLayer->get<%- camelize(originalPropertyName(property)) %>() ?: _rawLayer->getDefault<%- camelize(originalPropertyName(property)) %>();
auto propertyValue = self.rawLayer->get<%- camelize(originalPropertyName(property)) %>() ?: self.rawLayer->getDefault<%- camelize(originalPropertyName(property)) %>();
<% if (property.type == "enum") { -%>
return MGLStyleValueTransformer<mbgl::style::<%- mbglType(property) %>, NSValue *, mbgl::style::<%- mbglType(property) %>, MGL<%- camelize(originalPropertyName(property)) %>>().toEnumStyleValue(propertyValue);
return MGLStyleValueTransformer<mbgl::style::<%- mbglType(property) %>, NSValue *, mbgl::style::<%- mbglType(property) %>, MGL<%- camelize(property.name) %>>().toEnumStyleValue(propertyValue);
<% } else { -%>
return MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toStyleValue(propertyValue);
<% } -%>
}
<% if (property.original) { %>
- (void)set<%- camelize(originalPropertyName(property)) %>:(MGLStyleValue<<%- propertyType(property, true) %>> *)<%- camelizeWithLeadingLowercase(originalPropertyName(property)) %> {
self.<%- camelizeWithLeadingLowercase(property.name) %> = <%- camelizeWithLeadingLowercase(originalPropertyName(property)) %>;
}
- (MGLStyleValue<<%- propertyType(property, true) %>> *)<%- camelizeWithLeadingLowercase(originalPropertyName(property)) %> {
return self.<%- objCGetter(property) %>;
}
<% } -%>
<% } -%>
<% } -%>
<% if (paintProperties.length) { -%>
@@ -189,25 +206,31 @@ namespace mbgl {
MGLAssertStyleLayerIsValid();
<% if (property.type == "enum") { -%>
auto mbglValue = MGLStyleValueTransformer<mbgl::style::<%- mbglType(property) %>, NSValue *, mbgl::style::<%- mbglType(property) %>, MGL<%- camelize(originalPropertyName(property)) %>>().toEnumPropertyValue(<%- objCName(property) %>);
_rawLayer->set<%- camelize(originalPropertyName(property)) %>(mbglValue);
auto mbglValue = MGLStyleValueTransformer<mbgl::style::<%- mbglType(property) %>, NSValue *, mbgl::style::<%- mbglType(property) %>, MGL<%- camelize(property.name) %>>().toEnumPropertyValue(<%- objCName(property) %>);
self.rawLayer->set<%- camelize(originalPropertyName(property)) %>(mbglValue);
<% } else { -%>
auto mbglValue = MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toPropertyValue(<%- objCName(property) %>);
_rawLayer->set<%- camelize(originalPropertyName(property)) %>(mbglValue);
self.rawLayer->set<%- camelize(originalPropertyName(property)) %>(mbglValue);
<% } -%>
}
- (MGLStyleValue<<%- propertyType(property, true) %>> *)<%- objCName(property) %> {
- (MGLStyleValue<<%- propertyType(property, true) %>> *)<%- objCGetter(property) %> {
MGLAssertStyleLayerIsValid();
auto propertyValue = _rawLayer->get<%- camelize(originalPropertyName(property)) %>() ?: _rawLayer->getDefault<%- camelize(originalPropertyName(property)) %>();
auto propertyValue = self.rawLayer->get<%- camelize(originalPropertyName(property)) %>() ?: self.rawLayer->getDefault<%- camelize(originalPropertyName(property)) %>();
<% if (property.type == "enum") { -%>
return MGLStyleValueTransformer<mbgl::style::<%- mbglType(property) %>, NSValue *, mbgl::style::<%- mbglType(property) %>, MGL<%- camelize(originalPropertyName(property)) %>>().toEnumStyleValue(propertyValue);
return MGLStyleValueTransformer<mbgl::style::<%- mbglType(property) %>, NSValue *, mbgl::style::<%- mbglType(property) %>, MGL<%- camelize(property.name) %>>().toEnumStyleValue(propertyValue);
<% } else { -%>
return MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toStyleValue(propertyValue);
<% } -%>
}
<% if (property.original) { %>
- (void)set<%- camelize(originalPropertyName(property)) %>:(MGLStyleValue<<%- propertyType(property, true) %>> *)<%- camelizeWithLeadingLowercase(originalPropertyName(property)) %> {
NSAssert(NO, @"Use -set<%- camelize(property.name) %>: instead.");
}
<% } -%>
<% } -%>
<% } -%>

View File

@@ -5,6 +5,8 @@
#include <mbgl/style/layer.hpp>
NS_ASSUME_NONNULL_BEGIN
/**
Assert that the style layer is valid.
@@ -19,7 +21,7 @@
@"-[MGLStyle removeLayer:] has been called " \
@"with this instance but another style layer instance was added with the same identifer. It is an " \
@"error to send any message to this layer since it cannot be recovered after removal due to the " \
@"identifer collision. Use unique identifiers for all layer instances including layers of " \
@"identifier collision. Use unique identifiers for all layer instances including layers of " \
@"different types."]; \
} \
} while (NO);
@@ -40,13 +42,14 @@
@property (nonatomic) mbgl::style::Layer *rawLayer;
/**
Adds the mbgl style layer that this object represents to the mbgl map.
Adds the mbgl style layer that this object represents to the mbgl map below the
specified `otherLayer`.
Once a mbgl style layer is added, ownership of the object is transferred to the
`mbgl::Map` and this object no longer has an active unique_ptr reference to the
`mbgl::style::Layer`.
*/
- (void)addToMapView:(MGLMapView *)mapView;
- (void)addToMapView:(MGLMapView *)mapView belowLayer:(nullable MGLStyleLayer *)otherLayer;
/**
Removes the mbgl style layer that this object represents from the mbgl map.
@@ -57,13 +60,6 @@
*/
- (void)removeFromMapView:(MGLMapView *)mapView;
/**
Adds the mbgl style layer that this object represents to the mbgl map below the specified `otherLayer`.
Once a mbgl style layer is added, ownership of the object is transferred to the
`mbgl::Map` and this object no longer has an active unique_ptr reference to the
`mbgl::style::Layer`.
*/
- (void)addToMapView:(MGLMapView *)mapView belowLayer:(MGLStyleLayer *)otherLayer;
@end
NS_ASSUME_NONNULL_END

View File

@@ -63,6 +63,10 @@
- (instancetype)initWithBase:(CGFloat)base stops:(NSDictionary *)stops {
if (self = [super init]) {
if (!stops.count)
{
[NSException raise:NSInvalidArgumentException format:@"%@ requires at least one stop.", self];
}
_base = base;
_stops = stops;
}

View File

@@ -2,7 +2,12 @@
#import "MGLStyleLayer.h"
#import "MGLFillStyleLayer.h"
#import <mbgl/util/default_styles.hpp>
NS_ASSUME_NONNULL_BEGIN
@class MGLAttributionInfo;
@class MGLMapView;
@class MGLOpenGLStyleLayer;
@interface MGLStyle (Private)
@@ -10,6 +15,12 @@
@property (nonatomic, readonly, weak) MGLMapView *mapView;
- (nullable NS_ARRAY_OF(MGLAttributionInfo *) *)attributionInfosWithFontSize:(CGFloat)fontSize linkColor:(nullable MGLColor *)linkColor;
@property (nonatomic, readonly, strong) NS_MUTABLE_DICTIONARY_OF(NSString *, MGLOpenGLStyleLayer *) *openGLLayers;
- (void)setStyleClasses:(NS_ARRAY_OF(NSString *) *)appliedClasses transitionDuration:(NSTimeInterval)transitionDuration;
@end
NS_ASSUME_NONNULL_END

View File

@@ -113,21 +113,21 @@ typedef NS_ENUM(NSUInteger, MGLTextAnchor) {
/**
Text justification options.
Values of this type are used in the `textJustify` property of `MGLSymbolStyleLayer`.
Values of this type are used in the `textJustification` property of `MGLSymbolStyleLayer`.
*/
typedef NS_ENUM(NSUInteger, MGLTextJustify) {
typedef NS_ENUM(NSUInteger, MGLTextJustification) {
/**
The text is aligned to the left.
*/
MGLTextJustifyLeft,
MGLTextJustificationLeft,
/**
The text is centered.
*/
MGLTextJustifyCenter,
MGLTextJustificationCenter,
/**
The text is aligned to the right.
*/
MGLTextJustifyRight,
MGLTextJustificationRight,
};
/**
@@ -237,39 +237,45 @@ typedef NS_ENUM(NSUInteger, MGLTextTranslateAnchor) {
The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing `NO`. Set this property to `nil` to reset it to the default value.
This property is only applied to the style if `iconImage` is non-`nil`. Otherwise, it is ignored.
This property is only applied to the style if `iconImageName` is non-`nil`. Otherwise, it is ignored.
This attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-icon-allow-overlap"><code>icon-allow-overlap</code></a> layout property in the Mapbox Style Specification.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *iconAllowOverlap;
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *iconAllowsOverlap;
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *iconAllowOverlap __attribute__((unavailable("Use iconAllowsOverlap instead.")));
/**
If true, other symbols can be visible even if they collide with the icon.
The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing `NO`. Set this property to `nil` to reset it to the default value.
This property is only applied to the style if `iconImage` is non-`nil`. Otherwise, it is ignored.
This property is only applied to the style if `iconImageName` is non-`nil`. Otherwise, it is ignored.
This attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-icon-ignore-placement"><code>icon-ignore-placement</code></a> layout property in the Mapbox Style Specification.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *iconIgnorePlacement;
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *iconIgnoresPlacement;
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *iconIgnorePlacement __attribute__((unavailable("Use iconIgnoresPlacement instead.")));
/**
A string with {tokens} replaced, referencing the data property to pull from.
This attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-icon-image"><code>icon-image</code></a> layout property in the Mapbox Style Specification.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSString *> *iconImageName;
/**
If true, the icon may be flipped to prevent it from being rendered upside-down.
The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing `NO`. Set this property to `nil` to reset it to the default value.
This property is only applied to the style if `iconImage` is non-`nil`, and `iconRotationAlignment` is set to an `MGLStyleValue` object containing an `NSValue` object containing `MGLIconRotationAlignmentMap`, and `symbolPlacement` is set to an `MGLStyleValue` object containing an `NSValue` object containing `MGLSymbolPlacementLine`. Otherwise, it is ignored.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *iconKeepUpright;
@property (nonatomic, null_resettable) MGLStyleValue<NSString *> *iconImage __attribute__((unavailable("Use iconImageName instead.")));
/**
Offset distance of icon from its anchor.
The default value of this property is an `MGLStyleValue` object containing an `NSValue` object containing a `CGVector` struct set to 0 from the left and 0 from the top. Set this property to `nil` to reset it to the default value.
This property is only applied to the style if `iconImage` is non-`nil`. Otherwise, it is ignored.
This property is only applied to the style if `iconImageName` is non-`nil`. Otherwise, it is ignored.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *iconOffset;
@@ -278,9 +284,9 @@ typedef NS_ENUM(NSUInteger, MGLTextTranslateAnchor) {
The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing `NO`. Set this property to `nil` to reset it to the default value.
This property is only applied to the style if `iconImage` is non-`nil`, and `textField` is non-`nil`. Otherwise, it is ignored.
This property is only applied to the style if `iconImageName` is non-`nil`, and `textField` is non-`nil`. Otherwise, it is ignored.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *iconOptional;
@property (nonatomic, null_resettable, getter=isIconOptional) MGLStyleValue<NSNumber *> *iconOptional;
/**
Size of the additional area around the icon bounding box used for detecting symbol collisions.
@@ -289,7 +295,7 @@ typedef NS_ENUM(NSUInteger, MGLTextTranslateAnchor) {
The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `2`. Set this property to `nil` to reset it to the default value.
This property is only applied to the style if `iconImage` is non-`nil`. Otherwise, it is ignored.
This property is only applied to the style if `iconImageName` is non-`nil`. Otherwise, it is ignored.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *iconPadding;
@@ -300,16 +306,21 @@ typedef NS_ENUM(NSUInteger, MGLTextTranslateAnchor) {
The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `0`. Set this property to `nil` to reset it to the default value.
This property is only applied to the style if `iconImage` is non-`nil`. Otherwise, it is ignored.
This property is only applied to the style if `iconImageName` is non-`nil`. Otherwise, it is ignored.
This attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-icon-rotate"><code>icon-rotate</code></a> layout property in the Mapbox Style Specification.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *iconRotate;
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *iconRotation;
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *iconRotate __attribute__((unavailable("Use iconRotation instead.")));
/**
In combination with `symbolPlacement`, determines the rotation behavior of icons.
The default value of this property is an `MGLStyleValue` object containing an `NSValue` object containing `MGLIconRotationAlignmentAuto`. Set this property to `nil` to reset it to the default value.
This property is only applied to the style if `iconImage` is non-`nil`. Otherwise, it is ignored.
This property is only applied to the style if `iconImageName` is non-`nil`. Otherwise, it is ignored.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *iconRotationAlignment;
@@ -318,16 +329,21 @@ typedef NS_ENUM(NSUInteger, MGLTextTranslateAnchor) {
The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `1`. Set this property to `nil` to reset it to the default value.
This property is only applied to the style if `iconImage` is non-`nil`. Otherwise, it is ignored.
This property is only applied to the style if `iconImageName` is non-`nil`. Otherwise, it is ignored.
This attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-icon-size"><code>icon-size</code></a> layout property in the Mapbox Style Specification.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *iconSize;
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *iconScale;
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *iconSize __attribute__((unavailable("Use iconScale instead.")));
/**
Scales the icon to fit around the associated text.
The default value of this property is an `MGLStyleValue` object containing an `NSValue` object containing `MGLIconTextFitNone`. Set this property to `nil` to reset it to the default value.
This property is only applied to the style if `iconImage` is non-`nil`, and `textField` is non-`nil`. Otherwise, it is ignored.
This property is only applied to the style if `iconImageName` is non-`nil`, and `textField` is non-`nil`. Otherwise, it is ignored.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *iconTextFit;
@@ -338,16 +354,81 @@ typedef NS_ENUM(NSUInteger, MGLTextTranslateAnchor) {
The default value of this property is an `MGLStyleValue` object containing an `NSValue` object containing `NSEdgeInsetsZero` or `UIEdgeInsetsZero`. Set this property to `nil` to reset it to the default value.
This property is only applied to the style if `iconImage` is non-`nil`, and `textField` is non-`nil`, and `iconTextFit` is set to an `MGLStyleValue` object containing an `NSValue` object containing `MGLIconTextFitBoth`, `MGLIconTextFitWidth`, or `MGLIconTextFitHeight`. Otherwise, it is ignored.
This property is only applied to the style if `iconImageName` is non-`nil`, and `textField` is non-`nil`, and `iconTextFit` is set to an `MGLStyleValue` object containing an `NSValue` object containing `MGLIconTextFitBoth`, `MGLIconTextFitWidth`, or `MGLIconTextFitHeight`. Otherwise, it is ignored.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *iconTextFitPadding;
/**
If true, the icon may be flipped to prevent it from being rendered upside-down.
The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing `NO`. Set this property to `nil` to reset it to the default value.
This property is only applied to the style if `iconImageName` is non-`nil`, and `iconRotationAlignment` is set to an `MGLStyleValue` object containing an `NSValue` object containing `MGLIconRotationAlignmentMap`, and `symbolPlacement` is set to an `MGLStyleValue` object containing an `NSValue` object containing `MGLSymbolPlacementLine`. Otherwise, it is ignored.
This attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-icon-keep-upright"><code>icon-keep-upright</code></a> layout property in the Mapbox Style Specification.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *keepsIconUpright;
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *iconKeepUpright __attribute__((unavailable("Use keepsIconUpright instead.")));
/**
If true, the text may be flipped vertically to prevent it from being rendered upside-down.
The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing `YES`. Set this property to `nil` to reset it to the default value.
This property is only applied to the style if `textField` is non-`nil`, and `textRotationAlignment` is set to an `MGLStyleValue` object containing an `NSValue` object containing `MGLTextRotationAlignmentMap`, and `symbolPlacement` is set to an `MGLStyleValue` object containing an `NSValue` object containing `MGLSymbolPlacementLine`. Otherwise, it is ignored.
This attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-text-keep-upright"><code>text-keep-upright</code></a> layout property in the Mapbox Style Specification.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *keepsTextUpright;
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textKeepUpright __attribute__((unavailable("Use keepsTextUpright instead.")));
/**
Maximum angle change between adjacent characters.
This property is measured in degrees.
The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `45`. Set this property to `nil` to reset it to the default value.
This property is only applied to the style if `textField` is non-`nil`, and `symbolPlacement` is set to an `MGLStyleValue` object containing an `NSValue` object containing `MGLSymbolPlacementLine`. Otherwise, it is ignored.
This attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-text-max-angle"><code>text-max-angle</code></a> layout property in the Mapbox Style Specification.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *maximumTextAngle;
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textMaxAngle __attribute__((unavailable("Use maximumTextAngle instead.")));
/**
The maximum line width for text wrapping.
This property is measured in ems.
The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `10`. Set this property to `nil` to reset it to the default value.
This property is only applied to the style if `textField` is non-`nil`. Otherwise, it is ignored.
This attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-text-max-width"><code>text-max-width</code></a> layout property in the Mapbox Style Specification.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *maximumTextWidth;
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textMaxWidth __attribute__((unavailable("Use maximumTextWidth instead.")));
/**
If true, the symbols will not cross tile edges to avoid mutual collisions. Recommended in layers that don't have enough padding in the vector tile to prevent collisions, or if it is a point symbol layer placed after a line symbol layer.
The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing `NO`. Set this property to `nil` to reset it to the default value.
This attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-symbol-avoid-edges"><code>symbol-avoid-edges</code></a> layout property in the Mapbox Style Specification.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *symbolAvoidEdges;
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *symbolAvoidsEdges;
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *symbolAvoidEdges __attribute__((unavailable("Use symbolAvoidsEdges instead.")));
/**
Label placement relative to its geometry.
@@ -373,8 +454,13 @@ typedef NS_ENUM(NSUInteger, MGLTextTranslateAnchor) {
The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing `NO`. Set this property to `nil` to reset it to the default value.
This property is only applied to the style if `textField` is non-`nil`. Otherwise, it is ignored.
This attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-text-allow-overlap"><code>text-allow-overlap</code></a> layout property in the Mapbox Style Specification.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textAllowOverlap;
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textAllowsOverlap;
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textAllowOverlap __attribute__((unavailable("Use textAllowsOverlap instead.")));
/**
Part of the text placed closest to the anchor.
@@ -407,26 +493,27 @@ typedef NS_ENUM(NSUInteger, MGLTextTranslateAnchor) {
The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing `NO`. Set this property to `nil` to reset it to the default value.
This property is only applied to the style if `textField` is non-`nil`. Otherwise, it is ignored.
This attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-text-ignore-placement"><code>text-ignore-placement</code></a> layout property in the Mapbox Style Specification.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textIgnorePlacement;
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textIgnoresPlacement;
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textIgnorePlacement __attribute__((unavailable("Use textIgnoresPlacement instead.")));
/**
Text justification options.
The default value of this property is an `MGLStyleValue` object containing an `NSValue` object containing `MGLTextJustifyCenter`. Set this property to `nil` to reset it to the default value.
The default value of this property is an `MGLStyleValue` object containing an `NSValue` object containing `MGLTextJustificationCenter`. Set this property to `nil` to reset it to the default value.
This property is only applied to the style if `textField` is non-`nil`. Otherwise, it is ignored.
This attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-text-justify"><code>text-justify</code></a> layout property in the Mapbox Style Specification.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *textJustify;
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *textJustification;
/**
If true, the text may be flipped vertically to prevent it from being rendered upside-down.
The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing `YES`. Set this property to `nil` to reset it to the default value.
This property is only applied to the style if `textField` is non-`nil`, and `textRotationAlignment` is set to an `MGLStyleValue` object containing an `NSValue` object containing `MGLTextRotationAlignmentMap`, and `symbolPlacement` is set to an `MGLStyleValue` object containing an `NSValue` object containing `MGLSymbolPlacementLine`. Otherwise, it is ignored.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textKeepUpright;
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *textJustify __attribute__((unavailable("Use textJustification instead.")));
/**
Text tracking amount.
@@ -450,28 +537,6 @@ typedef NS_ENUM(NSUInteger, MGLTextTranslateAnchor) {
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textLineHeight;
/**
Maximum angle change between adjacent characters.
This property is measured in degrees.
The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `45`. Set this property to `nil` to reset it to the default value.
This property is only applied to the style if `textField` is non-`nil`, and `symbolPlacement` is set to an `MGLStyleValue` object containing an `NSValue` object containing `MGLSymbolPlacementLine`. Otherwise, it is ignored.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textMaxAngle;
/**
The maximum line width for text wrapping.
This property is measured in ems.
The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `10`. Set this property to `nil` to reset it to the default value.
This property is only applied to the style if `textField` is non-`nil`. Otherwise, it is ignored.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textMaxWidth;
/**
Offset distance of text from its anchor.
@@ -488,9 +553,9 @@ typedef NS_ENUM(NSUInteger, MGLTextTranslateAnchor) {
The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing `NO`. Set this property to `nil` to reset it to the default value.
This property is only applied to the style if `textField` is non-`nil`, and `iconImage` is non-`nil`. Otherwise, it is ignored.
This property is only applied to the style if `textField` is non-`nil`, and `iconImageName` is non-`nil`. Otherwise, it is ignored.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textOptional;
@property (nonatomic, null_resettable, getter=isTextOptional) MGLStyleValue<NSNumber *> *textOptional;
/**
Size of the additional area around the text bounding box used for detecting symbol collisions.
@@ -520,8 +585,13 @@ typedef NS_ENUM(NSUInteger, MGLTextTranslateAnchor) {
The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `0`. Set this property to `nil` to reset it to the default value.
This property is only applied to the style if `textField` is non-`nil`. Otherwise, it is ignored.
This attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-text-rotate"><code>text-rotate</code></a> layout property in the Mapbox Style Specification.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textRotate;
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textRotation;
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textRotate __attribute__((unavailable("Use textRotation instead.")));
/**
In combination with `symbolPlacement`, determines the rotation behavior of the individual glyphs forming the text.
@@ -556,20 +626,20 @@ typedef NS_ENUM(NSUInteger, MGLTextTranslateAnchor) {
#if TARGET_OS_IPHONE
/**
The color of the icon. This can only be used with sdf icons.
The tint color to apply to the icon. The `iconImageName` property must be set to a template image.
The default value of this property is an `MGLStyleValue` object containing `UIColor.blackColor`. Set this property to `nil` to reset it to the default value.
This property is only applied to the style if `iconImage` is non-`nil`. Otherwise, it is ignored.
This property is only applied to the style if `iconImageName` is non-`nil`. Otherwise, it is ignored.
*/
@property (nonatomic, null_resettable) MGLStyleValue<MGLColor *> *iconColor;
#else
/**
The color of the icon. This can only be used with sdf icons.
The tint color to apply to the icon. The `iconImageName` property must be set to a template image.
The default value of this property is an `MGLStyleValue` object containing `NSColor.blackColor`. Set this property to `nil` to reset it to the default value.
This property is only applied to the style if `iconImage` is non-`nil`. Otherwise, it is ignored.
This property is only applied to the style if `iconImageName` is non-`nil`. Otherwise, it is ignored.
*/
@property (nonatomic, null_resettable) MGLStyleValue<MGLColor *> *iconColor;
#endif
@@ -581,26 +651,26 @@ typedef NS_ENUM(NSUInteger, MGLTextTranslateAnchor) {
The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `0`. Set this property to `nil` to reset it to the default value.
This property is only applied to the style if `iconImage` is non-`nil`. Otherwise, it is ignored.
This property is only applied to the style if `iconImageName` is non-`nil`. Otherwise, it is ignored.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *iconHaloBlur;
#if TARGET_OS_IPHONE
/**
The color of the icon's halo. Icon halos can only be used with SDF icons.
The color of the icon’s halo. The `iconImageName` property must be set to a template image.
The default value of this property is an `MGLStyleValue` object containing `UIColor.clearColor`. Set this property to `nil` to reset it to the default value.
This property is only applied to the style if `iconImage` is non-`nil`. Otherwise, it is ignored.
This property is only applied to the style if `iconImageName` is non-`nil`. Otherwise, it is ignored.
*/
@property (nonatomic, null_resettable) MGLStyleValue<MGLColor *> *iconHaloColor;
#else
/**
The color of the icon's halo. Icon halos can only be used with SDF icons.
The color of the icon’s halo. The `iconImageName` property must be set to a template image.
The default value of this property is an `MGLStyleValue` object containing `NSColor.clearColor`. Set this property to `nil` to reset it to the default value.
This property is only applied to the style if `iconImage` is non-`nil`. Otherwise, it is ignored.
This property is only applied to the style if `iconImageName` is non-`nil`. Otherwise, it is ignored.
*/
@property (nonatomic, null_resettable) MGLStyleValue<MGLColor *> *iconHaloColor;
#endif
@@ -612,7 +682,7 @@ typedef NS_ENUM(NSUInteger, MGLTextTranslateAnchor) {
The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `0`. Set this property to `nil` to reset it to the default value.
This property is only applied to the style if `iconImage` is non-`nil`. Otherwise, it is ignored.
This property is only applied to the style if `iconImageName` is non-`nil`. Otherwise, it is ignored.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *iconHaloWidth;
@@ -621,7 +691,7 @@ typedef NS_ENUM(NSUInteger, MGLTextTranslateAnchor) {
The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `1`. Set this property to `nil` to reset it to the default value.
This property is only applied to the style if `iconImage` is non-`nil`. Otherwise, it is ignored.
This property is only applied to the style if `iconImageName` is non-`nil`. Otherwise, it is ignored.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *iconOpacity;
@@ -632,7 +702,7 @@ typedef NS_ENUM(NSUInteger, MGLTextTranslateAnchor) {
The default value of this property is an `MGLStyleValue` object containing an `NSValue` object containing a `CGVector` struct set to 0 points from the left and 0 points from the top. Set this property to `nil` to reset it to the default value.
This property is only applied to the style if `iconImage` is non-`nil`. Otherwise, it is ignored.
This property is only applied to the style if `iconImageName` is non-`nil`. Otherwise, it is ignored.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *iconTranslate;
@@ -641,7 +711,7 @@ typedef NS_ENUM(NSUInteger, MGLTextTranslateAnchor) {
The default value of this property is an `MGLStyleValue` object containing an `NSValue` object containing `MGLIconTranslateAnchorMap`. Set this property to `nil` to reset it to the default value.
This property is only applied to the style if `iconImage` is non-`nil`, and `iconTranslate` is non-`nil`. Otherwise, it is ignored.
This property is only applied to the style if `iconImageName` is non-`nil`, and `iconTranslate` is non-`nil`. Otherwise, it is ignored.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *iconTranslateAnchor;

File diff suppressed because it is too large Load Diff

View File

@@ -1,78 +0,0 @@
#import <Foundation/Foundation.h>
#import "MGLTypes.h"
NS_ASSUME_NONNULL_BEGIN
/** These constants represent the scheme that the tile URL templates will use. */
typedef NS_ENUM(NSUInteger, MGLTileSetScheme) {
MGLTileSetSchemeXYZ = 0,
MGLTileSetSchemeTMS
};
/**
The `MGLTileSet` class holds the tile URL template strings and associated
configuration for those strings. It can be passed to an `MGLVectorSource` or
`MGLRasterSource` instead of an `NSURL` representing a TileJSON URL to create a
source.
*/
@interface MGLTileSet : NSObject
/**
An `NSArray` of `NSString` objects that represent the tile templates.
*/
@property (nonatomic, copy) NS_ARRAY_OF(NSString *) *tileURLTemplates;
/**
An `NSNumber` object containing an integer; specifies the minimum zoom level at
which the source will display tiles. The value should be in the range of 0 to
22. The default value is 0 and the source will use the default value
if `minimumZoomLevel` is nil.
*/
@property (nonatomic, nullable) NSNumber *minimumZoomLevel;
/**
An `NSNumber` object containing an integer; specifies the maximum zoom level at
which to display tiles. The value should be in the range of 0 to 22 and greater
than `minimumZoomLevel`. The default value is 22 and the source will use the
default value if `maximumZoomLevel` is nil.
*/
@property (nonatomic, nullable) NSNumber *maximumZoomLevel;
/**
An `NSString` object that contains an attribution to be displayed when the map
is shown to a user. The default value is `nil`.
*/
@property (nonatomic, copy, nullable) NSString *attribution;
/**
An `MGLTileSetScheme` value that contains an enumeration (either
`MGLTileSetSchemeXYZ` or `MGLTileSetSchemeTMS`) that influences the y direction
of the tile coordinates. The default is `MGLTileSetSchemeXYZ`.
*/
@property (nonatomic) MGLTileSetScheme scheme;
/**
Initializes and returns a new tile set object.
@param tileURLTemplates An `NSArray` of `NSString` objects that represent the
tile templates.
@return The initialized tile set object.
*/
- (instancetype)initWithTileURLTemplates:(NS_ARRAY_OF(NSString *) *)tileURLTemplates;
/**
Initializes and returns a new tile set object.
@param tileURLTemplates An `NSArray` of `NSString` objects that represent the
tile templates.
@param minimumZoomLevel An `NSUInteger`; specifies the minimum zoom level at
which to display tiles.
@param maximumZoomLevel An `NSUInteger`; specifies the maximum zoom level at
which to display tiles.
@return The initialized tile set object.
*/
- (instancetype)initWithTileURLTemplates:(NS_ARRAY_OF(NSString *) *)tileURLTemplates minimumZoomLevel:(NSUInteger)minimumZoomLevel maximumZoomLevel:(NSUInteger)maximumZoomLevel;
@end
NS_ASSUME_NONNULL_END

View File

@@ -1,93 +0,0 @@
#import "MGLTileSet.h"
#include <mbgl/util/tileset.hpp>
@implementation MGLTileSet
- (instancetype)initWithTileURLTemplates:(NS_ARRAY_OF(NSString *) *)tileURLTemplates
{
if (self = [super init])
{
_tileURLTemplates = tileURLTemplates;
}
return self;
}
- (instancetype)initWithTileURLTemplates:(NS_ARRAY_OF(NSString *) *)tileURLTemplates minimumZoomLevel:(NSUInteger)minimumZoomLevel maximumZoomLevel:(NSUInteger)maximumZoomLevel
{
if (minimumZoomLevel > maximumZoomLevel)
{
[[NSException exceptionWithName:@"Invalid minimumZoomLevel"
reason:@"minimumZoomLevel must be less than maximumZoomLevel"
userInfo:nil] raise];
return nil;
}
if (self = [super init])
{
_tileURLTemplates = tileURLTemplates;
_minimumZoomLevel = @(minimumZoomLevel);
_maximumZoomLevel = @(maximumZoomLevel);
}
return self;
}
- (void)setMinimumZoomLevel:(NSNumber *)minimumZoomLevel
{
if (self.maximumZoomLevel && [minimumZoomLevel integerValue] > [self.maximumZoomLevel integerValue])
{
[[NSException exceptionWithName:@"Invalid minimumZoomLevel"
reason:@"minimumZoomLevel must be less than maximumZoomLevel"
userInfo:nil] raise];
return;
}
_minimumZoomLevel = minimumZoomLevel;
}
- (void)setMaximumZoomLevel:(NSNumber *)maximumZoomLevel
{
if (self.maximumZoomLevel && [maximumZoomLevel integerValue] < [self.maximumZoomLevel integerValue])
{
[[NSException exceptionWithName:@"Invalid minimumZoomLevel"
reason:@"minimumZoomLevel must be less than maximumZoomLevel"
userInfo:nil] raise];
}
_maximumZoomLevel = maximumZoomLevel;
}
- (mbgl::Tileset)mbglTileset
{
mbgl::Tileset tileset;
for (NSString *tileURLTemplate in self.tileURLTemplates)
{
tileset.tiles.push_back(tileURLTemplate.UTF8String);
}
// set the minimum / maximum zoom range to the values specified by this class if they
// were set. otherwise, use the core objects default values
uint8_t minimumZoomLevel = self.minimumZoomLevel ? [self.minimumZoomLevel unsignedIntegerValue] : tileset.zoomRange.min;
uint8_t maximumZoomLevel = self.minimumZoomLevel ? [self.maximumZoomLevel unsignedIntegerValue] : tileset.zoomRange.max;
tileset.zoomRange = mbgl::Range<uint8_t>(minimumZoomLevel, maximumZoomLevel);
if (self.attribution)
{
tileset.attribution = self.attribution.UTF8String;
}
if (self.scheme == MGLTileSetSchemeTMS) {
tileset.scheme = mbgl::Tileset::Scheme::TMS;
}
return tileset;
}
- (NSString *)description
{
return [NSString stringWithFormat:@"<%@: %p; tileURLTemplates = %@>",
NSStringFromClass([self class]), (void *)self, self.tileURLTemplates];
}
@end

View File

@@ -1,9 +0,0 @@
#import "MGLTileSet.h"
#include <mbgl/util/tileset.hpp>
@interface MGLTileSet (Private)
- (mbgl::Tileset)mbglTileset;
@end

View File

@@ -0,0 +1,179 @@
#import <Foundation/Foundation.h>
#import "MGLSource.h"
#import "MGLTypes.h"
NS_ASSUME_NONNULL_BEGIN
@class MGLAttributionInfo;
/**
Options for `MGLTileSource` objects.
*/
typedef NSString *MGLTileSourceOption NS_STRING_ENUM;
/**
An `NSNumber` object containing an unsigned integer that specifies the minimum
zoom level at which to display tiles from the source.
The value should be between 0 and 22, inclusive, and less than
`MGLTileSourceOptionMaximumZoomLevel`, if specified. The default value for this
option is 0.
*/
extern const MGLTileSourceOption MGLTileSourceOptionMinimumZoomLevel;
/**
An `NSNumber` object containing an unsigned integer that specifies the maximum
zoom level at which to display tiles from the source.
The value should be between 0 and 22, inclusive, and less than
`MGLTileSourceOptionMinimumZoomLevel`, if specified. The default value for this
option is 22.
*/
extern const MGLTileSourceOption MGLTileSourceOptionMaximumZoomLevel;
#if TARGET_OS_IPHONE
/**
An HTML string defining the buttons to be displayed in an action sheet when the
source is part of a map view’s style and the map view’s attribution button is
pressed.
By default, no attribution statements are displayed. If the
`MGLTileSourceOptionAttributionInfos` option is specified, this option is
ignored.
*/
extern const MGLTileSourceOption MGLTileSourceOptionAttributionHTMLString;
/**
An array of `MGLAttributionInfo` objects defining the buttons to be displayed
in an action sheet when the source is part of a map view’s style and the map
view’s attribution button is pressed.
By default, no attribution statements are displayed.
*/
extern const MGLTileSourceOption MGLTileSourceOptionAttributionInfos;
#else
/**
An HTML string defining the buttons to be displayed in the map view’s
attribution view when the source is part of the map view’s style.
By default, no attribution statements are displayed. If the
`MGLTileSourceOptionAttributionInfos` option is specified, this option is
ignored.
*/
extern const MGLTileSourceOption MGLTileSourceOptionAttributionHTMLString;
/**
An array of `MGLAttributionInfo` objects defining the buttons to be displayed
in the map view’s attribution view when the source is part of the map view’s
style.
By default, no attribution statements are displayed.
*/
extern const MGLTileSourceOption MGLTileSourceOptionAttributionInfos;
#endif
/**
An `NSNumber` object containing an unsigned integer that specifies the tile
coordinate system for the source’s tile URLs. The integer corresponds to one of
the constants described in `MGLTileCoordinateSystem`.
The default value for this option is `MGLTileCoordinateSystemXYZ`.
*/
extern const MGLTileSourceOption MGLTileSourceOptionTileCoordinateSystem;
/**
Tile coordinate systems that determine how tile coordinates in tile URLs are
interpreted.
*/
typedef NS_ENUM(NSUInteger, MGLTileCoordinateSystem) {
/**
The origin is at the top-left (northwest), and `y` values increase
southwards.
This tile coordinate system is used by Mapbox and OpenStreetMap tile
servers.
*/
MGLTileCoordinateSystemXYZ = 0,
/**
The origin is at the bottom-left (southwest), and `y` values increase
northwards.
This tile coordinate system is used by tile servers that conform to the
<a href="http://wiki.osgeo.org/wiki/Tile_Map_Service_Specification">Tile Map Service Specification</a>.
*/
MGLTileCoordinateSystemTMS
};
/**
`MGLTileSource` is a map content source that supplies map tiles to be shown on
the map. The location of and metadata about the tiles are defined either by an
option dictionary or by an external file that conforms to the
<a href="https://github.com/mapbox/tilejson-spec/">TileJSON specification</a>.
A tile source is added to an `MGLStyle` object along with one or more
`MGLRasterStyleLayer` or `MGLVectorStyleLayer` objects. Use a style layer to
control the appearance of content supplied by the tile source.
Do not create instances of this class directly, and do not create your own
subclasses of this class. Instead, create instances of `MGLRasterSource` and
`MGLVectorSource`.
*/
@interface MGLTileSource : MGLSource
#pragma mark Initializing a Source
- (instancetype)init __attribute__((unavailable("Use -initWithIdentifier:configurationURL: or -initWithIdentifier:tileURLTemplates:options: instead.")));
- (instancetype)initWithIdentifier:(NSString *)identifier __attribute__((unavailable("Use -initWithIdentifier:configurationURL: or -initWithIdentifier:tileURLTemplates:options: instead.")));
/**
Returns a tile source initialized with an identifier and configuration URL.
After initializing and configuring the source, add it to a map view’s style
using the `-[MGLStyle addSource:]` method.
The URL may be a full HTTP or HTTPS URL or, for tile sets hosted by Mapbox, a
Mapbox URL indicating a map identifier (`mapbox://<mapid>`). The URL should
point to a JSON file that conforms to the
<a href="https://github.com/mapbox/tilejson-spec/">TileJSON specification</a>.
@param identifier A string that uniquely identifies the source in the style to
which it is added.
@param configurationURL A URL to a TileJSON configuration file describing the
source’s contents and other metadata.
@return An initialized tile source.
*/
- (instancetype)initWithIdentifier:(NSString *)identifier configurationURL:(NSURL *)configurationURL;
/**
Returns a tile source initialized an identifier, tile URL templates, and
options.
After initializing and configuring the source, add it to a map view’s style
using the `-[MGLStyle addSource:]` method.
@param identifier A string that uniquely identifies the source in the style to
which it is added.
@param tileURLTemplates An array of tile URL template strings.
@param options A dictionary containing configuration options. See
`MGLTileSourceOption` for available keys and values. Pass in `nil` to use
the default values.
@return An initialized tile source.
*/
- (instancetype)initWithIdentifier:(NSString *)identifier tileURLTemplates:(NS_ARRAY_OF(NSString *) *)tileURLTemplates options:(nullable NS_DICTIONARY_OF(MGLTileSourceOption, id) *)options;
#pragma mark Accessing Attribution Strings
/**
An array of `MGLAttributionInfo` objects that define the attribution
statements to be displayed when the map is shown to the user.
By default, this array is empty. If the source is initialized with a
configuration URL, this array is also empty until the configuration JSON file
is loaded.
*/
@property (nonatomic, copy, readonly) NS_ARRAY_OF(MGLAttributionInfo *) *attributionInfos;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,123 @@
#import "MGLTileSource_Private.h"
#import "MGLAttributionInfo_Private.h"
#import "NSString+MGLAdditions.h"
#if TARGET_OS_IPHONE
#import <UIKit/UIKit.h>
#else
#import <Cocoa/Cocoa.h>
#endif
#include <mbgl/util/tileset.hpp>
const MGLTileSourceOption MGLTileSourceOptionMinimumZoomLevel = @"MGLTileSourceOptionMinimumZoomLevel";
const MGLTileSourceOption MGLTileSourceOptionMaximumZoomLevel = @"MGLTileSourceOptionMaximumZoomLevel";
const MGLTileSourceOption MGLTileSourceOptionAttributionHTMLString = @"MGLTileSourceOptionAttributionHTMLString";
const MGLTileSourceOption MGLTileSourceOptionAttributionInfos = @"MGLTileSourceOptionAttributionInfos";
const MGLTileSourceOption MGLTileSourceOptionTileCoordinateSystem = @"MGLTileSourceOptionTileCoordinateSystem";
@implementation MGLTileSource
- (instancetype)initWithIdentifier:(NSString *)identifier configurationURL:(NSURL *)configurationURL {
return [super initWithIdentifier:identifier];
}
- (instancetype)initWithIdentifier:(NSString *)identifier tileURLTemplates:(NS_ARRAY_OF(NSString *) *)tileURLTemplates options:(NS_DICTIONARY_OF(MGLTileSourceOption, id) *)options {
return [super initWithIdentifier:identifier];
}
- (NS_ARRAY_OF(MGLAttributionInfo *) *)attributionInfos {
return [self attributionInfosWithFontSize:0 linkColor:nil];
}
- (NS_ARRAY_OF(MGLAttributionInfo *) *)attributionInfosWithFontSize:(CGFloat)fontSize linkColor:(nullable MGLColor *)linkColor {
return [MGLAttributionInfo attributionInfosFromHTMLString:self.attributionHTMLString
fontSize:fontSize
linkColor:linkColor];
}
- (NSString *)attributionHTMLString {
[NSException raise:@"MGLAbstractClassException"
format:@"MGLTileSource is an abstract class"];
return nil;
}
@end
mbgl::Tileset MGLTileSetFromTileURLTemplates(NS_ARRAY_OF(NSString *) *tileURLTemplates, NS_DICTIONARY_OF(MGLTileSourceOption, id) * _Nullable options) {
mbgl::Tileset tileSet;
for (NSString *tileURLTemplate in tileURLTemplates) {
tileSet.tiles.push_back(tileURLTemplate.UTF8String);
}
// set the minimum / maximum zoom range to the values specified by this class if they
// were set. otherwise, use the core objects default values
if (NSNumber *minimumZoomLevel = options[MGLTileSourceOptionMinimumZoomLevel]) {
if (![minimumZoomLevel isKindOfClass:[NSNumber class]]) {
[NSException raise:NSInvalidArgumentException
format:@"MGLTileSourceOptionMinimumZoomLevel must be set to an NSNumber."];
}
tileSet.zoomRange.min = minimumZoomLevel.integerValue;
}
if (NSNumber *maximumZoomLevel = options[MGLTileSourceOptionMaximumZoomLevel]) {
if (![maximumZoomLevel isKindOfClass:[NSNumber class]]) {
[NSException raise:NSInvalidArgumentException
format:@"MGLTileSourceOptionMinimumZoomLevel must be set to an NSNumber."];
}
tileSet.zoomRange.max = maximumZoomLevel.integerValue;
}
if (tileSet.zoomRange.min > tileSet.zoomRange.max) {
[NSException raise:NSInvalidArgumentException
format:@"MGLTileSourceOptionMinimumZoomLevel must be less than MGLTileSourceOptionMaximumZoomLevel."];
}
if (NSString *attribution = options[MGLTileSourceOptionAttributionHTMLString]) {
if (![attribution isKindOfClass:[NSString class]]) {
[NSException raise:NSInvalidArgumentException
format:@"MGLTileSourceOptionAttributionHTMLString must be set to a string."];
}
tileSet.attribution = attribution.UTF8String;
}
if (NSArray *attributionInfos = options[MGLTileSourceOptionAttributionInfos]) {
if (![attributionInfos isKindOfClass:[NSArray class]]) {
[NSException raise:NSInvalidArgumentException
format:@"MGLTileSourceOptionAttributionInfos must be set to a string."];
}
NSAttributedString *attributedString = [MGLAttributionInfo attributedStringForAttributionInfos:attributionInfos];
#if TARGET_OS_IPHONE
static NSString * const NSExcludedElementsDocumentAttribute = @"ExcludedElements";
#endif
NSDictionary *documentAttributes = @{
NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType,
NSCharacterEncodingDocumentAttribute: @(NSUTF8StringEncoding),
// The attribution string is meant to be a simple, inline fragment, not a full-fledged, validating document.
NSExcludedElementsDocumentAttribute: @[@"XML", @"DOCTYPE", @"html", @"head", @"meta", @"title", @"style", @"body", @"p"],
};
NSData *data = [attributedString dataFromRange:attributedString.mgl_wholeRange documentAttributes:documentAttributes error:NULL];
NSString *html = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
tileSet.attribution = html.UTF8String;
}
if (NSNumber *tileCoordinateSystemNumber = options[MGLTileSourceOptionTileCoordinateSystem]) {
if (![tileCoordinateSystemNumber isKindOfClass:[NSValue class]]) {
[NSException raise:NSInvalidArgumentException
format:@"MGLTileSourceOptionTileCoordinateSystem must be set to an NSValue or NSNumber."];
}
MGLTileCoordinateSystem tileCoordinateSystem;
[tileCoordinateSystemNumber getValue:&tileCoordinateSystem];
switch (tileCoordinateSystem) {
case MGLTileCoordinateSystemXYZ:
tileSet.scheme = mbgl::Tileset::Scheme::XYZ;
break;
case MGLTileCoordinateSystemTMS:
tileSet.scheme = mbgl::Tileset::Scheme::TMS;
break;
}
}
return tileSet;
}

View File

@@ -0,0 +1,36 @@
#import "MGLTileSource.h"
#import <CoreGraphics/CoreGraphics.h>
NS_ASSUME_NONNULL_BEGIN
namespace mbgl {
class Tileset;
}
@class MGLAttributionInfo;
@interface MGLTileSource (Private)
/**
An HTML string to be displayed as attribution when the map is shown to a user.
The default value is `nil`. If the source is initialized with a configuration
URL, this property is also `nil` until the configuration JSON file is loaded.
*/
@property (nonatomic, copy, nullable, readonly) NSString *attributionHTMLString;
/**
A structured representation of the `attribution` property. The default value is
`nil`.
@param fontSize The default text size in points, or 0 to use the default.
@param linkColor The default link color, or `nil` to use the default.
*/
- (NS_ARRAY_OF(MGLAttributionInfo *) *)attributionInfosWithFontSize:(CGFloat)fontSize linkColor:(nullable MGLColor *)linkColor;
@end
mbgl::Tileset MGLTileSetFromTileURLTemplates(NS_ARRAY_OF(NSString *) *tileURLTemplates, NS_DICTIONARY_OF(MGLTileSourceOption, id) * _Nullable options);
NS_ASSUME_NONNULL_END

View File

@@ -1,68 +1,35 @@
#import "MGLSource.h"
#import "MGLTypes.h"
@class MGLTileSet;
#import "MGLTileSource.h"
NS_ASSUME_NONNULL_BEGIN
/**
A vector tile source. Tiles must be in Mapbox Vector Tile format.
`MGLVectorSource` is a map content source that supplies tiled vector data in
<a href="https://www.mapbox.com/vector-tiles/">Mapbox Vector Tile</a> format to
be shown on the map. The location of and metadata about the tiles are defined
either by an option dictionary or by an external file that conforms to the
<a href="https://github.com/mapbox/tilejson-spec/">TileJSON specification</a>.
A vector source is added to an `MGLStyle` object along with one or more
`MGLVectorStyleLayer` objects. A vector style layer defines the appearance of
any content supplied by the vector source.
@see <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-vector">The
style specification.</a>
Each
<a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-vector"><code>vector</code></a>
source defined by the style JSON file is represented at runtime by an
`MGLVectorSource` object that you can use to initialize new style layers. You
can also add and remove sources dynamically using methods such as
`-[MGLStyle addSource:]` and `-[MGLStyle sourceWithIdentifier:]`.
Within each vector tile, each geometric coordinate must lie between
−1&nbsp;×&nbsp;<var>extent</var> and
(<var>extent</var>&nbsp;×&nbsp;2)&nbsp;−&nbsp;1, inclusive. Any vector style
layer initialized with a vector source must have a non-`nil` value in its
`sourceLayerIdentifier` property.
*/
@interface MGLVectorSource : MGLSource
@interface MGLVectorSource : MGLTileSource
#pragma mark Initializing a Source
- (instancetype)initWithIdentifier:(NSString *)identifier configurationURL:(NSURL *)configurationURL NS_DESIGNATED_INITIALIZER;
/**
Returns a vector source initialized with an identifier and TileJSON URL.
After initializing and configuring the source, add it to a map view’s style
using the `-[MGLStyle addSource:]` method.
@param identifier A string that uniquely identifies the source in the style to
which it is added.
@param url A URL to a TileJSON configuration file describing the source’s
contents and other metadata.
@return An initialized vector source.
*/
- (instancetype)initWithIdentifier:(NSString *)identifier URL:(NSURL *)url NS_DESIGNATED_INITIALIZER;
/**
Returns a vector source initialized an identifier and tile set.
After initializing and configuring the source, add it to a map view’s style
using the `-[MGLStyle addSource:]` method.
@param identifier A string that uniquely identifies the source in the style to
which it is added.
@param tileSet A tile set describing the source’s contents and other metadata.
@return An initialized vector source.
*/
- (instancetype)initWithIdentifier:(NSString *)identifier tileSet:(MGLTileSet *)tileSet NS_DESIGNATED_INITIALIZER;
#pragma mark Accessing a Source’s Content
/**
A URL to a TileJSON configuration file describing the source’s contents and
other metadata.
The URL may be a full HTTP or HTTPS URL or a Mapbox URL indicating the tile
set’s map ID (`mapbox://<mapid>`).
If the receiver was initialized using `-initWithIdentifier:tileSet:`, this
property is set to `nil`.
*/
@property (nonatomic, readonly, copy) NSURL *URL;
/**
A tile set describing the source’s contents and other metadata.
If the receiver was initialized using `-initWithIdentifier:URL:`, this property
is set to `nil`.
*/
@property (nonatomic, readonly, nullable) MGLTileSet *tileSet;
- (instancetype)initWithIdentifier:(NSString *)identifier tileURLTemplates:(NS_ARRAY_OF(NSString *) *)tileURLTemplates options:(nullable NS_DICTIONARY_OF(MGLTileSourceOption, id) *)options NS_DESIGNATED_INITIALIZER;
@end

View File

@@ -1,64 +1,50 @@
#import "MGLVectorSource.h"
#import "MGLVectorSource_Private.h"
#import "MGLMapView_Private.h"
#import "MGLSource_Private.h"
#import "MGLTileSet_Private.h"
#import "MGLTileSource_Private.h"
#import "NSURL+MGLAdditions.h"
#include <mbgl/style/sources/vector_source.hpp>
@interface MGLVectorSource ()
- (instancetype)initWithRawSource:(mbgl::style::VectorSource *)rawSource NS_DESIGNATED_INITIALIZER;
@property (nonatomic) mbgl::style::VectorSource *rawSource;
@end
@implementation MGLVectorSource
{
@implementation MGLVectorSource {
std::unique_ptr<mbgl::style::VectorSource> _pendingSource;
}
- (instancetype)initWithIdentifier:(NSString *)identifier URL:(NSURL *)url
{
if (self = [super initWithIdentifier:identifier])
{
_URL = url;
[self commonInit];
- (instancetype)initWithIdentifier:(NSString *)identifier configurationURL:(NSURL *)configurationURL {
if (self = [super initWithIdentifier:identifier configurationURL:configurationURL]) {
auto source = std::make_unique<mbgl::style::VectorSource>(identifier.UTF8String,
configurationURL.mgl_URLByStandardizingScheme.absoluteString.UTF8String);
_pendingSource = std::move(source);
self.rawSource = _pendingSource.get();
}
return self;
}
- (instancetype)initWithIdentifier:(NSString *)identifier tileSet:(MGLTileSet *)tileSet
{
if (self = [super initWithIdentifier:identifier])
{
_tileSet = tileSet;
[self commonInit];
- (instancetype)initWithIdentifier:(NSString *)identifier tileURLTemplates:(NS_ARRAY_OF(NSString *) *)tileURLTemplates options:(nullable NS_DICTIONARY_OF(MGLTileSourceOption, id) *)options {
if (self = [super initWithIdentifier:identifier tileURLTemplates:tileURLTemplates options:options]) {
mbgl::Tileset tileSet = MGLTileSetFromTileURLTemplates(tileURLTemplates, options);
auto source = std::make_unique<mbgl::style::VectorSource>(identifier.UTF8String, tileSet);
_pendingSource = std::move(source);
self.rawSource = _pendingSource.get();
}
return self;
}
- (void)commonInit
{
std::unique_ptr<mbgl::style::VectorSource> source;
if (self.URL)
{
source = std::make_unique<mbgl::style::VectorSource>(self.identifier.UTF8String,
self.URL.mgl_URLByStandardizingScheme.absoluteString.UTF8String);
}
else
{
source = std::make_unique<mbgl::style::VectorSource>(self.identifier.UTF8String,
self.tileSet.mbglTileset);
}
_pendingSource = std::move(source);
self.rawSource = _pendingSource.get();
- (instancetype)initWithRawSource:(mbgl::style::VectorSource *)rawSource {
return [super initWithRawSource:rawSource];
}
- (void)addToMapView:(MGLMapView *)mapView
{
- (void)addToMapView:(MGLMapView *)mapView {
if (_pendingSource == nullptr) {
[NSException raise:@"MGLRedundantSourceException"
format:@"This instance %@ was already added to %@. Adding the same source instance " \
@@ -68,18 +54,24 @@
mapView.mbglMap->addSource(std::move(_pendingSource));
}
- (void)removeFromMapView:(MGLMapView *)mapView
{
- (void)removeFromMapView:(MGLMapView *)mapView {
auto removedSource = mapView.mbglMap->removeSource(self.identifier.UTF8String);
_pendingSource = std::move(reinterpret_cast<std::unique_ptr<mbgl::style::VectorSource> &>(removedSource));
self.rawSource = _pendingSource.get();
}
- (NSString *)description
{
return [NSString stringWithFormat:@"<%@: %p; identifier = %@; URL = %@; tileSet = %@>",
NSStringFromClass([self class]), (void *)self, self.identifier, self.URL, self.tileSet];
- (mbgl::style::VectorSource *)rawSource {
return (mbgl::style::VectorSource *)super.rawSource;
}
- (void)setRawSource:(mbgl::style::VectorSource *)rawSource {
super.rawSource = rawSource;
}
- (NSString *)attributionHTMLString {
auto attribution = self.rawSource->getAttribution();
return attribution ? @(attribution->c_str()) : nil;
}
@end

View File

@@ -0,0 +1,17 @@
#import "MGLVectorSource.h"
NS_ASSUME_NONNULL_BEGIN
namespace mbgl {
namespace style {
class VectorSource;
}
}
@interface MGLVectorSource (Private)
- (instancetype)initWithRawSource:(mbgl::style::VectorSource *)rawSource;
@end
NS_ASSUME_NONNULL_END

View File

@@ -6,7 +6,7 @@ NS_ASSUME_NONNULL_BEGIN
/**
`MGLVectorStyleLayer` is an abstract superclass for style layers whose content
is defined by an `MGLGeoJSONSource` or `MGLVectorSource` object.
is defined by an `MGLShapeSource` or `MGLVectorSource` object.
Do not create instances of this class directly, and do not create your own
subclasses of this class. Instead, create instances of the following concrete
@@ -122,6 +122,12 @@ NS_ASSUME_NONNULL_BEGIN
value specified in the predicate. Also, operator modifiers `c`, `d`, and the
combined `cd` for case and diacritic insensitivity are unsupported for
comparison and aggregate operators that are used in the predicate.
It is possible to create expressions that contain special characters in the
predicate format syntax. This includes the `$` in the `$id` and `$type` special
style attributes and also `hyphen-minus` and `tag:subtag`. However, you must use
`%K` in the format string to represent these variables:
`@"%K == 'LineString'", @"$type"`.
*/
@property (nonatomic, nullable) NSPredicate *predicate;

View File

@@ -6,4 +6,7 @@
- (std::vector<mbgl::Value>)mgl_vector;
/** Returns a string resulting from inserting a separator between each attributed string in the array */
- (NSAttributedString *)mgl_attributedComponentsJoinedByString:(NSString *)separator;
@end

View File

@@ -23,4 +23,19 @@
return vector;
}
- (NSAttributedString *)mgl_attributedComponentsJoinedByString:(NSString *)separator {
NSAttributedString *attributedSeparator = [[NSAttributedString alloc] initWithString:separator];
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] init];
BOOL isSubsequentItem = NO;
for (NSAttributedString *component in self) {
NSAssert([component isKindOfClass:[NSAttributedString class]], @"Items in array must be attributed strings.");
if (isSubsequentItem) {
[attributedString appendAttributedString:attributedSeparator];
}
isSubsequentItem = YES;
[attributedString appendAttributedString:component];
}
return attributedString;
}
@end

View File

@@ -4,9 +4,22 @@ NS_ASSUME_NONNULL_BEGIN
@interface NSString (MGLAdditions)
/** Returns the range spanning the entire receiver. */
- (NSRange)mgl_wholeRange;
/** Returns the receiver if non-empty or nil if empty. */
- (nullable NSString *)mgl_stringOrNilIfEmpty;
@end
@interface NSAttributedString (MGLAdditions)
/** Returns the range spanning the entire receiver. */
- (NSRange)mgl_wholeRange;
/** Returns a copy of the receiver with leading and trailing members of the given set removed. */
- (NSAttributedString *)mgl_attributedStringByTrimmingCharactersInSet:(NSCharacterSet *)set;
@end
NS_ASSUME_NONNULL_END

View File

@@ -2,9 +2,30 @@
@implementation NSString (MGLAdditions)
- (nullable NSString *)mgl_stringOrNilIfEmpty
{
- (NSRange)mgl_wholeRange {
return NSMakeRange(0, self.length);
}
- (nullable NSString *)mgl_stringOrNilIfEmpty {
return self.length ? self : nil;
}
@end
@implementation NSAttributedString (MGLAdditions)
- (NSRange)mgl_wholeRange {
return NSMakeRange(0, self.length);
}
- (NSAttributedString *)mgl_attributedStringByTrimmingCharactersInSet:(NSCharacterSet *)set {
NSScanner *scanner = [NSScanner scannerWithString:self.string];
scanner.charactersToBeSkipped = nil;
NSString *prefix;
[scanner scanCharactersFromSet:set intoString:&prefix];
NSString *trimmedString = [self.string stringByTrimmingCharactersInSet:set];
return [self attributedSubstringFromRange:NSMakeRange(prefix.length, trimmedString.length)];
}
@end

View File

@@ -98,17 +98,17 @@ NS_ASSUME_NONNULL_BEGIN
@property (readonly) MGLTextAnchor MGLTextAnchorValue;
/**
Creates a new value object containing the given `MGLTextJustify` enumeration.
Creates a new value object containing the given `MGLTextJustification` enumeration.
@param type The value for the new object.
@return A new value object that contains the style enumeration type.
*/
+ (instancetype)valueWithMGLTextJustify:(MGLTextJustify)textJustify;
+ (instancetype)valueWithMGLTextJustification:(MGLTextJustification)textJustification;
/**
The `MGLTextJustify` enumeration representation of the value.
The `MGLTextJustification` enumeration representation of the value.
*/
@property (readonly) MGLTextJustify MGLTextJustifyValue;
@property (readonly) MGLTextJustification MGLTextJustificationValue;
/**
Creates a new value object containing the given `MGLTextPitchAlignment` enumeration.

View File

@@ -65,12 +65,12 @@
return value;
}
+ (NSValue *)valueWithMGLTextJustify:(MGLTextJustify)textJustify {
return [NSValue value:&textJustify withObjCType:@encode(MGLTextJustify)];
+ (NSValue *)valueWithMGLTextJustification:(MGLTextJustification)textJustification {
return [NSValue value:&textJustification withObjCType:@encode(MGLTextJustification)];
}
- (MGLTextJustify)MGLTextJustifyValue {
MGLTextJustify value;
- (MGLTextJustification)MGLTextJustificationValue {
MGLTextJustification value;
[self getValue:&value];
return value;
}

View File

@@ -0,0 +1,115 @@
#import <Mapbox/Mapbox.h>
#import <XCTest/XCTest.h>
#import "MGLAttributionInfo_Private.h"
@interface MGLAttributionInfoTests : XCTestCase
@end
@implementation MGLAttributionInfoTests
- (void)testParsing {
static NSString * const htmlStrings[] = {
@"<a href=\"https://www.mapbox.com/about/maps/\" target=\"_blank\">&copy; Mapbox</a> "
@"<a href=\"http://www.openstreetmap.org/about/\" target=\"_blank\">©️ OpenStreetMap</a> "
@"CC&nbsp;BY-SA "
@"<a class=\"mapbox-improve-map\" href=\"https://www.mapbox.com/map-feedback/\" target=\"_blank\">Improve this map</a>",
};
NS_MUTABLE_ARRAY_OF(MGLAttributionInfo *) *infos = [NSMutableArray array];
for (NSUInteger i = 0; i < sizeof(htmlStrings) / sizeof(htmlStrings[0]); i++) {
NSArray *subinfos = [MGLAttributionInfo attributionInfosFromHTMLString:htmlStrings[i]
fontSize:0
linkColor:nil];
[infos growArrayByAddingAttributionInfosFromArray:subinfos];
}
XCTAssertEqual(infos.count, 4);
CLLocationCoordinate2D mapbox = CLLocationCoordinate2DMake(12.9810816, 77.6368034);
XCTAssertEqualObjects(infos[0].title.string, @"© Mapbox");
XCTAssertEqualObjects(infos[0].URL, [NSURL URLWithString:@"https://www.mapbox.com/about/maps/"]);
XCTAssertFalse(infos[0].feedbackLink);
XCTAssertNil([infos[0] feedbackURLAtCenterCoordinate:mapbox zoomLevel:14]);
XCTAssertEqualObjects(infos[1].title.string, @"©️ OpenStreetMap");
XCTAssertEqualObjects(infos[1].URL, [NSURL URLWithString:@"http://www.openstreetmap.org/about/"]);
XCTAssertFalse(infos[1].feedbackLink);
XCTAssertNil([infos[1] feedbackURLAtCenterCoordinate:mapbox zoomLevel:14]);
XCTAssertEqualObjects(infos[2].title.string, @"CC\u00a0BY-SA");
XCTAssertNil(infos[2].URL);
XCTAssertFalse(infos[2].feedbackLink);
XCTAssertNil([infos[2] feedbackURLAtCenterCoordinate:mapbox zoomLevel:14]);
XCTAssertEqualObjects(infos[3].title.string, @"Improve this map");
XCTAssertEqualObjects(infos[3].URL, [NSURL URLWithString:@"https://www.mapbox.com/map-feedback/"]);
XCTAssertTrue(infos[3].feedbackLink);
XCTAssertEqualObjects([infos[3] feedbackURLAtCenterCoordinate:mapbox zoomLevel:14],
[NSURL URLWithString:@"https://www.mapbox.com/map-feedback/#/77.63680/12.98108/15"]);
}
- (void)testStyle {
static NSString * const htmlStrings[] = {
@"<a href=\"https://www.mapbox.com/\">Mapbox</a>",
};
CGFloat fontSize = 72;
MGLColor *color = [MGLColor redColor];
NS_MUTABLE_ARRAY_OF(MGLAttributionInfo *) *infos = [NSMutableArray array];
for (NSUInteger i = 0; i < sizeof(htmlStrings) / sizeof(htmlStrings[0]); i++) {
NSArray *subinfos = [MGLAttributionInfo attributionInfosFromHTMLString:htmlStrings[i]
fontSize:72
linkColor:color];
[infos growArrayByAddingAttributionInfosFromArray:subinfos];
}
XCTAssertEqual(infos.count, 1);
XCTAssertEqualObjects(infos[0].title.string, @"Mapbox");
XCTAssertEqualObjects([infos[0].title attribute:NSLinkAttributeName atIndex:0 effectiveRange:nil], [NSURL URLWithString:@"https://www.mapbox.com/"]);
XCTAssertEqualObjects([infos[0].title attribute:NSUnderlineStyleAttributeName atIndex:0 effectiveRange:nil], @(NSUnderlineStyleSingle));
#if TARGET_OS_IPHONE
UIFont *font;
#else
NSFont *font;
#endif
font = [infos[0].title attribute:NSFontAttributeName atIndex:0 effectiveRange:nil];
XCTAssertEqual(font.pointSize, fontSize);
CGFloat r, g, b, a;
[color getRed:&r green:&g blue:&b alpha:&a];
MGLColor *linkColor = [infos[0].title attribute:NSForegroundColorAttributeName atIndex:0 effectiveRange:nil];
CGFloat linkR, linkG, linkB, linkA;
[linkColor getRed:&linkR green:&linkG blue:&linkB alpha:&linkA];
XCTAssertEqual(r, linkR);
XCTAssertEqual(g, linkG);
XCTAssertEqual(b, linkB);
XCTAssertEqual(a, linkA);
}
- (void)testDedupe {
static NSString * const htmlStrings[] = {
@"World",
@"Hello World",
@"Another Source",
@"Hello",
@"Hello World",
};
NS_MUTABLE_ARRAY_OF(MGLAttributionInfo *) *infos = [NSMutableArray array];
for (NSUInteger i = 0; i < sizeof(htmlStrings) / sizeof(htmlStrings[0]); i++) {
NSArray *subinfos = [MGLAttributionInfo attributionInfosFromHTMLString:htmlStrings[i]
fontSize:0
linkColor:nil];
[infos growArrayByAddingAttributionInfosFromArray:subinfos];
}
XCTAssertEqual(infos.count, 2);
XCTAssertEqualObjects(infos[0].title.string, @"Hello World");
XCTAssertEqualObjects(infos[1].title.string, @"Another Source");
}
@end

View File

@@ -8,6 +8,10 @@
@implementation MGLBackgroundLayerTests
+ (NSString *)layerType {
return @"background";
}
- (void)testBackgroundLayer {
MGLBackgroundStyleLayer *layer = [[MGLBackgroundStyleLayer alloc] initWithIdentifier:@"layerID"];
[self.mapView.style addLayer:layer];
@@ -31,4 +35,10 @@
XCTAssertEqualObjects(gLayer.backgroundPattern, [MGLRuntimeStylingHelper testStringFunction]);
}
- (void)testPropertyNames {
[self testPropertyName:@"background-color" isBoolean:NO];
[self testPropertyName:@"background-opacity" isBoolean:NO];
[self testPropertyName:@"background-pattern" isBoolean:NO];
}
@end

View File

@@ -8,10 +8,14 @@
@implementation MGLCircleLayerTests
+ (NSString *)layerType {
return @"circle";
}
- (void)testCircleLayer {
NSString *filePath = [[NSBundle bundleForClass:self.class] pathForResource:@"amsterdam" ofType:@"geojson"];
NSURL *url = [NSURL fileURLWithPath:filePath];
MGLGeoJSONSource *source = [[MGLGeoJSONSource alloc] initWithIdentifier:@"sourceID" URL:url options:nil];
MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" URL:url options:nil];
[self.mapView.style addSource:source];
MGLCircleStyleLayer *layer = [[MGLCircleStyleLayer alloc] initWithIdentifier:@"layerID" source:source];
[self.mapView.style addLayer:layer];
@@ -65,4 +69,17 @@
XCTAssertEqualObjects(gLayer.circleTranslateAnchor, [MGLRuntimeStylingHelper testEnumFunction:MGLCircleTranslateAnchorViewport type:@encode(MGLCircleTranslateAnchor)]);
}
- (void)testPropertyNames {
[self testPropertyName:@"circle-blur" isBoolean:NO];
[self testPropertyName:@"circle-color" isBoolean:NO];
[self testPropertyName:@"circle-opacity" isBoolean:NO];
[self testPropertyName:@"circle-pitch-scale" isBoolean:NO];
[self testPropertyName:@"circle-radius" isBoolean:NO];
[self testPropertyName:@"circle-stroke-color" isBoolean:NO];
[self testPropertyName:@"circle-stroke-opacity" isBoolean:NO];
[self testPropertyName:@"circle-stroke-width" isBoolean:NO];
[self testPropertyName:@"circle-translate" isBoolean:NO];
[self testPropertyName:@"circle-translate-anchor" isBoolean:NO];
}
@end

View File

@@ -159,7 +159,7 @@
}
- (void)testPointFeatureGeoJSONDictionary {
MGLPointFeature<MGLFeaturePrivate> *pointFeature = (MGLPointFeature<MGLFeaturePrivate> *)[[MGLPointFeature alloc] init];
MGLPointFeature *pointFeature = [[MGLPointFeature alloc] init];
CLLocationCoordinate2D coordinate = { 10, 10 };
pointFeature.coordinate = coordinate;

View File

@@ -8,15 +8,19 @@
@implementation MGLFillLayerTests
+ (NSString *)layerType {
return @"fill";
}
- (void)testFillLayer {
NSString *filePath = [[NSBundle bundleForClass:self.class] pathForResource:@"amsterdam" ofType:@"geojson"];
NSURL *url = [NSURL fileURLWithPath:filePath];
MGLGeoJSONSource *source = [[MGLGeoJSONSource alloc] initWithIdentifier:@"sourceID" URL:url options:nil];
MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" URL:url options:nil];
[self.mapView.style addSource:source];
MGLFillStyleLayer *layer = [[MGLFillStyleLayer alloc] initWithIdentifier:@"layerID" source:source];
[self.mapView.style addLayer:layer];
layer.fillAntialias = [MGLRuntimeStylingHelper testBool];
layer.fillAntialiased = [MGLRuntimeStylingHelper testBool];
layer.fillColor = [MGLRuntimeStylingHelper testColor];
layer.fillOpacity = [MGLRuntimeStylingHelper testNumber];
layer.fillOutlineColor = [MGLRuntimeStylingHelper testColor];
@@ -26,7 +30,7 @@
MGLFillStyleLayer *gLayer = (MGLFillStyleLayer *)[self.mapView.style layerWithIdentifier:@"layerID"];
XCTAssertTrue([gLayer isKindOfClass:[MGLFillStyleLayer class]]);
XCTAssertEqualObjects(gLayer.fillAntialias, [MGLRuntimeStylingHelper testBool]);
XCTAssertEqualObjects(gLayer.fillAntialiased, [MGLRuntimeStylingHelper testBool]);
XCTAssertEqualObjects(gLayer.fillColor, [MGLRuntimeStylingHelper testColor]);
XCTAssertEqualObjects(gLayer.fillOpacity, [MGLRuntimeStylingHelper testNumber]);
XCTAssertEqualObjects(gLayer.fillOutlineColor, [MGLRuntimeStylingHelper testColor]);
@@ -35,7 +39,7 @@
XCTAssert([gLayer.fillTranslateAnchor isKindOfClass:[MGLStyleConstantValue class]]);
XCTAssertEqualObjects(gLayer.fillTranslateAnchor, [MGLRuntimeStylingHelper testEnum:MGLFillTranslateAnchorViewport type:@encode(MGLFillTranslateAnchor)]);
layer.fillAntialias = [MGLRuntimeStylingHelper testBoolFunction];
layer.fillAntialiased = [MGLRuntimeStylingHelper testBoolFunction];
layer.fillColor = [MGLRuntimeStylingHelper testColorFunction];
layer.fillOpacity = [MGLRuntimeStylingHelper testNumberFunction];
layer.fillOutlineColor = [MGLRuntimeStylingHelper testColorFunction];
@@ -43,7 +47,7 @@
layer.fillTranslate = [MGLRuntimeStylingHelper testOffsetFunction];
layer.fillTranslateAnchor = [MGLRuntimeStylingHelper testEnumFunction:MGLFillTranslateAnchorViewport type:@encode(MGLFillTranslateAnchor)];
XCTAssertEqualObjects(gLayer.fillAntialias, [MGLRuntimeStylingHelper testBoolFunction]);
XCTAssertEqualObjects(gLayer.fillAntialiased, [MGLRuntimeStylingHelper testBoolFunction]);
XCTAssertEqualObjects(gLayer.fillColor, [MGLRuntimeStylingHelper testColorFunction]);
XCTAssertEqualObjects(gLayer.fillOpacity, [MGLRuntimeStylingHelper testNumberFunction]);
XCTAssertEqualObjects(gLayer.fillOutlineColor, [MGLRuntimeStylingHelper testColorFunction]);
@@ -52,4 +56,14 @@
XCTAssertEqualObjects(gLayer.fillTranslateAnchor, [MGLRuntimeStylingHelper testEnumFunction:MGLFillTranslateAnchorViewport type:@encode(MGLFillTranslateAnchor)]);
}
- (void)testPropertyNames {
[self testPropertyName:@"is-fill-antialiased" isBoolean:YES];
[self testPropertyName:@"fill-color" isBoolean:NO];
[self testPropertyName:@"fill-opacity" isBoolean:NO];
[self testPropertyName:@"fill-outline-color" isBoolean:NO];
[self testPropertyName:@"fill-pattern" isBoolean:NO];
[self testPropertyName:@"fill-translate" isBoolean:NO];
[self testPropertyName:@"fill-translate-anchor" isBoolean:NO];
}
@end

View File

@@ -5,7 +5,7 @@
@interface MGLFilterTests : MGLStyleLayerTests {
MGLGeoJSONSource *source;
MGLShapeSource *source;
MGLLineStyleLayer *layer;
}
@end
@@ -18,7 +18,11 @@
NSString *filePath = [[NSBundle bundleForClass:self.class] pathForResource:@"amsterdam" ofType:@"geojson"];
NSURL *url = [NSURL fileURLWithPath:filePath];
NSData *geoJSONData = [NSData dataWithContentsOfURL:url];
source = [[MGLGeoJSONSource alloc] initWithIdentifier:@"test-source" geoJSONData:geoJSONData options:nil];
NSError *error;
MGLShape *shape = [MGLShape shapeWithData:geoJSONData encoding:NSUTF8StringEncoding error:&error];
XCTAssertNil(error);
XCTAssertNotNil(shape);
source = [[MGLShapeSource alloc] initWithIdentifier:@"test-source" shape:shape options:nil];
[self.mapView.style addSource:source];
layer = [[MGLLineStyleLayer alloc] initWithIdentifier:@"test-layer" source:source];
}

View File

@@ -99,4 +99,49 @@
XCTAssertFalse(MGLCoordinateInCoordinateBounds(kCLLocationCoordinate2DInvalid, wyoming));
}
- (void)testGeoJSONDeserialization {
NSData *data = [@"{\"type\": \"Feature\", \"geometry\": {\"type\": \"Point\", \"coordinates\": [0, 0]}, \"properties\": {}}" dataUsingEncoding:NSUTF8StringEncoding];
NSError *error;
MGLPointFeature *feature = (MGLPointFeature *)[MGLShape shapeWithData:data encoding:NSUTF8StringEncoding error:&error];
XCTAssertNil(error, @"Valid GeoJSON data should produce no error on deserialization.");
XCTAssertNotNil(feature, @"Valid GeoJSON data should produce an object on deserialization.");
XCTAssertTrue([feature isKindOfClass:[MGLPointFeature class]], @"Valid GeoJSON point feature data should produce an MGLPointFeature.");
XCTAssertEqual(feature.attributes.count, 0);
XCTAssertEqual(feature.coordinate.latitude, 0);
XCTAssertEqual(feature.coordinate.longitude, 0);
data = [@"{\"type\": \"Feature\", \"feature\": {\"type\": \"Point\", \"coordinates\": [0, 0]}}" dataUsingEncoding:NSUTF8StringEncoding];
error = nil;
MGLShape *shape = [MGLShape shapeWithData:data encoding:NSUTF8StringEncoding error:&error];
XCTAssertNotNil(error, @"Invalid GeoJSON data should produce an error on deserialization.");
XCTAssertNil(shape, @"Invalid GeoJSON data should produce no object on deserialization.");
}
- (void)testGeoJSONSerialization {
MGLPointFeature *feature = [[MGLPointFeature alloc] init];
feature.identifier = @504;
feature.coordinate = CLLocationCoordinate2DMake(29.95, -90.066667);
NSData *data = [feature geoJSONDataUsingEncoding:NSUTF8StringEncoding];
XCTAssertNotNil(data, @"MGLPointFeature should serialize as an UTF-8 string data object.");
NSError *error;
NSDictionary *serializedGeoJSON = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
XCTAssertNil(error, @"Serialized GeoJSON data should be deserializable JSON.");
XCTAssertNotNil(serializedGeoJSON, @"Serialized GeoJSON data should be valid JSON.");
XCTAssertTrue([serializedGeoJSON isKindOfClass:[NSDictionary class]], @"Serialized GeoJSON data should be a JSON object.");
NSDictionary *geoJSON = @{
@"type": @"Feature",
@"id": @504,
@"geometry": @{
@"type": @"Point",
@"coordinates": @[
@(-90.066667),
@29.95,
],
},
@"properties": @{},
};
XCTAssertEqualObjects(serializedGeoJSON, geoJSON, @"MGLPointFeature should serialize as a GeoJSON point feature.");
}
@end

View File

@@ -8,10 +8,14 @@
@implementation MGLLineLayerTests
+ (NSString *)layerType {
return @"line";
}
- (void)testLineLayer {
NSString *filePath = [[NSBundle bundleForClass:self.class] pathForResource:@"amsterdam" ofType:@"geojson"];
NSURL *url = [NSURL fileURLWithPath:filePath];
MGLGeoJSONSource *source = [[MGLGeoJSONSource alloc] initWithIdentifier:@"sourceID" URL:url options:nil];
MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" URL:url options:nil];
[self.mapView.style addSource:source];
MGLLineStyleLayer *layer = [[MGLLineStyleLayer alloc] initWithIdentifier:@"layerID" source:source];
[self.mapView.style addLayer:layer];
@@ -22,7 +26,7 @@
layer.lineRoundLimit = [MGLRuntimeStylingHelper testNumber];
layer.lineBlur = [MGLRuntimeStylingHelper testNumber];
layer.lineColor = [MGLRuntimeStylingHelper testColor];
layer.lineDasharray = [MGLRuntimeStylingHelper testDashArray];
layer.lineDashPattern = [MGLRuntimeStylingHelper testDashArray];
layer.lineGapWidth = [MGLRuntimeStylingHelper testNumber];
layer.lineOffset = [MGLRuntimeStylingHelper testNumber];
layer.lineOpacity = [MGLRuntimeStylingHelper testNumber];
@@ -41,7 +45,7 @@
XCTAssertEqualObjects(gLayer.lineRoundLimit, [MGLRuntimeStylingHelper testNumber]);
XCTAssertEqualObjects(gLayer.lineBlur, [MGLRuntimeStylingHelper testNumber]);
XCTAssertEqualObjects(gLayer.lineColor, [MGLRuntimeStylingHelper testColor]);
XCTAssertEqualObjects(gLayer.lineDasharray, [MGLRuntimeStylingHelper testDashArray]);
XCTAssertEqualObjects(gLayer.lineDashPattern, [MGLRuntimeStylingHelper testDashArray]);
XCTAssertEqualObjects(gLayer.lineGapWidth, [MGLRuntimeStylingHelper testNumber]);
XCTAssertEqualObjects(gLayer.lineOffset, [MGLRuntimeStylingHelper testNumber]);
XCTAssertEqualObjects(gLayer.lineOpacity, [MGLRuntimeStylingHelper testNumber]);
@@ -57,7 +61,7 @@
layer.lineRoundLimit = [MGLRuntimeStylingHelper testNumberFunction];
layer.lineBlur = [MGLRuntimeStylingHelper testNumberFunction];
layer.lineColor = [MGLRuntimeStylingHelper testColorFunction];
layer.lineDasharray = [MGLRuntimeStylingHelper testDashArrayFunction];
layer.lineDashPattern = [MGLRuntimeStylingHelper testDashArrayFunction];
layer.lineGapWidth = [MGLRuntimeStylingHelper testNumberFunction];
layer.lineOffset = [MGLRuntimeStylingHelper testNumberFunction];
layer.lineOpacity = [MGLRuntimeStylingHelper testNumberFunction];
@@ -72,7 +76,7 @@
XCTAssertEqualObjects(gLayer.lineRoundLimit, [MGLRuntimeStylingHelper testNumberFunction]);
XCTAssertEqualObjects(gLayer.lineBlur, [MGLRuntimeStylingHelper testNumberFunction]);
XCTAssertEqualObjects(gLayer.lineColor, [MGLRuntimeStylingHelper testColorFunction]);
XCTAssertEqualObjects(gLayer.lineDasharray, [MGLRuntimeStylingHelper testDashArrayFunction]);
XCTAssertEqualObjects(gLayer.lineDashPattern, [MGLRuntimeStylingHelper testDashArrayFunction]);
XCTAssertEqualObjects(gLayer.lineGapWidth, [MGLRuntimeStylingHelper testNumberFunction]);
XCTAssertEqualObjects(gLayer.lineOffset, [MGLRuntimeStylingHelper testNumberFunction]);
XCTAssertEqualObjects(gLayer.lineOpacity, [MGLRuntimeStylingHelper testNumberFunction]);
@@ -82,4 +86,21 @@
XCTAssertEqualObjects(gLayer.lineWidth, [MGLRuntimeStylingHelper testNumberFunction]);
}
- (void)testPropertyNames {
[self testPropertyName:@"line-cap" isBoolean:NO];
[self testPropertyName:@"line-join" isBoolean:NO];
[self testPropertyName:@"line-miter-limit" isBoolean:NO];
[self testPropertyName:@"line-round-limit" isBoolean:NO];
[self testPropertyName:@"line-blur" isBoolean:NO];
[self testPropertyName:@"line-color" isBoolean:NO];
[self testPropertyName:@"line-dash-pattern" isBoolean:NO];
[self testPropertyName:@"line-gap-width" isBoolean:NO];
[self testPropertyName:@"line-offset" isBoolean:NO];
[self testPropertyName:@"line-opacity" isBoolean:NO];
[self testPropertyName:@"line-pattern" isBoolean:NO];
[self testPropertyName:@"line-translate" isBoolean:NO];
[self testPropertyName:@"line-translate-anchor" isBoolean:NO];
[self testPropertyName:@"line-width" isBoolean:NO];
}
@end

View File

@@ -8,10 +8,14 @@
@implementation MGLRasterLayerTests
+ (NSString *)layerType {
return @"raster";
}
- (void)testRasterLayer {
NSString *filePath = [[NSBundle bundleForClass:self.class] pathForResource:@"amsterdam" ofType:@"geojson"];
NSURL *url = [NSURL fileURLWithPath:filePath];
MGLGeoJSONSource *source = [[MGLGeoJSONSource alloc] initWithIdentifier:@"sourceID" URL:url options:nil];
MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" URL:url options:nil];
[self.mapView.style addSource:source];
MGLRasterStyleLayer *layer = [[MGLRasterStyleLayer alloc] initWithIdentifier:@"layerID" source:source];
[self.mapView.style addLayer:layer];
@@ -20,7 +24,7 @@
layer.minimumRasterBrightness = [MGLRuntimeStylingHelper testNumber];
layer.rasterContrast = [MGLRuntimeStylingHelper testNumber];
layer.rasterFadeDuration = [MGLRuntimeStylingHelper testNumber];
layer.rasterHueRotate = [MGLRuntimeStylingHelper testNumber];
layer.rasterHueRotation = [MGLRuntimeStylingHelper testNumber];
layer.rasterOpacity = [MGLRuntimeStylingHelper testNumber];
layer.rasterSaturation = [MGLRuntimeStylingHelper testNumber];
@@ -30,7 +34,7 @@
XCTAssertEqualObjects(gLayer.minimumRasterBrightness, [MGLRuntimeStylingHelper testNumber]);
XCTAssertEqualObjects(gLayer.rasterContrast, [MGLRuntimeStylingHelper testNumber]);
XCTAssertEqualObjects(gLayer.rasterFadeDuration, [MGLRuntimeStylingHelper testNumber]);
XCTAssertEqualObjects(gLayer.rasterHueRotate, [MGLRuntimeStylingHelper testNumber]);
XCTAssertEqualObjects(gLayer.rasterHueRotation, [MGLRuntimeStylingHelper testNumber]);
XCTAssertEqualObjects(gLayer.rasterOpacity, [MGLRuntimeStylingHelper testNumber]);
XCTAssertEqualObjects(gLayer.rasterSaturation, [MGLRuntimeStylingHelper testNumber]);
@@ -38,7 +42,7 @@
layer.minimumRasterBrightness = [MGLRuntimeStylingHelper testNumberFunction];
layer.rasterContrast = [MGLRuntimeStylingHelper testNumberFunction];
layer.rasterFadeDuration = [MGLRuntimeStylingHelper testNumberFunction];
layer.rasterHueRotate = [MGLRuntimeStylingHelper testNumberFunction];
layer.rasterHueRotation = [MGLRuntimeStylingHelper testNumberFunction];
layer.rasterOpacity = [MGLRuntimeStylingHelper testNumberFunction];
layer.rasterSaturation = [MGLRuntimeStylingHelper testNumberFunction];
@@ -46,9 +50,19 @@
XCTAssertEqualObjects(gLayer.minimumRasterBrightness, [MGLRuntimeStylingHelper testNumberFunction]);
XCTAssertEqualObjects(gLayer.rasterContrast, [MGLRuntimeStylingHelper testNumberFunction]);
XCTAssertEqualObjects(gLayer.rasterFadeDuration, [MGLRuntimeStylingHelper testNumberFunction]);
XCTAssertEqualObjects(gLayer.rasterHueRotate, [MGLRuntimeStylingHelper testNumberFunction]);
XCTAssertEqualObjects(gLayer.rasterHueRotation, [MGLRuntimeStylingHelper testNumberFunction]);
XCTAssertEqualObjects(gLayer.rasterOpacity, [MGLRuntimeStylingHelper testNumberFunction]);
XCTAssertEqualObjects(gLayer.rasterSaturation, [MGLRuntimeStylingHelper testNumberFunction]);
}
- (void)testPropertyNames {
[self testPropertyName:@"maximum-raster-brightness" isBoolean:NO];
[self testPropertyName:@"minimum-raster-brightness" isBoolean:NO];
[self testPropertyName:@"raster-contrast" isBoolean:NO];
[self testPropertyName:@"raster-fade-duration" isBoolean:NO];
[self testPropertyName:@"raster-hue-rotation" isBoolean:NO];
[self testPropertyName:@"raster-opacity" isBoolean:NO];
[self testPropertyName:@"raster-saturation" isBoolean:NO];
}
@end

View File

@@ -2,28 +2,25 @@
#import <Mapbox/Mapbox.h>
#import "MGLFeature_Private.h"
#import "MGLGeoJSONSource_Private.h"
#import "MGLShapeSource_Private.h"
#import "MGLSource_Private.h"
#include <mbgl/style/sources/geojson_source.hpp>
@interface MGLGeoJSONSourceTests : XCTestCase
@interface MGLShapeSourceTests : XCTestCase
@end
@implementation MGLGeoJSONSourceTests
@implementation MGLShapeSourceTests
- (void)testMGLGeoJSONSourceWithOptions {
NSURL *url = [NSURL URLWithString:@"http://www.mapbox.com/source"];
- (void)testGeoJSONOptionsFromDictionary {
NSDictionary *options = @{MGLShapeSourceOptionClustered: @YES,
MGLShapeSourceOptionClusterRadius: @42,
MGLShapeSourceOptionMaximumZoomLevelForClustering: @98,
MGLShapeSourceOptionMaximumZoomLevel: @99,
MGLShapeSourceOptionBuffer: @1976,
MGLShapeSourceOptionSimplificationTolerance: @0.42};
NSDictionary *options = @{MGLGeoJSONSourceOptionClustered: @YES,
MGLGeoJSONSourceOptionClusterRadius: @42,
MGLGeoJSONSourceOptionMaximumZoomLevelForClustering: @98,
MGLGeoJSONSourceOptionMaximumZoomLevel: @99,
MGLGeoJSONSourceOptionBuffer: @1976,
MGLGeoJSONSourceOptionSimplificationTolerance: @0.42};
MGLGeoJSONSource *source = [[MGLGeoJSONSource alloc] initWithIdentifier:@"source-id" URL:url options:options];
auto mbglOptions = [source geoJSONOptions];
auto mbglOptions = MGLGeoJSONOptionsFromDictionary(options);
XCTAssertTrue(mbglOptions.cluster);
XCTAssertEqual(mbglOptions.clusterRadius, 42);
XCTAssertEqual(mbglOptions.clusterMaxZoom, 98);
@@ -31,34 +28,68 @@
XCTAssertEqual(mbglOptions.buffer, 1976);
XCTAssertEqual(mbglOptions.tolerance, 0.42);
options = @{MGLGeoJSONSourceOptionClustered: @"number 1"};
XCTAssertThrows([[MGLGeoJSONSource alloc] initWithIdentifier:@"source-id" URL:url options:options]);
options = @{MGLShapeSourceOptionClustered: @"number 1"};
XCTAssertThrows(MGLGeoJSONOptionsFromDictionary(options));
}
- (void)testMGLGeoJSONSourceWithData {
- (void)testNilShape {
MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"id" shape:nil options:nil];
XCTAssertNil(source.shape);
}
- (void)testMGLShapeSourceWithDataMultipleFeatures {
NSString *geoJSON = @"{\"type\": \"FeatureCollection\",\"features\": [{\"type\": \"Feature\",\"properties\": {},\"geometry\": {\"type\": \"LineString\",\"coordinates\": [[-107.75390625,40.329795743702064],[-104.34814453125,37.64903402157866]]}}]}";
NSData *data = [geoJSON dataUsingEncoding:NSUTF8StringEncoding];
MGLGeoJSONSource *source = [[MGLGeoJSONSource alloc] initWithIdentifier:@"source-id" geoJSONData:data options:nil];
NSError *error;
MGLShape *shape = [MGLShape shapeWithData:data encoding:NSUTF8StringEncoding error:&error];
XCTAssertNil(error);
XCTAssertNotNil(shape);
MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"source-id" shape:shape options:nil];
XCTAssertNotNil(source.features);
XCTAssertEqual(source.features.count, 1);
XCTAssertTrue([source.features.firstObject isMemberOfClass:[MGLPolylineFeature class]]);
MGLShapeCollection *collection = (MGLShapeCollection *)source.shape;
XCTAssertNotNil(collection);
XCTAssertEqual(collection.shapes.count, 1);
XCTAssertTrue([collection.shapes.firstObject isMemberOfClass:[MGLPolylineFeature class]]);
}
- (void)testMGLGeoJSONSourceWithPolylineFeatures {
- (void)testMGLShapeSourceWithSingleGeometry {
NSData *data = [@"{\"type\": \"Point\", \"coordinates\": [0, 0]}" dataUsingEncoding:NSUTF8StringEncoding];
NSError *error;
MGLShape *shape = [MGLShape shapeWithData:data encoding:NSUTF8StringEncoding error:&error];
XCTAssertNil(error);
XCTAssertNotNil(shape);
MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"geojson" shape:shape options:nil];
XCTAssertNotNil(source.shape);
XCTAssert([source.shape isKindOfClass:[MGLPointAnnotation class]]);
}
- (void)testMGLGeoJSONSourceWithSingleFeature {
NSString *geoJSON = @"{\"type\": \"Feature\", \"properties\": {\"color\": \"green\"}, \"geometry\": { \"type\": \"Point\", \"coordinates\": [ -114.06847000122069, 51.050459433092655 ] }}";
NSData *data = [geoJSON dataUsingEncoding:NSUTF8StringEncoding];
NSError *error;
MGLShape *shape = [MGLShape shapeWithData:data encoding:NSUTF8StringEncoding error:&error];
XCTAssertNil(error);
XCTAssertNotNil(shape);
MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"geojson" shape:shape options:nil];
XCTAssertNotNil(source.shape);
XCTAssert([source.shape isKindOfClass:[MGLPointFeature class]]);
MGLPointFeature *feature = (MGLPointFeature *)source.shape;
XCTAssert([feature.attributes.allKeys containsObject:@"color"]);
}
- (void)testMGLShapeSourceWithPolylineFeatures {
CLLocationCoordinate2D coordinates[] = { CLLocationCoordinate2DMake(0, 0), CLLocationCoordinate2DMake(10, 10)};
MGLPolylineFeature *polylineFeature = [MGLPolylineFeature polylineWithCoordinates:coordinates count:2];
MGLGeoJSONSource *source = [[MGLGeoJSONSource alloc] initWithIdentifier:@"source-id" features:@[polylineFeature] options:nil];
MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"source-id" shape:polylineFeature options:nil];
XCTAssertNotNil(source.features);
XCTAssertEqual(source.features.count, 1);
XCTAssertTrue([source.features.firstObject isMemberOfClass:[MGLPolylineFeature class]]);
XCTAssertNotNil(source.shape);
XCTAssertTrue([source.shape isMemberOfClass:[MGLPolylineFeature class]]);
}
- (void)testMGLGeoJSONSourceWithPolygonFeatures {
- (void)testMGLShapeSourceWithPolygonFeatures {
CLLocationCoordinate2D coordinates[] = {
CLLocationCoordinate2DMake(100.0, 0.0),
CLLocationCoordinate2DMake(101.0, 0.0),
@@ -66,7 +97,7 @@
CLLocationCoordinate2DMake(100.0, 1.0),
CLLocationCoordinate2DMake(100.0, 0.0)};
MGLPolygonFeature<MGLFeaturePrivate> *polygonFeature = (MGLPolygonFeature<MGLFeaturePrivate> *)[MGLPolygonFeature polygonWithCoordinates:coordinates count:5];
MGLPolygonFeature *polygonFeature = [MGLPolygonFeature polygonWithCoordinates:coordinates count:5];
polygonFeature.identifier = @"feature-id";
NSString *stringAttribute = @"string";
NSNumber *boolAttribute = [NSNumber numberWithBool:YES];
@@ -88,11 +119,11 @@
@"array-of-array-attribute": arrayOfArrays,
@"array-of-dictionary-attribute": arrayOfDictionaries};
MGLGeoJSONSource *source = [[MGLGeoJSONSource alloc] initWithIdentifier:@"source-id" features:@[polygonFeature] options:nil];
MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"source-id" shape:polygonFeature options:nil];
XCTAssertNotNil(source.features);
XCTAssertEqual(source.features.count, 1);
MGLPolygonFeature *expectedPolygonFeature = (MGLPolygonFeature *)source.features.firstObject;
XCTAssertNotNil(source.shape);
MGLPolygonFeature *expectedPolygonFeature = (MGLPolygonFeature *)source.shape;
XCTAssertEqualObjects(expectedPolygonFeature.identifier, polygonFeature.identifier);
XCTAssertTrue([expectedPolygonFeature isMemberOfClass:[MGLPolygonFeature class]]);
XCTAssertEqualObjects(expectedPolygonFeature.identifier, polygonFeature.identifier);
XCTAssertEqualObjects(expectedPolygonFeature.attributes[@"name"], stringAttribute);
@@ -104,7 +135,7 @@
XCTAssertEqualObjects(expectedPolygonFeature.attributes[@"array-of-dictionary-attribute"], arrayOfDictionaries);
}
- (void)testMGLGeoJSONSourceWithPolygonFeaturesInculdingInteriorPolygons {
- (void)testMGLShapeSourceWithPolygonFeaturesInculdingInteriorPolygons {
CLLocationCoordinate2D coordinates[] = {
CLLocationCoordinate2DMake(100.0, 0.0),
CLLocationCoordinate2DMake(101.0, 0.0),
@@ -123,29 +154,26 @@
MGLPolygonFeature *polygonFeature = [MGLPolygonFeature polygonWithCoordinates:coordinates count:5 interiorPolygons:@[polygon]];
MGLGeoJSONSource *source = [[MGLGeoJSONSource alloc] initWithIdentifier:@"source-id" features:@[polygonFeature] options:nil];
MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"source-id" shape:polygonFeature options:nil];
XCTAssertNotNil(source.features);
XCTAssertEqual(source.features.count, 1);
XCTAssertTrue([source.features.firstObject isMemberOfClass:[MGLPolygonFeature class]]);
XCTAssertNotNil(source.shape);
XCTAssertTrue([source.shape isMemberOfClass:[MGLPolygonFeature class]]);
}
- (void)testMGLGeoJSONSourceWithMultiPolylineFeatures {
- (void)testMGLShapeSourceWithMultiPolylineFeatures {
CLLocationCoordinate2D firstCoordinates[] = { CLLocationCoordinate2DMake(0, 0), CLLocationCoordinate2DMake(10, 10)};
MGLPolylineFeature *firstPolylineFeature = [MGLPolylineFeature polylineWithCoordinates:firstCoordinates count:2];
CLLocationCoordinate2D secondCoordinates[] = { CLLocationCoordinate2DMake(0, 0), CLLocationCoordinate2DMake(10, 10)};
MGLPolylineFeature *secondPolylineFeature = [MGLPolylineFeature polylineWithCoordinates:secondCoordinates count:2];
MGLMultiPolylineFeature *multiPolylineFeature = [MGLMultiPolylineFeature multiPolylineWithPolylines:@[firstPolylineFeature, secondPolylineFeature]];
MGLGeoJSONSource *source = [[MGLGeoJSONSource alloc] initWithIdentifier:@"source-id" features:@[multiPolylineFeature] options:nil];
MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"source-id" shape:multiPolylineFeature options:nil];
XCTAssertNotNil(source.features);
XCTAssertEqual(source.features.count, 1);
XCTAssertTrue([source.features.firstObject isMemberOfClass:[MGLMultiPolylineFeature class]]);
XCTAssertNotNil(source.shape);
XCTAssertTrue([source.shape isMemberOfClass:[MGLMultiPolylineFeature class]]);
}
- (void)testMGLGeoJSONSourceWithMultiPolygonFeatures {
- (void)testMGLShapeSourceWithMultiPolygonFeatures {
CLLocationCoordinate2D coordinates[] = {
CLLocationCoordinate2DMake(100.0, 0.0),
CLLocationCoordinate2DMake(101.0, 0.0),
@@ -167,26 +195,23 @@
MGLMultiPolygonFeature *multiPolygonFeature = [MGLMultiPolygonFeature multiPolygonWithPolygons:@[firstPolygon, secondPolygon]];
MGLGeoJSONSource *source = [[MGLGeoJSONSource alloc] initWithIdentifier:@"source-id" features:@[multiPolygonFeature] options:nil];
MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"source-id" shape:multiPolygonFeature options:nil];
XCTAssertNotNil(source.features);
XCTAssertEqual(source.features.count, 1);
XCTAssertTrue([source.features.firstObject isMemberOfClass:[MGLMultiPolygonFeature class]]);
XCTAssertNotNil(source.shape);
XCTAssertTrue([source.shape isMemberOfClass:[MGLMultiPolygonFeature class]]);
}
- (void)testMGLGeoJSONSourceWithPointFeature {
- (void)testMGLShapeSourceWithPointFeature {
MGLPointFeature *pointFeature = [MGLPointFeature new];
pointFeature.coordinate = CLLocationCoordinate2DMake(100.2, 0.2);
MGLGeoJSONSource *source = [[MGLGeoJSONSource alloc] initWithIdentifier:@"souce-id" features:@[pointFeature] options:nil];
MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"souce-id" shape:pointFeature options:nil];
XCTAssertNotNil(source.features);
XCTAssertEqual(source.features.count, 1);
XCTAssertTrue([source.features.firstObject isMemberOfClass:[MGLPointFeature class]]);
XCTAssertNotNil(source.shape);
XCTAssertTrue([source.shape isMemberOfClass:[MGLPointFeature class]]);
}
- (void)testMGLGeoJSONSourceWithPointCollectionFeature {
- (void)testMGLShapeSourceWithPointCollectionFeature {
CLLocationCoordinate2D coordinates[] = {
CLLocationCoordinate2DMake(100.0, 0.0),
CLLocationCoordinate2DMake(101.0, 0.0),
@@ -194,14 +219,13 @@
CLLocationCoordinate2DMake(100.0, 1.0),
CLLocationCoordinate2DMake(100.0, 0.0)};
MGLPointCollectionFeature *pointCollectionFeature = [MGLPointCollectionFeature pointCollectionWithCoordinates:coordinates count:5];
MGLGeoJSONSource *source = [[MGLGeoJSONSource alloc] initWithIdentifier:@"souce-id" features:@[pointCollectionFeature] options:nil];
MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"souce-id" shape:pointCollectionFeature options:nil];
XCTAssertNotNil(source.features);
XCTAssertEqual(source.features.count, 1);
XCTAssertTrue([source.features.firstObject isMemberOfClass:[MGLPointCollectionFeature class]]);
XCTAssertNotNil(source.shape);
XCTAssertTrue([source.shape isMemberOfClass:[MGLPointCollectionFeature class]]);
}
- (void)testMGLGeoJSONSourceWithShapeCollectionFeatures {
- (void)testMGLShapeSourceWithShapeCollectionFeatures {
CLLocationCoordinate2D coordinates[] = {
CLLocationCoordinate2DMake(100.0, 0.0),
CLLocationCoordinate2DMake(101.0, 0.0),
@@ -234,9 +258,11 @@
MGLShapeCollectionFeature *shapeCollectionFeature = [MGLShapeCollectionFeature shapeCollectionWithShapes:@[polygonFeature, polylineFeature, multiPolygonFeature, multiPolylineFeature, pointCollectionFeature, pointFeature]];
MGLShapeCollectionFeature *shapeCollectionFeature_1 = [MGLShapeCollectionFeature shapeCollectionWithShapes:@[polygonFeature, polylineFeature, multiPolygonFeature, multiPolylineFeature, pointCollectionFeature, pointFeature, shapeCollectionFeature]];
XCTAssertThrowsSpecificNamed([[MGLGeoJSONSource alloc] initWithIdentifier:@"source-id" features:@[shapeCollectionFeature_1] options:nil], NSException, @"Method unavailable");
MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"source-id" shape:shapeCollectionFeature options:nil];
MGLShapeCollectionFeature *shape = (MGLShapeCollectionFeature *)source.shape;
XCTAssertNotNil(shape);
XCTAssert(shape.shapes.count == 6, @"Shape collection should contain 6 shapes");
}
@end

View File

@@ -6,5 +6,15 @@
@property (nonatomic) IBOutlet MGLMapView *mapView;
@property (nonatomic) XCTestExpectation *expectation;
@property (nonatomic, copy, readonly, class) NSString *layerType;
- (void)testPropertyName:(NSString *)name isBoolean:(BOOL)isBoolean;
@end
@interface NSString (MGLStyleLayerTestAdditions)
@property (nonatomic, readonly, copy) NS_ARRAY_OF(NSString *) *lexicalClasses;
@property (nonatomic, readonly, copy) NSString *lemma;
@end

View File

@@ -1,7 +1,13 @@
#import "MGLStyleLayerTests.h"
#import "NSString+MGLAdditions.h"
#define TEST_STRICT_NAMING_CONVENTIONS 0
@implementation MGLStyleLayerTests
@dynamic layerType;
- (void)setUp {
[super setUp];
#if TARGET_OS_IPHONE
@@ -19,4 +25,65 @@
#endif
}
- (void)testPropertyName:(NSString *)name isBoolean:(BOOL)isBoolean {
NS_MUTABLE_ARRAY_OF(NSString *) *components = [name componentsSeparatedByString:@"-"].mutableCopy;
if (isBoolean) {
if ([components.firstObject isEqualToString:@"is"]) {
[components removeObjectAtIndex:0];
if (![components.lastObject.lexicalClasses containsObject:NSLinguisticTagAdjective]) {
XCTAssertTrue([components.lastObject.lexicalClasses containsObject:NSLinguisticTagVerb],
@"Boolean getter %@ that starts with “is” should contain an adjective, past participle, or verb.", name);
XCTAssertNotEqualObjects(components.lastObject.lemma, components.lastObject,
@"Boolean getter %@ should not have infinitive, imperative, or present tense verb.", name);
}
} else {
if ([components.firstObject isEqualToString:[self class].layerType]
|| [components.firstObject isEqualToString:@"icon"] || [components.firstObject isEqualToString:@"text"]) {
[components removeObjectAtIndex:0];
}
#if TEST_STRICT_NAMING_CONVENTIONS
XCTAssertTrue([components.firstObject.lexicalClasses containsObject:NSLinguisticTagVerb],
@"Boolean getter %@ that doesn’t start with “is” should contain a verb.", name);
XCTAssertNotEqualObjects(components.firstObject.lemma, components.lastObject);
#endif
}
} else {
XCTAssertFalse([components.firstObject isEqualToString:@"is"]);
#if TEST_STRICT_NAMING_CONVENTIONS
XCTAssertTrue([components.lastObject.lexicalClasses containsObject:NSLinguisticTagNoun],
@"Non-Boolean getter %@ should contain a noun.", name);
#endif
}
}
@end
@implementation NSString (MGLStyleLayerTestAdditions)
- (NS_ARRAY_OF(NSString *) *)lexicalClasses {
NSOrthography *orthography = [NSOrthography orthographyWithDominantScript:@"Latn"
languageMap:@{@"Latn": @[@"en"]}];
NSLinguisticTaggerOptions options = (NSLinguisticTaggerOmitPunctuation
| NSLinguisticTaggerOmitWhitespace
| NSLinguisticTaggerOmitOther);
return [self linguisticTagsInRange:self.mgl_wholeRange
scheme:NSLinguisticTagSchemeLexicalClass
options:options
orthography:orthography
tokenRanges:NULL];
}
- (NSString *)lemma {
NSOrthography *orthography = [NSOrthography orthographyWithDominantScript:@"Latn"
languageMap:@{@"Latn": @[@"en"]}];
NSLinguisticTaggerOptions options = (NSLinguisticTaggerOmitPunctuation
| NSLinguisticTaggerOmitWhitespace
| NSLinguisticTaggerOmitOther);
return [self linguisticTagsInRange:self.mgl_wholeRange
scheme:NSLinguisticTagSchemeLemma
options:options
orthography:orthography
tokenRanges:NULL].firstObject;
}
@end

View File

@@ -13,13 +13,17 @@
@implementation MGL<%- camelize(type) %>LayerTests
+ (NSString *)layerType {
return @"<%- type %>";
}
- (void)test<%- camelize(type) %>Layer {
<% if (type === 'background') { -%>
MGL<%- camelize(type) %>StyleLayer *layer = [[MGL<%- camelize(type) %>StyleLayer alloc] initWithIdentifier:@"layerID"];
<% } else { -%>
NSString *filePath = [[NSBundle bundleForClass:self.class] pathForResource:@"amsterdam" ofType:@"geojson"];
NSURL *url = [NSURL fileURLWithPath:filePath];
MGLGeoJSONSource *source = [[MGLGeoJSONSource alloc] initWithIdentifier:@"sourceID" URL:url options:nil];
MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" URL:url options:nil];
[self.mapView.style addSource:source];
MGL<%- camelize(type) %>StyleLayer *layer = [[MGL<%- camelize(type) %>StyleLayer alloc] initWithIdentifier:@"layerID" source:source];
<% } -%>
@@ -56,4 +60,13 @@
<% } -%>
}
- (void)testPropertyNames {
<% for (const property of layoutProperties) { -%>
[self testPropertyName:@"<%- property.getter || property.name %>" isBoolean:<%- property.type === 'boolean' ? 'YES' : 'NO' %>];
<% } -%>
<% for (const property of paintProperties) { -%>
[self testPropertyName:@"<%- property.getter || property.name %>" isBoolean:<%- property.type === 'boolean' ? 'YES' : 'NO' %>];
<% } -%>
}
@end

View File

@@ -1,10 +1,7 @@
#import "MGLMapView.h"
#import "MGLStyle_Private.h"
#if TARGET_OS_IPHONE
#import "MGLMapView+MGLCustomStyleLayerAdditions.h"
#endif
#import "MGLGeoJSONSource.h"
#import "MGLShapeSource.h"
#import "MGLRasterSource.h"
#import "MGLVectorSource.h"
@@ -12,6 +9,7 @@
#import "MGLCircleStyleLayer.h"
#import "MGLFillStyleLayer.h"
#import "MGLLineStyleLayer.h"
#import "MGLOpenGLStyleLayer.h"
#import "MGLRasterStyleLayer.h"
#import "MGLSymbolStyleLayer.h"
@@ -20,6 +18,11 @@
#import <mbgl/util/default_styles.hpp>
#import <XCTest/XCTest.h>
#if TARGET_OS_IPHONE
#import <UIKit/UIKit.h>
#else
#import <Cocoa/Cocoa.h>
#endif
#import <objc/runtime.h>
@interface MGLStyleTests : XCTestCase
@@ -119,29 +122,29 @@
}
- (void)testAddingSourcesTwice {
MGLGeoJSONSource *geoJSONSource = [[MGLGeoJSONSource alloc] initWithIdentifier:@"geoJSONSource" features:@[] options:nil];
[self.style addSource:geoJSONSource];
XCTAssertThrowsSpecificNamed([self.style addSource:geoJSONSource], NSException, @"MGLRedundantSourceException");
MGLShapeSource *shapeSource = [[MGLShapeSource alloc] initWithIdentifier:@"shapeSource" shape:nil options:nil];
[self.style addSource:shapeSource];
XCTAssertThrowsSpecificNamed([self.style addSource:shapeSource], NSException, @"MGLRedundantSourceException");
MGLRasterSource *rasterSource = [[MGLRasterSource alloc] initWithIdentifier:@"rasterSource" URL:[NSURL new] tileSize:42];
MGLRasterSource *rasterSource = [[MGLRasterSource alloc] initWithIdentifier:@"rasterSource" configurationURL:[NSURL URLWithString:@".json"] tileSize:42];
[self.style addSource:rasterSource];
XCTAssertThrowsSpecificNamed([self.style addSource:rasterSource], NSException, @"MGLRedundantSourceException");
MGLVectorSource *vectorSource = [[MGLVectorSource alloc] initWithIdentifier:@"vectorSource" URL:[NSURL new]];
MGLVectorSource *vectorSource = [[MGLVectorSource alloc] initWithIdentifier:@"vectorSource" configurationURL:[NSURL URLWithString:@".json"]];
[self.style addSource:vectorSource];
XCTAssertThrowsSpecificNamed([self.style addSource:vectorSource], NSException, @"MGLRedundantSourceException");
}
- (void)testAddingSourcesWithDuplicateIdentifiers {
MGLVectorSource *source1 = [[MGLVectorSource alloc] initWithIdentifier:@"my-source" URL:[NSURL URLWithString:@"mapbox://mapbox.mapbox-terrain-v2"]];
MGLVectorSource *source2 = [[MGLVectorSource alloc] initWithIdentifier:@"my-source" URL:[NSURL URLWithString:@"mapbox://mapbox.mapbox-terrain-v2"]];
MGLVectorSource *source1 = [[MGLVectorSource alloc] initWithIdentifier:@"my-source" configurationURL:[NSURL URLWithString:@"mapbox://mapbox.mapbox-terrain-v2"]];
MGLVectorSource *source2 = [[MGLVectorSource alloc] initWithIdentifier:@"my-source" configurationURL:[NSURL URLWithString:@"mapbox://mapbox.mapbox-terrain-v2"]];
[self.style addSource: source1];
XCTAssertThrowsSpecificNamed([self.style addSource: source2], NSException, @"MGLRedundantSourceIdentiferException");
XCTAssertThrowsSpecificNamed([self.style addSource: source2], NSException, @"MGLRedundantSourceIdentifierException");
}
- (void)testAddingLayersTwice {
MGLGeoJSONSource *source = [[MGLGeoJSONSource alloc] initWithIdentifier:@"geoJSONSource" features:@[] options:nil];
MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"shapeSource" shape:nil options:nil];
MGLBackgroundStyleLayer *backgroundLayer = [[MGLBackgroundStyleLayer alloc] initWithIdentifier:@"backgroundLayer"];
[self.style addLayer:backgroundLayer];
@@ -170,7 +173,7 @@
- (void)testAddingLayersWithDuplicateIdentifiers {
//Just some source
MGLVectorSource *source = [[MGLVectorSource alloc] initWithIdentifier:@"my-source" URL:[NSURL URLWithString:@"mapbox://mapbox.mapbox-terrain-v2"]];
MGLVectorSource *source = [[MGLVectorSource alloc] initWithIdentifier:@"my-source" configurationURL:[NSURL URLWithString:@"mapbox://mapbox.mapbox-terrain-v2"]];
[self.mapView.style addSource: source];
//Add initial layer
@@ -182,14 +185,7 @@
XCTAssertThrowsSpecificNamed([self.mapView.style insertLayer:[[MGLFillStyleLayer alloc] initWithIdentifier:@"my-layer" source:source] belowLayer:initial],NSException, @"MGLRedundantLayerIdentifierException");
XCTAssertThrowsSpecificNamed([self.mapView.style insertLayer:[[MGLFillStyleLayer alloc] initWithIdentifier:@"my-layer" source:source] aboveLayer:initial], NSException, @"MGLRedundantLayerIdentifierException");
XCTAssertThrowsSpecificNamed([self.mapView.style insertLayer:[[MGLFillStyleLayer alloc] initWithIdentifier:@"my-layer" source:source] atIndex:0], NSException, @"MGLRedundantLayerIdentifierException");
#if TARGET_OS_IPHONE
//Try to insert a duplicate custom layer
MGLCustomStyleLayerDrawingHandler drawingHandler = ^(CGSize size, CLLocationCoordinate2D centerCoordinate, double zoomLevel, CLLocationDirection direction, CGFloat pitch, CGFloat perspectiveSkew) {
};
XCTAssertThrowsSpecific([self.mapView insertCustomStyleLayerWithIdentifier:@"my-layer" preparationHandler:^{} drawingHandler:drawingHandler completionHandler: ^{} belowStyleLayerWithIdentifier:nil], NSException);
#endif
XCTAssertThrowsSpecificNamed([self.mapView.style insertLayer:[[MGLOpenGLStyleLayer alloc] initWithIdentifier:@"my-layer"] atIndex:0], NSException, @"MGLRedundantLayerIdentifierException");
}
- (NSString *)stringWithContentsOfStyleHeader {
@@ -202,4 +198,23 @@
return styleHeader;
}
- (void)testImages {
NSString *imageName = @"TrackingLocationMask";
#if TARGET_OS_IPHONE
MGLImage *image = [MGLImage imageNamed:imageName
inBundle:[NSBundle bundleForClass:[self class]]
compatibleWithTraitCollection:nil];
#else
MGLImage *image = [[NSBundle bundleForClass:[self class]] imageForResource:imageName];
#endif
XCTAssertNotNil(image);
[self.mapView.style setImage:image forName:imageName];
MGLImage *styleImage = [self.mapView.style imageForName:imageName];
XCTAssertNotNil(styleImage);
XCTAssertEqual(image.size.width, styleImage.size.width);
XCTAssertEqual(image.size.height, styleImage.size.height);
}
@end

View File

@@ -0,0 +1,4 @@
#import <XCTest/XCTest.h>
@interface MGLStyleValueTests : XCTestCase
@end

View File

@@ -0,0 +1,13 @@
#import <XCTest/XCTest.h>
#import <Mapbox/Mapbox.h>
@interface MGLStyleValueTests : XCTestCase
@end
@implementation MGLStyleValueTests
- (void)testStoplessFunction {
XCTAssertThrowsSpecificNamed([MGLStyleValue<NSNumber *> valueWithStops:@{}], NSException, NSInvalidArgumentException, @"Stopless function should raise an exception");
}
@end

Some files were not shown because too many files have changed in this diff Show More