Ticket #13124: josm_ticket_13124_gpx_heat_map_by_kidelo.patch
File josm_ticket_13124_gpx_heat_map_by_kidelo.patch, 62.8 KB (added by , 7 years ago) |
---|
-
src/org/openstreetmap/josm/gui/layer/gpx/GpxDrawHelper.java
4 4 import static org.openstreetmap.josm.tools.I18n.marktr; 5 5 import static org.openstreetmap.josm.tools.I18n.tr; 6 6 7 import java.awt.AlphaComposite; 7 8 import java.awt.BasicStroke; 8 9 import java.awt.Color; 10 import java.awt.Composite; 9 11 import java.awt.Graphics2D; 12 import java.awt.LinearGradientPaint; 13 import java.awt.MultipleGradientPaint; 14 import java.awt.Paint; 10 15 import java.awt.Point; 16 import java.awt.Rectangle; 11 17 import java.awt.RenderingHints; 12 18 import java.awt.Stroke; 19 import java.awt.image.BufferedImage; 20 import java.awt.image.DataBufferInt; 21 import java.awt.image.Raster; 13 22 import java.util.ArrayList; 14 23 import java.util.Arrays; 15 24 import java.util.Collection; 16 25 import java.util.Collections; 17 26 import java.util.Date; 27 import java.util.LinkedList; 18 28 import java.util.List; 19 29 20 30 import org.openstreetmap.josm.Main; … … 28 38 import org.openstreetmap.josm.data.preferences.ColorProperty; 29 39 import org.openstreetmap.josm.gui.MapView; 30 40 import org.openstreetmap.josm.tools.ColorScale; 41 import org.openstreetmap.josm.tools.Utils; 31 42 32 43 /** 33 44 * Class that helps to draw large set of GPS tracks with different colors and options … … 45 56 46 57 // draw lines between points belonging to different segments 47 58 private boolean forceLines; 59 // use alpha blending for line draw 60 private boolean alphaLines; 48 61 // draw direction arrows on the lines 49 62 private boolean direction; 50 /** don't draw lines if longer than x meters**/63 /** width of line for paint **/ 51 64 private int lineWidth; 65 /** don't draw lines if longer than x meters **/ 52 66 private int maxLineLength; 67 // draw lines 53 68 private boolean lines; 54 69 /** paint large dots for points **/ 55 70 private boolean large; … … 73 88 private boolean computeCacheColorDynamic; 74 89 private ColorMode computeCacheColored; 75 90 private int computeCacheColorTracksTune; 91 private int computeCacheHeatMapDrawColorTableIdx; 76 92 77 93 //// Color-related fields 78 94 /** Mode of the line coloring **/ … … 104 120 {+ll0, -sl4, +sl4, -ll0}, {+ll0, +sl9, +ll0, -sl9} 105 121 }; 106 122 123 /** heat map parameters **/ 124 125 // enabled or not (override by settings) 126 private boolean heatMapEnabled = false; 127 // draw small extra line 128 private boolean heatMapDrawExtraLine = false; 129 // used index for color table (parameter) 130 private int heatMapDrawColorTableIdx = 0; 131 132 // normal buffered image and draw object (cached) 133 private BufferedImage heatMapImgGray = null; 134 private Graphics2D heatMapGraph2d = null; 135 136 // some cached values 137 Rectangle heatMapCacheScreenBounds = new Rectangle(); 138 int heatMapCacheVisibleSegments = 0; 139 double heatMapCacheZoomScale = 0; 140 int heatMapCacheLineWith = 0; 141 142 // copied value for line drawing 143 private List<Integer> heatMapPolyX = new ArrayList<Integer>(); 144 private List<Integer> heatMapPolyY = new ArrayList<Integer>(); 145 146 // based on color map aka inferno with adjustment to more brighter values 147 // Used to reconstruct the colormap in viscm (http://bids.github.io/colormap/) 148 // parameters = {'xp': [-2.059155383623448, 55.527989656842408, 34.409268195655187, 4.76708575112832, -9.505963894261754}, 149 // 'yp': [-25.66489361702122, -20.376712328767127, 26.997716894977174, 20.56737588652487, 32.047872340425585}, 150 // 'min_Jp': 33.3692722372, 151 // 'max_Jp': 95} 152 private static final double[][] colorMapJosmInfernoBright = { 153 {0.21520753, 0.27038249, 0.57012105}, 154 {0.22312459, 0.27103303, 0.57166455}, 155 {0.23080347, 0.27168503, 0.57324007}, 156 {0.23833063, 0.27231877, 0.57483869}, 157 {0.24568074, 0.27294692, 0.57646522}, 158 {0.25289476, 0.2735611, 0.57811579}, 159 {0.25997831, 0.27416334, 0.57979067}, 160 {0.2669379, 0.27475519, 0.58148978}, 161 {0.27380298, 0.27532947, 0.58321}, 162 {0.28055428, 0.27589622, 0.58495399}, 163 {0.287239, 0.2764405, 0.58671621}, 164 {0.29381911, 0.27697939, 0.58850116}, 165 {0.30035424, 0.27749166, 0.59030167}, 166 {0.3067935, 0.27799996, 0.59212335}, 167 {0.31320428, 0.2784783, 0.59395808}, 168 {0.31952836, 0.27895311, 0.59581191}, 169 {0.32583529, 0.27939586, 0.59767646}, 170 {0.3320659, 0.27983431, 0.59955752}, 171 {0.33828602, 0.28023999, 0.60144712}, 172 {0.34443919, 0.2806404, 0.60335045}, 173 {0.35058925, 0.28100652, 0.60525968}, 174 {0.35668082, 0.28136625, 0.60717967}, 175 {0.36277287, 0.28169157, 0.60910303}, 176 {0.3688165, 0.28200806, 0.61103375}, 177 {0.37486069, 0.28229156, 0.61296536}, 178 {0.38086771, 0.28256263, 0.61490057}, 179 {0.38687304, 0.28280326, 0.61683417}, 180 {0.39285321, 0.28302691, 0.61876728}, 181 {0.39882725, 0.28322388, 0.6206963}, 182 {0.40478897, 0.28339829, 0.62262037}, 183 {0.41073803, 0.28355108, 0.62453795}, 184 {0.41668846, 0.28367469, 0.62644568}, 185 {0.42261777, 0.28378305, 0.62834468}, 186 {0.42856299, 0.28385455, 0.63022847}, 187 {0.43448626, 0.28391267, 0.63210021}, 188 {0.44042184, 0.28393692, 0.63395343}, 189 {0.44634815, 0.28394123, 0.63578925}, 190 {0.45227252, 0.28392157, 0.63760476}, 191 {0.45820558, 0.28387152, 0.63939628}, 192 {0.46412436, 0.28380662, 0.6411656}, 193 {0.47006356, 0.28370439, 0.64290476}, 194 {0.47599406, 0.28358471, 0.64461676}, 195 {0.48192565, 0.28344156, 0.64629781}, 196 {0.48786962, 0.28326756, 0.64794343}, 197 {0.49380435, 0.28307827, 0.64955593}, 198 {0.49975251, 0.28285825, 0.65112821}, 199 {0.50570289, 0.28261587, 0.65266041}, 200 {0.51164619, 0.2823585, 0.65415271}, 201 {0.51760901, 0.28206718, 0.65559589}, 202 {0.52356861, 0.28175913, 0.65699349}, 203 {0.52952249, 0.28143693, 0.65834417}, 204 {0.5354961, 0.28108192, 0.65963775}, 205 {0.54146547, 0.28071283, 0.66087903}, 206 {0.54742976, 0.28033111, 0.66206616}, 207 {0.55340844, 0.27992224, 0.66318972}, 208 {0.55938599, 0.27949898, 0.66425255}, 209 {0.56535835, 0.27906539, 0.66525388}, 210 {0.57133473, 0.2786149, 0.66618743}, 211 {0.57731677, 0.27814689, 0.66704956}, 212 {0.58329279, 0.27767173, 0.66784277}, 213 {0.58926275, 0.27719044, 0.66856469}, 214 {0.59523878, 0.27669389, 0.66920646}, 215 {0.601212, 0.27619042, 0.66976956}, 216 {0.60717734, 0.27568537, 0.67025404}, 217 {0.61313444, 0.27518023, 0.67065755}, 218 {0.6190896, 0.27467077, 0.67097344}, 219 {0.62504118, 0.27415958, 0.67119949}, 220 {0.63098171, 0.27365438, 0.67133763}, 221 {0.63691049, 0.27315721, 0.67138563}, 222 {0.64282668, 0.27267021, 0.67134132}, 223 {0.64873334, 0.2721922, 0.67119941}, 224 {0.65463011, 0.27172501, 0.67095685}, 225 {0.66051031, 0.27127617, 0.67061602}, 226 {0.66637279, 0.27084839, 0.67017505}, 227 {0.67221629, 0.27044454, 0.66963216}, 228 {0.67803951, 0.27006762, 0.66898569}, 229 {0.68384101, 0.26972075, 0.66823411}, 230 {0.68962043, 0.2694062, 0.66737478}, 231 {0.69537788, 0.26912584, 0.66640432}, 232 {0.70110815, 0.26888634, 0.66532544}, 233 {0.70680955, 0.26869125, 0.66413723}, 234 {0.71248034, 0.26854423, 0.66283897}, 235 {0.71811869, 0.26844898, 0.66143017}, 236 {0.72372274, 0.26840929, 0.6599105}, 237 {0.72929057, 0.26842895, 0.65827991}, 238 {0.7348202, 0.26851179, 0.65653854}, 239 {0.74030966, 0.26866163, 0.65468679}, 240 {0.74575692, 0.26888225, 0.65272532}, 241 {0.75115994, 0.26917738, 0.65065505}, 242 {0.75651668, 0.26955067, 0.64847715}, 243 {0.76182512, 0.27000568, 0.64619309}, 244 {0.76708321, 0.27054582, 0.64380458}, 245 {0.77228898, 0.27117434, 0.64131363}, 246 {0.77744045, 0.27189431, 0.63872252}, 247 {0.78253571, 0.27270861, 0.63603377}, 248 {0.7875729, 0.27361986, 0.63325018}, 249 {0.79255022, 0.27463045, 0.6303748}, 250 {0.79746596, 0.27574247, 0.62741092}, 251 {0.80231908, 0.27695738, 0.62436032}, 252 {0.80710794, 0.27827681, 0.62122676}, 253 {0.81183046, 0.27970239, 0.6180159}, 254 {0.8164853, 0.28123501, 0.61473188}, 255 {0.82107123, 0.28287522, 0.611379}, 256 {0.82558714, 0.28462328, 0.60796168}, 257 {0.83003205, 0.28647909, 0.60448445}, 258 {0.8344051, 0.28844227, 0.60095193}, 259 {0.83870608, 0.29051198, 0.59736649}, 260 {0.84293394, 0.29268742, 0.59373445}, 261 {0.84708799, 0.29496738, 0.59006162}, 262 {0.8511679, 0.29735032, 0.58635274}, 263 {0.85517346, 0.29983446, 0.58261253}, 264 {0.85910459, 0.30241779, 0.57884566}, 265 {0.86296154, 0.30509821, 0.57505503}, 266 {0.8667442, 0.30787334, 0.57124668}, 267 {0.87045278, 0.31074062, 0.56742555}, 268 {0.87408763, 0.3136974, 0.5635959}, 269 {0.87764922, 0.31674094, 0.55976186}, 270 {0.88113814, 0.31986844, 0.55592693}, 271 {0.88455499, 0.32307701, 0.55209513}, 272 {0.88790044, 0.32636363, 0.54827073}, 273 {0.89117526, 0.32972536, 0.54445721}, 274 {0.89438031, 0.33315921, 0.54065783}, 275 {0.89751647, 0.33666226, 0.53687571}, 276 {0.90058468, 0.34023153, 0.53311396}, 277 {0.90358593, 0.34386414, 0.52937539}, 278 {0.90652122, 0.34755725, 0.52566255}, 279 {0.90939159, 0.35130809, 0.5219778}, 280 {0.91219812, 0.35511391, 0.51832354}, 281 {0.91494189, 0.35897199, 0.51470218}, 282 {0.91762398, 0.36287988, 0.51111515}, 283 {0.92024546, 0.36683514, 0.50756411}, 284 {0.92280743, 0.3708354, 0.50405059}, 285 {0.92531095, 0.37487835, 0.5005761}, 286 {0.92775723, 0.37896156, 0.49714278}, 287 {0.93014721, 0.38308319, 0.4937508}, 288 {0.93248195, 0.38724127, 0.49040111}, 289 {0.93476246, 0.3914339, 0.48709457}, 290 {0.93698975, 0.39565929, 0.48383192}, 291 {0.93916494, 0.39991543, 0.48061464}, 292 {0.94128894, 0.40420083, 0.47744286}, 293 {0.94336261, 0.40851411, 0.47431661}, 294 {0.94538686, 0.4128538, 0.47123623}, 295 {0.94736256, 0.41721856, 0.468202}, 296 {0.94929056, 0.42160708, 0.46521414}, 297 {0.95117192, 0.42601776, 0.46227381}, 298 {0.95300724, 0.4304498, 0.45938022}, 299 {0.95479724, 0.43490219, 0.4565332}, 300 {0.95654264, 0.43937392, 0.45373274}, 301 {0.95824414, 0.44386407, 0.45097877}, 302 {0.95990241, 0.44837175, 0.44827118}, 303 {0.96151825, 0.45289592, 0.44561039}, 304 {0.96309223, 0.45743586, 0.44299605}, 305 {0.9646248, 0.46199106, 0.44042751}, 306 {0.96611649, 0.46656086, 0.43790454}, 307 {0.96756782, 0.47114466, 0.43542688}, 308 {0.96897927, 0.47574187, 0.43299428}, 309 {0.9703513, 0.48035197, 0.43060645}, 310 {0.97168455, 0.48497424, 0.42826362}, 311 {0.9729793, 0.48960837, 0.42596514}, 312 {0.97423583, 0.49425407, 0.42371048}, 313 {0.97545448, 0.49891094, 0.42149932}, 314 {0.97663559, 0.50357865, 0.41933134}, 315 {0.97777945, 0.50825686, 0.41720624}, 316 {0.97888633, 0.51294528, 0.41512369}, 317 {0.97995654, 0.5176436, 0.41308347}, 318 {0.98099046, 0.52235141, 0.41108558}, 319 {0.98198808, 0.5270687, 0.40912927}, 320 {0.98294961, 0.53179527, 0.40721424}, 321 {0.98387521, 0.53653092, 0.40534022}, 322 {0.98476504, 0.54127549, 0.40350692}, 323 {0.98561924, 0.54602881, 0.40171405}, 324 {0.98643793, 0.55079072, 0.39996136}, 325 {0.98722122, 0.55556111, 0.3982486}, 326 {0.98796936, 0.5603397, 0.39657571}, 327 {0.98868226, 0.56512655, 0.39494219}, 328 {0.98936, 0.56992153, 0.3933478}, 329 {0.99000264, 0.57472455, 0.39179229}, 330 {0.99061026, 0.57953551, 0.39027544}, 331 {0.99118291, 0.5843543, 0.38879701}, 332 {0.99172063, 0.58918085, 0.38735678}, 333 {0.99222348, 0.59401505, 0.38595451}, 334 {0.99269152, 0.59885681, 0.38458997}, 335 {0.99312476, 0.60370607, 0.38326287}, 336 {0.99352325, 0.60856274, 0.38197295}, 337 {0.99388704, 0.61342672, 0.38071994}, 338 {0.9942162, 0.61829793, 0.37950355}, 339 {0.9945108, 0.62317625, 0.37832349}, 340 {0.99477091, 0.62806159, 0.37717942}, 341 {0.99499662, 0.63295383, 0.376071}, 342 {0.99518804, 0.63785286, 0.37499782}, 343 {0.99534511, 0.64275869, 0.37395927}, 344 {0.99546806, 0.64767111, 0.372955}, 345 {0.99555705, 0.65258996, 0.37198453}, 346 {0.99561226, 0.65751512, 0.37104728}, 347 {0.99563387, 0.66244643, 0.37014263}, 348 {0.99562207, 0.66738375, 0.36926988}, 349 {0.99557709, 0.6723269, 0.36842829}, 350 {0.99549919, 0.67727574, 0.367617}, 351 {0.99538832, 0.68223028, 0.3668348}, 352 {0.99524486, 0.6871903, 0.36608079}, 353 {0.99506928, 0.69215551, 0.36535402}, 354 {0.99486193, 0.69712571, 0.36465327}, 355 {0.99462316, 0.70210071, 0.36397724}, 356 {0.99435337, 0.70708033, 0.36332451}, 357 {0.99405297, 0.71206436, 0.36269354}, 358 {0.99372226, 0.7170527, 0.36208252}, 359 {0.99336115, 0.72204548, 0.36148919}, 360 {0.99297075, 0.72704212, 0.36091215}, 361 {0.99255157, 0.73204239, 0.36034933}, 362 {0.99210417, 0.7370461, 0.35979848}, 363 {0.9916291, 0.74205305, 0.35925722}, 364 {0.99112697, 0.74706302, 0.35872299}, 365 {0.99059766, 0.75207625, 0.35819249}, 366 {0.99004191, 0.75709248, 0.3576629}, 367 {0.98946091, 0.76211118, 0.35713157}, 368 {0.98885534, 0.76713218, 0.35659523}, 369 {0.98822592, 0.77215526, 0.3560504}, 370 {0.98757341, 0.77718026, 0.35549344}, 371 {0.98689724, 0.78220771, 0.35491939}, 372 {0.98619894, 0.78723702, 0.35432474}, 373 {0.98547981, 0.79226775, 0.35370552}, 374 {0.98474069, 0.79729971, 0.35305716}, 375 {0.98398247, 0.80233272, 0.35237485}, 376 {0.98320475, 0.80736733, 0.3516524}, 377 {0.98240874, 0.81240322, 0.35088461}, 378 {0.9815964, 0.81743967, 0.35006665}, 379 {0.9807688, 0.8224765, 0.34919255}, 380 {0.97992705, 0.82751352, 0.34825605}, 381 {0.97906945, 0.83255201, 0.34724796}, 382 {0.97819995, 0.83759034, 0.34616365}, 383 {0.97731989, 0.84262826, 0.34499577}, 384 {0.97643067, 0.84766553, 0.34373656}, 385 {0.97553084, 0.85270337, 0.34237486}, 386 {0.9746244, 0.85774026, 0.34090421}, 387 {0.97371347, 0.86277567, 0.3393158}, 388 {0.97279937, 0.8678095, 0.33759927}, 389 {0.97188135, 0.87284272, 0.33574113}, 390 {0.97096472, 0.87787333, 0.33373367}, 391 {0.97005177, 0.88290083, 0.33156512}, 392 {0.96914211, 0.88792612, 0.3292193}, 393 {0.9682402, 0.89294775, 0.32668465}, 394 {0.96735004, 0.89796453, 0.32394813}, 395 {0.96647255, 0.90297683, 0.32099108}, 396 {0.96561166, 0.9079836, 0.31779718}, 397 {0.96477281, 0.91298312, 0.31435094}, 398 {0.96395774, 0.91797553, 0.31062911}, 399 {0.96317157, 0.92295935, 0.30661145}, 400 {0.96242046, 0.92793272, 0.30227735}, 401 {0.96170672, 0.93289563, 0.29759626}, 402 {0.96103783, 0.93784572, 0.29254395}, 403 {0.96041973, 0.94278138, 0.2870899}, 404 {0.95985661, 0.94770189, 0.28119495}, 405 {0.95935719, 0.95260448, 0.27482525}, 406 {0.95892721, 0.9574878, 0.26793369}, 407 {0.95857402, 0.9623498, 0.2604697}, 408 {0.9583055, 0.96718821, 0.25237504} 409 410 }; // end of colorMapJosmInfernoBright 411 412 // Used to reconstruct the colormap in viscm (http://bids.github.io/colormap/) 413 // {'xp': [-8.9697272381347659, -14.962877923066287, -32.371553722153038, -30.373836827175865, -6.9720103431575922, -8.684339110280888}, 414 // 'yp': [-25.513698630136986, 15.296803652968038, -30.650684931506845, 20.719178082191775, 25.570776255707756, 32.990867579908667}, 415 // 'min_Jp': 33.3692722372, 416 // 'max_Jp': 95} 417 private static final double[][] colorMapJosmViridisBright = { 418 {0.0331179, 0.29975688, 0.57579112}, 419 {0.04256739, 0.3028265, 0.57286799}, 420 {0.0512467, 0.30584793, 0.57009011}, 421 {0.05914659, 0.30882508, 0.5674503}, 422 {0.06654831, 0.3117815, 0.5647918}, 423 {0.07345228, 0.31469781, 0.56227052}, 424 {0.07995739, 0.31757925, 0.55986398}, 425 {0.08619278, 0.32044241, 0.55745447}, 426 {0.09212195, 0.32327213, 0.55517502}, 427 {0.09780928, 0.32607626, 0.55297584}, 428 {0.10331033, 0.32886259, 0.55080222}, 429 {0.10859491, 0.33162106, 0.54875221}, 430 {0.11372563, 0.33436292, 0.54673886}, 431 {0.11870231, 0.33708616, 0.54479015}, 432 {0.12351267, 0.33978626, 0.54295921}, 433 {0.12822783, 0.3424784, 0.541114}, 434 {0.13279867, 0.34515022, 0.53938101}, 435 {0.13725748, 0.34780851, 0.53770555}, 436 {0.14161799, 0.35045603, 0.53606914}, 437 {0.14585622, 0.3530865, 0.53454415}, 438 {0.15002582, 0.35571293, 0.5330082}, 439 {0.15408488, 0.35832466, 0.5315781}, 440 {0.15806357, 0.36092928, 0.53018482}, 441 {0.16195691, 0.36352554, 0.52884943}, 442 {0.16576237, 0.36611275, 0.52758751}, 443 {0.16949979, 0.36869662, 0.52634711}, 444 {0.1731454, 0.37127046, 0.52520656}, 445 {0.17673382, 0.37384485, 0.52406183}, 446 {0.18023309, 0.37641026, 0.52302135}, 447 {0.18367353, 0.37897678, 0.5219859}, 448 {0.18703181, 0.38153698, 0.52104134}, 449 {0.19032855, 0.38409867, 0.52011314}, 450 {0.19354787, 0.38665632, 0.5192658}, 451 {0.19670438, 0.38921652, 0.51843878}, 452 {0.19978526, 0.39177424, 0.51769017}, 453 {0.20280277, 0.39433623, 0.51695934}, 454 {0.20574448, 0.39689659, 0.51631112}, 455 {0.20862219, 0.39946359, 0.51567252}, 456 {0.21142395, 0.40203013, 0.51511745}, 457 {0.21415805, 0.40460435, 0.51457709}, 458 {0.21681705, 0.40718098, 0.51410601}, 459 {0.21940294, 0.40976427, 0.5136727}, 460 {0.22191346, 0.4123542, 0.51328427}, 461 {0.22434688, 0.41494912, 0.51295975}, 462 {0.22670152, 0.4175556, 0.51265342}, 463 {0.22897578, 0.42016834, 0.51241261}, 464 {0.23116721, 0.42279102, 0.51221511}, 465 {0.23327224, 0.42542553, 0.5120539}, 466 {0.23529113, 0.42806929, 0.51195199}, 467 {0.23721876, 0.4307259, 0.51189091}, 468 {0.23905088, 0.43339672, 0.51186833}, 469 {0.24078829, 0.43607984, 0.51190068}, 470 {0.24242777, 0.43877648, 0.5119848}, 471 {0.24395722, 0.44149191, 0.51209793}, 472 {0.24538089, 0.44422266, 0.51226326}, 473 {0.24669486, 0.44696981, 0.512479}, 474 {0.24789484, 0.44973443, 0.51274365}, 475 {0.24897073, 0.45251957, 0.51304809}, 476 {0.24992008, 0.45532509, 0.51339708}, 477 {0.25074106, 0.45815079, 0.51379462}, 478 {0.25142853, 0.46099761, 0.51423996}, 479 {0.2519772, 0.46386643, 0.51473252}, 480 {0.25238166, 0.46675805, 0.51527187}, 481 {0.25263645, 0.46967322, 0.51585774}, 482 {0.25273608, 0.47261257, 0.51648993}, 483 {0.25267511, 0.47557666, 0.51716828}, 484 {0.25244821, 0.47856593, 0.51789267}, 485 {0.25205017, 0.4815807, 0.51866293}, 486 {0.25147595, 0.48462119, 0.51947882}, 487 {0.25072074, 0.48768749, 0.52034}, 488 {0.24977992, 0.49077954, 0.52124597}, 489 {0.24864914, 0.49389721, 0.52219605}, 490 {0.24732429, 0.4970402, 0.52318934}, 491 {0.2458015, 0.50020813, 0.5242247}, 492 {0.24407712, 0.50340048, 0.52530069}, 493 {0.24213937, 0.50661827, 0.52641341}, 494 {0.23998809, 0.50986008, 0.52756205}, 495 {0.2376243, 0.51312431, 0.5287454}, 496 {0.23504515, 0.51641008, 0.52996075}, 497 {0.23223599, 0.51971846, 0.53120267}, 498 {0.22919943, 0.52304738, 0.53246911}, 499 {0.22593842, 0.52639479, 0.53375736}, 500 {0.22243635, 0.52976175, 0.53506084}, 501 {0.21869708, 0.53314592, 0.53637622}, 502 {0.21472177, 0.53654544, 0.53769908}, 503 {0.21049097, 0.53996144, 0.53902151}, 504 {0.20602332, 0.5433894, 0.54034076}, 505 {0.20129189, 0.54683133, 0.54164703}, 506 {0.19632014, 0.5502822, 0.54293704}, 507 {0.1910817, 0.5537437, 0.54420016}, 508 {0.1856016, 0.55721085, 0.54543206}, 509 {0.17986279, 0.56068409, 0.5466222}, 510 {0.17388472, 0.56415953, 0.54776421}, 511 {0.16767592, 0.56763485, 0.54884959}, 512 {0.16124118, 0.57110836, 0.54986858}, 513 {0.15461572, 0.57457555, 0.55081476}, 514 {0.14782653, 0.57803342, 0.55167986}, 515 {0.14090518, 0.58147916, 0.55245531}, 516 {0.13391472, 0.5849079, 0.5531362}, 517 {0.12692017, 0.58831582, 0.55371706}, 518 {0.12000191, 0.59169907, 0.55419371}, 519 {0.11326013, 0.59505365, 0.55456398}, 520 {0.10681409, 0.59837568, 0.55482785}, 521 {0.10079543, 0.60166197, 0.55498638}, 522 {0.09534887, 0.60490977, 0.55504241}, 523 {0.09063347, 0.60811639, 0.55500215}, 524 {0.08679049, 0.61128079, 0.55487004}, 525 {0.08394854, 0.6144023, 0.55465197}, 526 {0.08221537, 0.61748019, 0.55435753}, 527 {0.08164325, 0.6205151, 0.55399342}, 528 {0.08223013, 0.62350855, 0.55356369}, 529 {0.08394439, 0.62646065, 0.55308231}, 530 {0.08668611, 0.6293742, 0.55254872}, 531 {0.09034668, 0.63225032, 0.55197376}, 532 {0.09479378, 0.63509139, 0.55135952}, 533 {0.09989897, 0.63789906, 0.55071423}, 534 {0.10553908, 0.64067585, 0.55003665}, 535 {0.11160448, 0.64342303, 0.54933941}, 536 {0.11800283, 0.64614329, 0.54861541}, 537 {0.12465323, 0.64883798, 0.54787462}, 538 {0.13149053, 0.65150897, 0.54711829}, 539 {0.13846531, 0.65415809, 0.5463437}, 540 {0.1455335, 0.65678673, 0.54555555}, 541 {0.15265709, 0.65939627, 0.54476003}, 542 {0.15981518, 0.66198821, 0.54395146}, 543 {0.16698676, 0.66456378, 0.54313117}, 544 {0.17415531, 0.66712409, 0.54230031}, 545 {0.18130458, 0.66967023, 0.54146307}, 546 {0.18842545, 0.67220323, 0.54061925}, 547 {0.19551341, 0.67472397, 0.53976647}, 548 {0.2025629, 0.67723331, 0.53890516}, 549 {0.20956984, 0.67973202, 0.53803564}, 550 {0.2165314, 0.68222082, 0.53715809}, 551 {0.22344573, 0.68470038, 0.53627262}, 552 {0.23031175, 0.6871713, 0.53537923}, 553 {0.23712903, 0.68963415, 0.53447784}, 554 {0.24389765, 0.69208946, 0.53356833}, 555 {0.25061808, 0.6945377, 0.53265048}, 556 {0.25729111, 0.69697932, 0.53172407}, 557 {0.26391778, 0.6994147, 0.53078879}, 558 {0.27049933, 0.70184423, 0.52984433}, 559 {0.27703712, 0.70426823, 0.52889033}, 560 {0.28353264, 0.70668701, 0.52792642}, 561 {0.28998746, 0.70910086, 0.52695218}, 562 {0.29640321, 0.71151001, 0.52596722}, 563 {0.30278152, 0.71391471, 0.5249711}, 564 {0.30912407, 0.71631516, 0.52396339}, 565 {0.31543254, 0.71871153, 0.52294366}, 566 {0.3217086, 0.72110401, 0.52191145}, 567 {0.3279539, 0.72349274, 0.52086633}, 568 {0.33417008, 0.72587784, 0.51980786}, 569 {0.34035875, 0.72825944, 0.5187356}, 570 {0.34652147, 0.73063763, 0.51764911}, 571 {0.35265864, 0.73301261, 0.51654918}, 572 {0.35877137, 0.73538448, 0.51543583}, 573 {0.3648628, 0.73775319, 0.51430692}, 574 {0.37093438, 0.74011877, 0.51316203}, 575 {0.37698751, 0.74248126, 0.51200075}, 576 {0.38302357, 0.7448407, 0.51082267}, 577 {0.38904388, 0.7471971, 0.5096274}, 578 {0.39504973, 0.74955049, 0.50841457}, 579 {0.40104082, 0.75190103, 0.5071855}, 580 {0.40701899, 0.75424866, 0.50593917}, 581 {0.41298655, 0.75659325, 0.50467398}, 582 {0.41894464, 0.75893479, 0.50338958}, 583 {0.42489434, 0.76127325, 0.50208564}, 584 {0.43083671, 0.76360862, 0.50076184}, 585 {0.43677259, 0.76594088, 0.4994181}, 586 {0.44270136, 0.7682702, 0.49805594}, 587 {0.44862605, 0.77059628, 0.49667271}, 588 {0.45454756, 0.77291909, 0.49526814}, 589 {0.46046679, 0.77523857, 0.49384196}, 590 {0.46638456, 0.77755469, 0.4923939}, 591 {0.47230148, 0.7798674, 0.49092398}, 592 {0.47821759, 0.78217677, 0.48943283}, 593 {0.48413494, 0.78448256, 0.48791871}, 594 {0.49005423, 0.78678471, 0.48638138}, 595 {0.49597616, 0.78908317, 0.48482063}, 596 {0.50190137, 0.79137786, 0.48323626}, 597 {0.5078303, 0.79366877, 0.48162833}, 598 {0.5137638, 0.79595578, 0.47999631}, 599 {0.51970278, 0.79823879, 0.47833963}, 600 {0.52564777, 0.80051774, 0.47665809}, 601 {0.53159931, 0.80279254, 0.47495153}, 602 {0.53755788, 0.80506315, 0.47321975}, 603 {0.54352447, 0.80732942, 0.47146196}, 604 {0.54949945, 0.80959129, 0.46967805}, 605 {0.55548322, 0.81184871, 0.4678679}, 606 {0.56147617, 0.8141016, 0.46603131}, 607 {0.5674787, 0.81634992, 0.46416812}, 608 {0.57349149, 0.81859354, 0.46227771}, 609 {0.57951582, 0.82083223, 0.46035867}, 610 {0.58555114, 0.82306609, 0.45841193}, 611 {0.59159777, 0.82529507, 0.45643726}, 612 {0.59765599, 0.82751909, 0.45443444}, 613 {0.60372607, 0.82973812, 0.45240324}, 614 {0.60980907, 0.83195194, 0.45034236}, 615 {0.61590608, 0.83416034, 0.44825035}, 616 {0.62201604, 0.83636352, 0.44612867}, 617 {0.62813915, 0.83856142, 0.443977}, 618 {0.6342756, 0.84075401, 0.44179501}, 619 {0.64042559, 0.84294124, 0.43958235}, 620 {0.64658927, 0.84512308, 0.43733862}, 621 {0.65276961, 0.84729891, 0.43505957}, 622 {0.65896438, 0.84946917, 0.43274795}, 623 {0.66517356, 0.85163387, 0.43040351}, 624 {0.67139725, 0.85379299, 0.4280257}, 625 {0.67763555, 0.85594651, 0.42561396}, 626 {0.68388856, 0.8580944, 0.42316766}, 627 {0.69015635, 0.86023667, 0.42068611}, 628 {0.69643989, 0.86237309, 0.41816731}, 629 {0.70274062, 0.86450334, 0.41560843}, 630 {0.70905639, 0.86662792, 0.41301167}, 631 {0.71538721, 0.86874683, 0.41037609}, 632 {0.72173308, 0.87086011, 0.40770069}, 633 {0.72809396, 0.87296778, 0.40498434}, 634 {0.7344698, 0.87506988, 0.40222583}, 635 {0.74086053, 0.87716647, 0.39942384}, 636 {0.74726606, 0.8792576, 0.39657691}, 637 {0.75368625, 0.88134336, 0.39368347}, 638 {0.76012096, 0.88342383, 0.39074178}, 639 {0.76656999, 0.88549913, 0.38774996}, 640 {0.77303308, 0.8875694, 0.38470595}, 641 {0.77950995, 0.88963477, 0.38160749}, 642 {0.78600023, 0.89169545, 0.37845211}, 643 {0.79250349, 0.89375165, 0.37523713}, 644 {0.79901921, 0.89580363, 0.37195957}, 645 {0.80554676, 0.8978517, 0.36861621}, 646 {0.8120854, 0.89989622, 0.3652035}, 647 {0.81863422, 0.90193761, 0.36171754}, 648 {0.82519216, 0.90397637, 0.35815405}, 649 {0.83175795, 0.9060131, 0.35450833}, 650 {0.83833008, 0.90804849, 0.3507752}, 651 {0.84490673, 0.91008337, 0.34694895}, 652 {0.85148576, 0.91211872, 0.34302325}, 653 {0.85806684, 0.91415505, 0.33898699}, 654 {0.86465276, 0.91619201, 0.3348209}, 655 {0.87123317, 0.91823316, 0.33052851}, 656 {0.87780375, 0.9202804, 0.32609988}, 657 {0.88435971, 0.92233593, 0.32152327}, 658 {0.89091043, 0.92439784, 0.31675269}, 659 {0.89743393, 0.9264737, 0.31180336}, 660 {0.9039243, 0.92856651, 0.3066523}, 661 {0.91038551, 0.93067656, 0.30124469}, 662 {0.91678774, 0.93281453, 0.29559791}, 663 {0.92313653, 0.9349809, 0.28963085}, 664 {0.92939556, 0.93718902, 0.28335908}, 665 {0.93555967, 0.93944353, 0.2766966}, 666 {0.94159054, 0.94175935, 0.26963707}, 667 {0.94745672, 0.94414992, 0.26213946}, 668 {0.95312442, 0.94662987, 0.25415069}, 669 {0.9585465, 0.94921781, 0.24566287}, 670 {0.96367764, 0.95193147, 0.23667632}, 671 {0.96847776, 0.95478608, 0.22720755}, 672 {0.97291733, 0.95779215, 0.21729217}, 673 {0.97698301, 0.96095356, 0.20697158} 674 675 }; // end of colorMapJosmViridisBright 676 677 // diverging red to blue, designed by http://colorbrewer2.org/ 678 private static Color[] colorMapJosmRed2Blue = { 679 new Color(0, 0, 0), 680 new Color(49, 54, 149), 681 new Color(69, 117, 180), 682 new Color(116, 173, 209), 683 new Color(171, 217, 233), 684 new Color(224, 243, 248), 685 new Color(254, 224, 144), 686 new Color(253, 174, 97), 687 new Color(244, 109, 67), 688 new Color(215, 48, 39), 689 new Color(165, 0, 38), 690 }; 691 692 // diverging brown to green, designed by http://colorbrewer2.org/ 693 private static Color[] colorMapJosmBrown2SeaGreen = { 694 new Color(0, 0, 0), 695 new Color(1, 102, 9), 696 new Color(53, 151, 143), 697 new Color(128, 205, 193), 698 new Color(199, 234, 229), 699 new Color(246, 232, 195), 700 new Color(223, 194, 125), 701 new Color(191, 129, 45), 702 new Color(140, 81, 10) 703 }; 704 705 // setup color maps used by heat map 706 private static Color[] heatMapLutColorJosmInferno = createColorFromRawArray(colorMapJosmInfernoBright); 707 private static Color[] heatMapLutColorJosmViridis = createColorFromRawArray(colorMapJosmViridisBright); 708 private static Color[] heatMapLutColorJosmBrown2Sea = createColorLut(colorMapJosmBrown2SeaGreen); 709 private static Color[] heatMapLutColorJosmRed2Blue = createColorLut(colorMapJosmRed2Blue); 710 711 // user defined heatmap color 712 private Color[] heatMapLutUserColor = createColorLut(Color.BLACK, Color.WHITE); 713 714 // heat map color in use 715 private Color[] heatMapLutColor = null; 716 107 717 private void setupColors() { 108 718 hdopAlpha = Main.pref.getInteger("hdop.color.alpha", -1); 109 719 velocityScale = ColorScale.createHSBScale(256); … … 111 721 hdopScale = ColorScale.createHSBScale(256).makeReversed().addTitle(tr("HDOP")); 112 722 dateScale = ColorScale.createHSBScale(256).addTitle(tr("Time")); 113 723 directionScale = ColorScale.createCyclicScale(256).setIntervalCount(4).addTitle(tr("Direction")); 724 heatMapLutColor = heatMapLutUserColor; 725 114 726 systemOfMeasurementChanged(null, null); 115 727 } 116 728 … … 127 739 * Different color modes 128 740 */ 129 741 public enum ColorMode { 130 NONE, VELOCITY, HDOP, DIRECTION, TIME ;742 NONE, VELOCITY, HDOP, DIRECTION, TIME, HEATMAP; 131 743 132 744 static ColorMode fromIndex(final int index) { 133 745 return values()[index]; … … 198 810 forceLines = Main.pref.getBoolean("draw.rawgps.lines.force", spec, false); 199 811 direction = Main.pref.getBoolean("draw.rawgps.direction", spec, false); 200 812 lineWidth = Main.pref.getInteger("draw.rawgps.linewidth", spec, 0); 813 alphaLines = Main.pref.getBoolean("draw.rawgps.lines.alpha-blend", spec, false); 201 814 202 815 if (!data.fromServer) { 203 816 maxLineLength = Main.pref.getInteger("draw.rawgps.max-line-length.local", spec, -1); … … 219 832 minTrackDurationForTimeColoring = Main.pref.getInteger("draw.rawgps.date-coloring-min-dt", 60); 220 833 largePointAlpha = Main.pref.getInteger("draw.rawgps.large.alpha", -1) & 0xFF; 221 834 835 // get heatmap parameters 836 heatMapEnabled = Main.pref.getBoolean("draw.rawgps.heatmap.enabled", spec, false); 837 heatMapDrawExtraLine = Main.pref.getBoolean("draw.rawgps.heatmap.line-extra", spec, false); 838 heatMapDrawColorTableIdx = Main.pref.getInteger("draw.rawgps.heatmap.colormap", specName(layerName), 0); 839 222 840 neutralColor = getColor(layerName, true); 223 841 velocityScale.setNoDataColor(neutralColor); 224 842 dateScale.setNoDataColor(neutralColor); … … 230 848 231 849 public void drawAll(Graphics2D g, MapView mv, List<WayPoint> visibleSegments) { 232 850 851 final long timeStart = System.currentTimeMillis(); 852 233 853 checkCache(); 234 854 235 855 // STEP 2b - RE-COMPUTE CACHE DATA ********************* … … 237 857 calculateColors(); 238 858 } 239 859 240 Stroke storedStroke = g.getStroke(); 860 fixColors(visibleSegments); 861 862 // backup the environment 863 Composite oldComposite = g.getComposite(); 864 Stroke oldStroke = g.getStroke(); 865 Paint oldPaint = g.getPaint(); 241 866 867 // set hints for the render 242 868 g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 243 869 Main.pref.getBoolean("mappaint.gpx.use-antialiasing", false) ? 244 870 RenderingHints.VALUE_ANTIALIAS_ON : RenderingHints.VALUE_ANTIALIAS_OFF); … … 246 872 if (lineWidth != 0) { 247 873 g.setStroke(new BasicStroke(lineWidth, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); 248 874 } 249 fixColors(visibleSegments); 250 drawLines(g, mv, visibleSegments); 875 876 // global enabled or select via color 877 boolean useHeatMap = heatMapEnabled || ColorMode.HEATMAP == colored; 878 879 // default global alpha level 880 float layerAlpha = 1.00f; 881 882 // extract current alpha blending value 883 if (oldComposite instanceof AlphaComposite) { 884 layerAlpha = ((AlphaComposite) oldComposite).getAlpha(); 885 } 886 887 // use heatmap background layer 888 if (useHeatMap) { 889 drawHeatMap(g, mv, visibleSegments); 890 } else { 891 // use normal line style or alpha-blending lines 892 if (!alphaLines) { 893 drawLines(g, mv, visibleSegments); 894 } else { 895 drawLinesAlpha(g, mv, visibleSegments, layerAlpha); 896 } 897 } 898 899 // override global alpha settings (smooth overlay) 900 if (alphaLines || useHeatMap) { 901 g.setComposite(AlphaComposite.SrcOver.derive(0.25f * layerAlpha)); 902 } 903 904 // normal overlays 251 905 drawArrows(g, mv, visibleSegments); 252 906 drawPoints(g, mv, visibleSegments); 253 if (lineWidth != 0) { 254 g.setStroke(storedStroke); 907 908 // restore environment 909 g.setPaint(oldPaint); 910 g.setStroke(oldStroke); 911 g.setComposite(oldComposite); 912 913 // show some debug info 914 if (Main.isDebugEnabled() && !visibleSegments.isEmpty()) { 915 final long timeDiff = System.currentTimeMillis() - timeStart; 916 917 Main.debug("gpxdraw::draw takes " + 918 Utils.getDurationString(timeDiff) + 919 "(" + 920 "segments= " + visibleSegments.size() + 921 ", per 10000 = " + Utils.getDurationString(10000 * timeDiff / visibleSegments.size()) + 922 ")" 923 ); 255 924 } 256 925 } 257 926 … … 391 1060 } 392 1061 } 393 1062 1063 // heat mode 1064 if (ColorMode.HEATMAP == colored) { 1065 1066 // generate new user color map 1067 heatMapLutUserColor = createColorLut(Color.BLACK, neutralColor.darker(), 1068 neutralColor, neutralColor.brighter(), Color.WHITE); 1069 1070 // decide what, keep order is sync with setting on GUI 1071 Color[][] lut = { 1072 heatMapLutUserColor, 1073 heatMapLutColorJosmInferno, 1074 heatMapLutColorJosmViridis, 1075 heatMapLutColorJosmBrown2Sea, 1076 heatMapLutColorJosmRed2Blue, 1077 }; 1078 1079 // select by index 1080 if (heatMapDrawColorTableIdx < lut.length) { 1081 heatMapLutColor = lut[ heatMapDrawColorTableIdx ]; 1082 } else { 1083 // fallback 1084 heatMapLutColor = heatMapLutUserColor; 1085 } 1086 1087 // force redraw of image 1088 heatMapCacheVisibleSegments = 0; 1089 1090 } // end of if (ColorMode.HEATMAP == colored) 1091 394 1092 computeCacheInSync = true; 395 1093 } 396 1094 … … 550 1248 } // end if large 551 1249 } 552 1250 1251 // draw GPS a lines by using alpha blending 1252 private void drawLinesAlpha(Graphics2D g, MapView mv, List<WayPoint> visibleSegments, float layerAlpha) { 1253 1254 // early abort 1255 if (lineWidth < 1) return; 1256 1257 // 1st. backup the paint environment ---------------------------------- 1258 Composite oldComposite = g.getComposite(); 1259 Stroke oldStroke = g.getStroke(); 1260 Paint oldPaint = g.getPaint(); 1261 1262 // 2nd. determine current scale factors ------------------------------- 1263 1264 // cache scale of view 1265 final double zoomScale = mv.getScale(); 1266 1267 // 3rd. determine current paint parameters ----------------------------- 1268 1269 // alpha value is based on zoom and line with combined with global layer alpha 1270 float theLineAlpha = Math.min(Math.max((0.50f/(float) zoomScale)/(lineWidth + 1), 0.001f), 0.50f) * layerAlpha; 1271 final int theLineWith = (int) (lineWidth / zoomScale) + 1; 1272 1273 // 4th setup virtual paint area ---------------------------------------- 1274 1275 // set line format and alpha channel for all overlays (more lines -> few overlap -> more transparency) 1276 g.setStroke(new BasicStroke(theLineWith, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); 1277 g.setComposite(AlphaComposite.SrcOver.derive(theLineAlpha)); 1278 1279 // last used / calculated entries 1280 Point lastPaintPnt = null; 1281 1282 // 5th draw the layer --------------------------------------------------- 1283 1284 // for all points 1285 for (WayPoint trkPnt : visibleSegments) { 1286 1287 // transform coordinates 1288 final Point paintPnt = mv.getPoint(trkPnt.getEastNorth()); 1289 1290 // skip single points 1291 if (lastPaintPnt != null && trkPnt.drawLine && !lastPaintPnt.equals(paintPnt)) { 1292 1293 // set different color 1294 g.setColor(trkPnt.customColoring); 1295 1296 // draw it 1297 g.drawLine(lastPaintPnt.x, lastPaintPnt.y, paintPnt.x, paintPnt.y); 1298 1299 } // end of if() 1300 1301 lastPaintPnt = paintPnt; 1302 1303 } // end of for() 1304 1305 // @last restore modified paint environment ----------------------------- 1306 g.setPaint(oldPaint); 1307 g.setStroke(oldStroke); 1308 g.setComposite(oldComposite); 1309 } 1310 1311 // creates a linear distributed colormap by linear blending between colors 1312 protected static Color[] createColorLut(Color... colors) { 1313 1314 // number of lookup entries 1315 int tableSize = 256; 1316 1317 // create image an paint object 1318 BufferedImage img = new BufferedImage(tableSize, 1, BufferedImage.TYPE_INT_RGB); 1319 Graphics2D g = img.createGraphics(); 1320 1321 float[] fract = new float[ colors.length ]; 1322 1323 // distribute fractions (define position of color in map) 1324 for (int i = 0; i < colors.length; ++i) { 1325 fract[i] = i * (1.0f / colors.length); 1326 } 1327 1328 // draw the gradient map 1329 LinearGradientPaint gradient = new LinearGradientPaint(0, 0, tableSize, 1, fract, colors, 1330 MultipleGradientPaint.CycleMethod.NO_CYCLE); 1331 g.setPaint(gradient); 1332 g.fillRect(0, 0, tableSize, 1); 1333 g.dispose(); 1334 1335 // access it via raw interface 1336 final Raster imgRaster = img.getData(); 1337 1338 // the pixel storage 1339 int[] pixel = new int[1]; 1340 1341 Color[] colorTable = new Color[tableSize]; 1342 1343 // map the range 0..255 to 0..pi/2 1344 final double mapTo90Deg = Math.PI / 2.0 / 255.0; 1345 1346 // create the lookup table 1347 for (int i = 0; i < tableSize; i++) { 1348 1349 // get next single pixel 1350 imgRaster.getDataElements((int) (i * (double) img.getWidth() / tableSize), 0, pixel); 1351 1352 // get color and map 1353 Color c = new Color(pixel[0]); 1354 1355 // smooth alpha like sin curve 1356 int alpha = (int) (Math.sin(i * mapTo90Deg) * 255); 1357 1358 // alpha with pre-offset, first color -> full transparent 1359 alpha = i > 0 ? (75 + alpha) : 0; 1360 1361 // shrink to maximum bound 1362 if (alpha > 255) { 1363 alpha = 255; 1364 } 1365 1366 // increase transparency for higher values ( avoid big saturation ) 1367 if (i > 240 && 255 == alpha) { 1368 alpha -= (i - 240); 1369 } 1370 1371 // fill entry in table, assign a alpha value 1372 colorTable[i] = new Color(c.getRed(), c.getGreen(), c.getBlue(), alpha); 1373 } 1374 1375 // transform into lookup table 1376 return colorTable; 1377 1378 } // end of createColorLut() 1379 1380 // creates a colormap by using a static color map with 1..n colors (RGB 0.0 ..1.0) 1381 protected static Color[] createColorFromRawArray(double[][] data) { 1382 1383 // create the array 1384 Color[] color = new Color[ data.length ]; 1385 1386 for (int k = 0; k < data.length; k++) { 1387 // cast an map to linear array 1388 color[k] = new Color((float) data[k][0], (float) data[k][1], (float) data[k][2]); 1389 } 1390 1391 // forward 1392 return createColorLut(color); 1393 1394 } // end of createColorFromRawArray() 1395 1396 // collect and draw GPS segments and displays a heat-map 1397 private void drawHeatMap(Graphics2D g, MapView mv, List<WayPoint> visibleSegments) { 1398 1399 // early abort 1400 if (lineWidth < 1) return; 1401 1402 long timeStart; 1403 1404 // 1st setup virtual paint area ---------------------------------------- 1405 1406 // get bounds of screen image and projection 1407 final Rectangle screenBounds = g.getDeviceConfiguration().getBounds(); 1408 1409 // cache scale of view 1410 final double zoomScale = mv.getScale(); 1411 1412 if (Main.isDebugEnabled()) { 1413 Main.debug("gpxdraw::heat : bound = " + screenBounds.width + "x" + screenBounds.height); 1414 } 1415 1416 // HACK: sometime screen bounds does not return valid values when picture is shifted 1417 // therefore we use a bigger area to avoid missing parts of image 1418 screenBounds.width = screenBounds.width * 3 / 2; 1419 screenBounds.height = screenBounds.height * 3 / 2; 1420 1421 // new image buffer needed 1422 boolean imageSetup = !heatMapCacheScreenBounds.equals(screenBounds) || null == heatMapImgGray; 1423 1424 // screen bounds changed, need new image buffer ? 1425 if (imageSetup) { 1426 timeStart = System.currentTimeMillis(); 1427 1428 // we would use a "pure" grayscale image, but there is not efficient way to map gray scale values to RGB) 1429 heatMapImgGray = new BufferedImage(screenBounds.width, screenBounds.height, BufferedImage.TYPE_INT_ARGB); 1430 1431 heatMapGraph2d = heatMapImgGray.createGraphics(); 1432 heatMapGraph2d.setBackground(new Color(0, 0, 0, 255)); 1433 heatMapGraph2d.setColor(Color.WHITE); 1434 1435 // cache it 1436 heatMapCacheScreenBounds = screenBounds; 1437 1438 // show some debug info 1439 if (Main.isDebugEnabled()) { 1440 Main.debug("gpxdraw::heat : new buffer takes " + Utils.getDurationString(System.currentTimeMillis() - timeStart)); 1441 } 1442 } 1443 1444 // shortcuts 1445 final BufferedImage imgG = heatMapImgGray; 1446 final Graphics2D gB = heatMapGraph2d; 1447 1448 // 2nd. determine current scale factors ------------------------------- 1449 1450 // alpha combines both values, therefore the foreground shall be lighter 1451 final float lineAlphaB = Math.min(Math.max((0.40f/(float) zoomScale)/(lineWidth + 1), 0.001f), 0.50f); 1452 final float lineAlphaF = lineAlphaB / 1.5f; 1453 1454 // derive draw parameters 1455 final Composite fC = AlphaComposite.SrcOver.derive(lineAlphaF); 1456 final Composite bC = AlphaComposite.SrcOver.derive(lineAlphaB); 1457 1458 // the line width (foreground: draw extra small footprint line of track) 1459 final int lineWidthB = Math.max((int) (lineWidth / zoomScale) + 1, 2); 1460 final int lineWidthF = lineWidthB > 2 ? lineWidth - 1 : 0; 1461 1462 final Stroke bS = new BasicStroke(lineWidthB, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND); 1463 final Stroke fS = new BasicStroke(lineWidthF, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND); 1464 1465 // set initial values 1466 gB.setStroke(bS); gB.setComposite(bC); 1467 1468 if (Main.isDebugEnabled()) { 1469 Main.debug("gpxdraw::heat : GPX segments = " + visibleSegments.size()); 1470 Main.debug("gpxdraw::heat : zoomscale = " + zoomScale); 1471 Main.debug("gpxdraw::heat : f-line-alpha = " + lineAlphaF); 1472 Main.debug("gpxdraw::heat : b-line-alpha = " + lineAlphaB); 1473 Main.debug("gpxdraw::heat : f-line-width = " + lineWidthF); 1474 Main.debug("gpxdraw::heat : b-line-with = " + lineWidthB); 1475 } 1476 1477 // 3rd Calculate the heat map data by draw GPX traces with alpha value ---------- 1478 1479 timeStart = System.currentTimeMillis(); 1480 1481 // clear data storage 1482 heatMapPolyX.clear(); heatMapPolyY.clear(); 1483 1484 // dummy list 1485 List<WayPoint> listSegm = new LinkedList<>(); 1486 1487 // recalculation of image needed 1488 final boolean imageRecalc = heatMapCacheVisibleSegments != visibleSegments.size() || 1489 heatMapCacheZoomScale != zoomScale || 1490 heatMapCacheLineWith != lineWidth; 1491 1492 // need re-generation of gray image ? 1493 if (imageSetup || imageRecalc) { 1494 1495 // clear background 1496 gB.clearRect(0, 0, heatMapImgGray.getWidth(), heatMapImgGray.getHeight()); 1497 1498 // use real data 1499 listSegm = visibleSegments; 1500 1501 // remember 1502 heatMapCacheVisibleSegments = visibleSegments.size(); 1503 heatMapCacheZoomScale = zoomScale; 1504 heatMapCacheLineWith = lineWidth; 1505 } 1506 1507 // for all points, draw single lines by using optimize drawing 1508 for (WayPoint trkPnt : listSegm) { 1509 1510 // something to paint or color changed (new segment needed, decrease performance ;-() 1511 if (!trkPnt.drawLine && !heatMapPolyX.isEmpty()) { 1512 1513 // convert to primitive type 1514 final int[] polyXArr = heatMapPolyX.stream().mapToInt(Integer::intValue).toArray(); 1515 final int[] polyYArr = heatMapPolyY.stream().mapToInt(Integer::intValue).toArray(); 1516 1517 // a.) draw background 1518 gB.drawPolyline(polyXArr, polyYArr, polyXArr.length); 1519 1520 // b.) draw extra foreground 1521 if (heatMapDrawExtraLine && lineWidthF > 0) { 1522 1523 gB.setStroke(fS); gB.setComposite(fC); 1524 gB.drawPolyline(polyXArr, polyYArr, polyXArr.length); 1525 gB.setStroke(bS); gB.setComposite(bC); 1526 } 1527 1528 // drop used pints 1529 heatMapPolyX.clear(); heatMapPolyY.clear(); 1530 1531 } else { 1532 1533 // get transformed coordinates 1534 final Point paintPnt = mv.getPoint(trkPnt.getEastNorth()); 1535 1536 // store only the integer part (make sense because pixel is 1:1 here) 1537 heatMapPolyX.add((int) paintPnt.getX()); 1538 heatMapPolyY.add((int) paintPnt.getY()); 1539 } 1540 1541 } // end of for() 1542 1543 // show some debug info 1544 if (Main.isDebugEnabled()) { 1545 Main.debug("gpxdraw::heat : gray-image takes " + Utils.getDurationString(System.currentTimeMillis() - timeStart)); 1546 } 1547 1548 // 4th. Draw data on target layer, map data via color lookup table -------------- 1549 1550 timeStart = System.currentTimeMillis(); 1551 1552 final int[] imgPixels = ((DataBufferInt) imgG.getRaster().getDataBuffer()).getData(); 1553 1554 // samples offset and bounds are scaled with line width derived from zoom level 1555 final int offX = Math.max(1, lineWidthB / 2); 1556 final int offY = Math.max(1, lineWidthB / 2); 1557 1558 final int maxPixelX = imgG.getWidth(); 1559 final int maxPixelY = imgG.getHeight(); 1560 1561 int lastPixelY = 0; int lastPixelColor = 0; 1562 1563 // resample gray scale image with line linear weight of next sample in line 1564 // process each line and draw pixels / rectangles with same color with one operations 1565 for (int x = 0; x < maxPixelX; x += offX) { 1566 for (int y = 0; y < maxPixelY; y += offY) { 1567 1568 int thePixelColor = 0; 1569 1570 // sample the image (it is gray scale) 1571 int offset = (x * maxPixelX) + y; 1572 1573 // merge next pixels of window of line 1574 for (int k = 0; k < offX && offset + k < imgPixels.length; k++) { 1575 thePixelColor += imgPixels[offset+k] & 0xFF; 1576 } 1577 1578 // mean value 1579 thePixelColor /= offX; 1580 1581 // restart -> use initial sample 1582 if (0 == y) { 1583 lastPixelY = 0; lastPixelColor = thePixelColor; 1584 } 1585 1586 // different color to last one ? 1587 if (Math.abs(lastPixelColor - thePixelColor) > 1) { 1588 1589 // draw only foreground pixels, skip small variations 1590 if (lastPixelColor > 1+1) { 1591 1592 // gray to RGB mapping 1593 g.setColor(heatMapLutColor[ lastPixelColor ]); 1594 1595 // start point for draw ( 1596 int yN = lastPixelY > 0 ? lastPixelY - 1 : y; 1597 1598 // box from from last Y pixel to current pixel 1599 if (offX < lineWidth + 2) { 1600 g.fillRect(yN, x, offY + y - yN, offX); 1601 } else { 1602 g.drawRect(yN, x, offY + y - yN, offX); 1603 } 1604 } 1605 // restart detection 1606 lastPixelY = y; lastPixelColor = thePixelColor; 1607 } 1608 } 1609 1610 } // end of for() 1611 1612 // show some debug info 1613 if (Main.isDebugEnabled()) { 1614 Main.debug("gpxdraw::heat : color-image takes " + Utils.getDurationString(System.currentTimeMillis() - timeStart)); 1615 } 1616 1617 } // end of drawHeatMap() 1618 553 1619 private void fixColors(List<WayPoint> visibleSegments) { 554 1620 for (WayPoint trkPnt : visibleSegments) { 555 1621 if (trkPnt.customColoring == null) { … … 564 1630 private void checkCache() { 565 1631 if ((computeCacheMaxLineLengthUsed != maxLineLength) || (!neutralColor.equals(computeCacheColorUsed)) 566 1632 || (computeCacheColored != colored) || (computeCacheColorTracksTune != colorTracksTune) 567 || (computeCacheColorDynamic != colorModeDynamic)) { 1633 || (computeCacheColorDynamic != colorModeDynamic) 1634 || (computeCacheHeatMapDrawColorTableIdx != heatMapDrawColorTableIdx) 1635 ) { 568 1636 computeCacheMaxLineLengthUsed = maxLineLength; 569 1637 computeCacheInSync = false; 570 1638 computeCacheColorUsed = neutralColor; 571 1639 computeCacheColored = colored; 572 1640 computeCacheColorTracksTune = colorTracksTune; 573 1641 computeCacheColorDynamic = colorModeDynamic; 1642 computeCacheHeatMapDrawColorTableIdx = heatMapDrawColorTableIdx; 574 1643 } 575 1644 } 576 1645 … … 580 1649 581 1650 public void drawColorBar(Graphics2D g, MapView mv) { 582 1651 int w = mv.getWidth(); 1652 1653 // set do default 1654 g.setComposite(AlphaComposite.SrcOver.derive(1.00f)); 1655 583 1656 if (colored == ColorMode.HDOP) { 584 1657 hdopScale.drawColorBar(g, w-30, 50, 20, 100, 1.0); 585 1658 } else if (colored == ColorMode.VELOCITY) { -
src/org/openstreetmap/josm/gui/preferences/display/GPXSettingsPanel.java
55 55 private final JRadioButton colorTypeDirection = new JRadioButton(tr("Direction (red = west, yellow = north, green = east, blue = south)")); 56 56 private final JRadioButton colorTypeDilution = new JRadioButton(tr("Dilution of Position (red = high, green = low, if available)")); 57 57 private final JRadioButton colorTypeTime = new JRadioButton(tr("Track date")); 58 private final JRadioButton colorTypeHeatMap = new JRadioButton(tr("Heat Map (dark = few tracks, bright = many tracks)")); 58 59 private final JRadioButton colorTypeNone = new JRadioButton(tr("Single Color (can be customized for named layers)")); 59 60 private final JRadioButton colorTypeGlobal = new JRadioButton(tr("Use global settings")); 60 61 private final JosmComboBox<String> colorTypeVelocityTune = new JosmComboBox<>(new String[] {tr("Car"), tr("Bicycle"), tr("Foot")}); 62 private final JosmComboBox<String> colorTypeHeatMapTune = new JosmComboBox<>(new String[] {tr("User"), tr("Inferno"), tr("Viridis"), 63 tr("Wood"), tr("Heat")}); 61 64 private final JCheckBox makeAutoMarkers = new JCheckBox(tr("Create markers when reading GPX")); 62 65 private final JCheckBox drawGpsArrows = new JCheckBox(tr("Draw Direction Arrows")); 63 66 private final JCheckBox drawGpsArrowsFast = new JCheckBox(tr("Fast drawing (looks uglier)")); … … 68 71 private final JosmComboBox<String> audioWaypointLabel = new JosmComboBox<>(LABEL_PATTERN_DESC); 69 72 private final JosmTextField audioWaypointLabelPattern = new JosmTextField(); 70 73 private final JCheckBox useGpsAntialiasing = new JCheckBox(tr("Smooth GPX graphics (antialiasing)")); 74 private final JCheckBox drawLineWithAlpha = new JCheckBox(tr("Draw with Opacity (alpha blending) ")); 71 75 72 76 private String layerName; 73 77 private final boolean local; // flag to display LocalOnly checkbox … … 179 183 drawGpsArrowsMinDist.setEnabled(drawGpsArrows.isSelected() && drawGpsArrows.isEnabled()); 180 184 }); 181 185 drawGpsArrows.setToolTipText(tr("Draw direction arrows for lines, connecting GPS points.")); 182 add(drawGpsArrows, GBC.eop().insets( 40, 0, 0, 0));186 add(drawGpsArrows, GBC.eop().insets(20, 0, 0, 0)); 183 187 184 188 // drawGpsArrowsFast 185 189 drawGpsArrowsFast.setToolTipText(tr("Draw the direction arrows using table lookups instead of complex math.")); 186 add(drawGpsArrowsFast, GBC.eop().insets( 60, 0, 0, 0));190 add(drawGpsArrowsFast, GBC.eop().insets(40, 0, 0, 0)); 187 191 ExpertToggleAction.addVisibilitySwitcher(drawGpsArrowsFast); 188 192 189 193 // drawGpsArrowsMinDist 190 194 drawGpsArrowsMinDist.setToolTipText(tr("Do not draw arrows if they are not at least this distance away from the last one.")); 191 add(new JLabel(tr("Minimum distance (pixels)")), GBC.std().insets( 60, 0, 0, 0));195 add(new JLabel(tr("Minimum distance (pixels)")), GBC.std().insets(40, 0, 0, 0)); 192 196 add(drawGpsArrowsMinDist, GBC.eol().fill(GBC.HORIZONTAL).insets(5, 0, 0, 5)); 193 197 194 198 // hdopCircleGpsPoints … … 210 214 add(useGpsAntialiasing, GBC.eop().insets(20, 0, 0, 0)); 211 215 ExpertToggleAction.addVisibilitySwitcher(useGpsAntialiasing); 212 216 217 // alpha blending 218 drawLineWithAlpha.setToolTipText(tr("Apply dynamic alpha-blending and adjust width based on zoom level for all GPX lines.")); 219 add(drawLineWithAlpha, GBC.eop().insets(20, 0, 0, 0)); 220 ExpertToggleAction.addVisibilitySwitcher(drawLineWithAlpha); 221 213 222 // colorTracks 214 223 ButtonGroup colorGroup = new ButtonGroup(); 215 224 if (layerName != null) { … … 220 229 colorGroup.add(colorTypeDirection); 221 230 colorGroup.add(colorTypeDilution); 222 231 colorGroup.add(colorTypeTime); 232 colorGroup.add(colorTypeHeatMap); 223 233 224 234 colorTypeVelocity.addChangeListener(e -> { 225 235 colorTypeVelocityTune.setEnabled(colorTypeVelocity.isSelected()); 226 236 colorDynamic.setEnabled(colorTypeVelocity.isSelected() || colorTypeDilution.isSelected()); 227 237 }); 238 239 colorTypeHeatMap.addChangeListener(e -> { 240 colorTypeHeatMapTune.setEnabled(colorTypeHeatMap.isSelected()); 241 colorDynamic.setEnabled(false); 242 }); 243 228 244 colorTypeDilution.addChangeListener(e -> colorDynamic.setEnabled(colorTypeVelocity.isSelected() || colorTypeDilution.isSelected())); 229 245 230 246 colorTypeNone.setToolTipText(tr("All points and track segments will have the same color. Can be customized in Layer Manager.")); … … 233 249 colorTypeDilution.setToolTipText( 234 250 tr("Colors points and track segments by dilution of position (HDOP). Your capture device needs to log that information.")); 235 251 colorTypeTime.setToolTipText(tr("Colors points and track segments by its timestamp.")); 252 colorTypeHeatMap.setToolTipText(tr("Collected points and track segments for a position and displayed as heat map.")); 236 253 237 254 // color Tracks by Velocity Tune 238 255 colorTypeVelocityTune.setToolTipText(tr("Allows to tune the track coloring for different average speeds.")); 239 256 257 colorTypeHeatMapTune.setToolTipText(tr("Selects the color schema for heat map.")); 258 240 259 add(Box.createVerticalGlue(), GBC.eol().insets(0, 20, 0, 0)); 241 260 242 261 add(new JLabel(tr("Track and Point Coloring")), GBC.eol().insets(20, 0, 0, 0)); … … 249 268 add(colorTypeDirection, GBC.eol().insets(40, 0, 0, 0)); 250 269 add(colorTypeDilution, GBC.eol().insets(40, 0, 0, 0)); 251 270 add(colorTypeTime, GBC.eol().insets(40, 0, 0, 0)); 271 add(colorTypeHeatMap, GBC.std().insets(40, 0, 0, 0)); 272 add(colorTypeHeatMapTune, GBC.eop().insets(5, 0, 0, 5)); 273 252 274 ExpertToggleAction.addVisibilitySwitcher(colorTypeDirection); 253 275 ExpertToggleAction.addVisibilitySwitcher(colorTypeDilution); 254 276 … … 315 337 drawRawGpsMaxLineLengthLocal.setText(Integer.toString(Main.pref.getInteger("draw.rawgps.max-line-length.local", layerName, -1))); 316 338 drawRawGpsMaxLineLength.setText(Integer.toString(Main.pref.getInteger("draw.rawgps.max-line-length", layerName, 200))); 317 339 drawLineWidth.setText(Integer.toString(Main.pref.getInteger("draw.rawgps.linewidth", layerName, 0))); 340 drawLineWithAlpha.setSelected(Main.pref.getBoolean("draw.rawgps.lines.alpha-blend", layerName, false)); 318 341 forceRawGpsLines.setSelected(Main.pref.getBoolean("draw.rawgps.lines.force", layerName, false)); 319 342 drawGpsArrows.setSelected(Main.pref.getBoolean("draw.rawgps.direction", layerName, false)); 320 343 drawGpsArrowsFast.setSelected(Main.pref.getBoolean("draw.rawgps.alternatedirection", layerName, false)); … … 322 345 hdopCircleGpsPoints.setSelected(Main.pref.getBoolean("draw.rawgps.hdopcircle", layerName, false)); 323 346 largeGpsPoints.setSelected(Main.pref.getBoolean("draw.rawgps.large", layerName, false)); 324 347 useGpsAntialiasing.setSelected(Main.pref.getBoolean("mappaint.gpx.use-antialiasing", false)); 348 325 349 drawRawGpsLinesActionListener.actionPerformed(null); 326 350 327 351 if (layerName != null && Main.pref.get("draw.rawgps.colors."+layerName).isEmpty()) { … … 336 360 case 2: colorTypeDilution.setSelected(true); break; 337 361 case 3: colorTypeDirection.setSelected(true); break; 338 362 case 4: colorTypeTime.setSelected(true); break; 363 case 5: colorTypeHeatMap.setSelected(true); break; 339 364 default: Main.warn("Unknown color type: " + colorType); 340 365 } 341 366 int ccts = Main.pref.getInteger("draw.rawgps.colorTracksTune", layerName, 45); 342 367 colorTypeVelocityTune.setSelectedIndex(ccts == 10 ? 2 : (ccts == 20 ? 1 : 0)); 343 368 colorTypeVelocityTune.setEnabled(colorTypeVelocity.isSelected() && colorTypeVelocity.isEnabled()); 369 370 colorTypeHeatMapTune.setSelectedIndex(Main.pref.getInteger("draw.rawgps.heatmap.colormap", layerName, 0)); 371 colorTypeHeatMapTune.setEnabled(colorTypeHeatMap.isSelected() && colorTypeHeatMap.isEnabled()); 372 344 373 colorDynamic.setSelected(Main.pref.getBoolean("draw.rawgps.colors.dynamic", layerName, false)); 345 374 colorDynamic.setEnabled(colorTypeVelocity.isSelected() || colorTypeDilution.isSelected()); 346 375 } … … 385 414 Main.pref.put("draw.rawgps.hdopcircle"+layerNameDot, hdopCircleGpsPoints.isSelected()); 386 415 Main.pref.put("draw.rawgps.large"+layerNameDot, largeGpsPoints.isSelected()); 387 416 Main.pref.put("draw.rawgps.linewidth"+layerNameDot, drawLineWidth.getText()); 417 Main.pref.put("draw.rawgps.lines.alpha-blend"+layerNameDot, drawLineWithAlpha.isSelected()); 418 388 419 Main.pref.put("mappaint.gpx.use-antialiasing", useGpsAntialiasing.isSelected()); 389 420 390 421 TemplateEntryProperty.forMarker(layerName).put(waypointLabelPattern.getText()); … … 403 434 Main.pref.putInteger("draw.rawgps.colors"+layerNameDot, 3); 404 435 } else if (colorTypeTime.isSelected()) { 405 436 Main.pref.putInteger("draw.rawgps.colors"+layerNameDot, 4); 437 } else if (colorTypeHeatMap.isSelected()) { 438 Main.pref.putInteger("draw.rawgps.colors"+layerNameDot, 5); 406 439 } else { 407 440 Main.pref.putInteger("draw.rawgps.colors"+layerNameDot, 0); 408 441 } 409 442 Main.pref.put("draw.rawgps.colors.dynamic"+layerNameDot, colorDynamic.isSelected()); 410 443 int ccti = colorTypeVelocityTune.getSelectedIndex(); 411 444 Main.pref.putInteger("draw.rawgps.colorTracksTune"+layerNameDot, ccti == 2 ? 10 : (ccti == 1 ? 20 : 45)); 445 446 Main.pref.putInteger("draw.rawgps.heatmap.colormap"+layerNameDot, colorTypeHeatMapTune.getSelectedIndex()); 447 412 448 return false; 413 449 } 414 450