1/* ******Functions included in start/_NG_utilities.def:****** 2 * 3 * so_balance ref_meanmax im1 im2 mask blur gauss * 4 * nonzero_mean im = no_out * 5 * so_meanmax im = result * 6 * so_calculate ref_meanmax im mask = result * 7 * simple_frame frame im_w im_h ov cs ms bf option = result * 8 * corner_frame frame im_w im_h ov cs ms bf = result * 9 * build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf = result * 10 * complex_frame frame im_w im_h ov cs es ms bf option= result * 11 * complex_edge ra rb t bl d = rc * 12 * frame_lr_min r_l r_r target bw = result * 13 * frame_tb_min r_t r_b target bw = result * 14 * frame_position_image im ref os colour= result * 15 * merge_array bw arr = result * 16 * merge_to_scale im target blend dir = result * 17 * select_ellipse line width = mask * 18 * select_tetragon p1 p2 p3 p4 = mask * 19 * select_polygon pt_list = mask * 20 * perspective_transform to from = trans'' * 21 * sort_pts_clockwise l = l'' * 22 */ 23 24/* Called from: 25* _NG_Extra.def Clone_area_item 26*/ 27so_balance ref_meanmax im1 im2 mask gauss 28 = result 29 { 30 //ref_meanmax = so_meanmax im1; 31 so_values = so_calculate ref_meanmax im2 mask; 32 im2_cor_a = clip2fmt im2.format im2'', has_member "format" im2 33 = im2'' 34 {im2'' = im2 * (so_values?0) + (so_values?1);} 35 // Option to convert replacement image to scaled gaussian noise 36 im2_cor = im2_cor_a, gauss == false 37 = clip2fmt im2_cor_a.format gauss_im 38 {gauss_im = 39 gaussnoise im2_cor_a.width im2_cor_a.height ref_meanmax?0 40(deviation im2_cor_a);} 41 result = im_blend (get_image mask) (get_image 42im2_cor) (get_image im1); 43 }; 44 45//////////////////////////////////////////////////////////////////////////////// 46/* Calculates the mean of the non zero pixels. 47 * 48 * Called from: 49 * _NG_utilities so_meanmax 50 */ 51nonzero_mean im = no_out 52 { 53 zero_im = (im == 0); 54 zero_mean = mean zero_im; 55 no_mean = mean im; 56 no_out = no_mean/(1 - (zero_mean/255)); 57 }; 58 59//////////////////////////////////////////////////////////////////////////////// 60/* Calculates the max and nonzero mean of an image 61 * 62 * Called from: 63 * _NG_utilities so_balance 64 * _NG_utilities so_calculate 65 * _NG_Extra.def Clone_area_item 66 * _NG_Extra.def Balance_item.Balance_find_item 67 */ 68so_meanmax im = result 69 { 70 mean_of_im = nonzero_mean im; 71 adjusted_im = im - mean_of_im; 72 max_of_im = max adjusted_im; 73 74 result = [mean_of_im, max_of_im]; 75 }; 76 77//////////////////////////////////////////////////////////////////////////////// 78/* Calculates the scale and offset required to match a reference mean and max 79 * 80 * Called from: 81 * _NG_utilities so_balance 82 * _NG_Extra.def Balance_item.Balance_find_item 83 */ 84so_calculate ref_meanmax im mask = result 85 { 86 im' = if mask then im else 0; 87 im_values = so_meanmax im'; 88 89 mean_of_ref = ref_meanmax?0; 90 mean_of_im = im_values?0; 91 92 max_of_ref = ref_meanmax?1; 93 max_of_im = im_values?1; 94 95 scale = (max_of_ref)/(max_of_im); 96 offset = mean_of_ref - (mean_of_im * scale); 97 result = [ scale, offset ]; 98 }; 99 100//////////////////////////////////////////////////////////////////////////////// 101/* Extends or shortens the central sections of a simple frame to fit round a given image. 102 * 103 * Called from: 104 * _NG_Extra.def Frame_item.Simple_frame_item 105 */ 106simple_frame frame im_w im_h ov cs ms bf option = result 107 { 108 cs' = (1 - cs); 109 ms' = (0.5 - (ms/2)); 110 ms'' = (1 - cs); 111 112 //Regions 113 r_tl = Region_relative frame 0 0 cs cs; 114 r_tr = fliplr r_tl, option == true 115 = Region_relative frame cs' 0 cs cs; 116 r_bl = Region_relative frame 0 cs' cs cs; 117 r_br = fliplr r_bl, option == true 118 = Region_relative frame cs' cs' cs cs; 119 120 r_mt = Region_relative frame ms' 0 ms cs; 121 r_mb = Region_relative frame ms' ms'' ms cs; 122 r_ml = Region_relative frame 0 ms' cs ms; 123 r_mr = fliplr r_ml, option == true 124 = Region_relative frame ms'' ms' cs ms; 125 126 result = build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf; 127 }; 128 129//////////////////////////////////////////////////////////////////////////////// 130/* Copies and extends a simple frame corner to produce a complete frame to fit round a given image. 131 * 132 * Called from: 133 * _NG_Extra.def Frame_item.Frame_corner_item 134 */ 135corner_frame frame im_w im_h ov cs ms bf = result 136 { 137 cs' = (1 - cs); 138 ms' = (0.5 - (ms/2)); 139 140 //Regions 141 r_tl = Region_relative frame 0 0 cs cs; 142 r_tr = fliplr r_tl; 143 r_bl = fliptb r_tl; 144 r_br = fliplr r_bl; 145 r_mt = Region_relative frame ms' 0 ms cs; 146 r_mb = fliptb r_mt; 147 r_ml = Region_relative frame 0 ms' cs ms;; 148 r_mr = fliplr r_ml; 149 result = build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf; 150 }; 151 152//////////////////////////////////////////////////////////////////////////////// 153/* Completes the frame building process for simple_frame and corner_frame. 154 * 155 * _NG_utilities simple_frame 156 * _NG_utilities corner_frame 157 */ 158build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf = result 159 { 160 //Find pixel thickness of frames section 161 s_width = r_ml.width - mean (im_profile (map_unary fliplr (r_ml.value)?0) 1); 162 s_height = r_mt.height - mean (im_profile (map_unary fliptb (r_mt.value)?0) 0); 163 164 w_target = im_w + (2 * (s_width - ov)); 165 h_target = im_h + (2 * (s_height - ov)); 166 167 blend = bf * r_tl.width; 168 169 cw_target = w_target - (2 * r_tl.width) + (2 * blend), w_target > (2 * r_tl.width) 170 = w_target; 171 ch_target = h_target - (2 * r_tl.height) + (2 * blend), h_target > (2 * r_tl.height) 172 = h_target; 173 174 //Use regions to produce sections 175 top = merge_to_scale r_mt cw_target blend 0; 176 bottom = merge_to_scale r_mb cw_target blend 0; 177 left = merge_to_scale r_ml ch_target blend 1; 178 right = merge_to_scale r_mr ch_target blend 1; 179 middle = Image 180 (image_new cw_target ch_target left.bands left.format left.coding left.type 0 0 0); 181 182 //Build sections into full frame. 183 row_1 = frame_lr_min r_tl r_tr w_target blend, ( w_target < (r_tl.width * 2)) 184 = merge_array blend [[r_tl, top, r_tr]]; 185 row_2 = frame_lr_min left right w_target blend, ( w_target < (r_tl.width * 2)) 186 = merge_array blend [[left, middle, right]]; 187 row_3 = frame_lr_min r_bl r_br w_target blend, ( w_target < (r_tl.width * 2)) 188 = merge_array blend [[r_bl, bottom, r_br]]; 189 190 result = frame_tb_min row_1 row_3 h_target blend, (h_target < (r_tl.height * 2)) 191 = merge_array blend [[row_1], [row_2], [row_3]]; 192 }; 193 194//////////////////////////////////////////////////////////////////////////////// 195/* Extends or shortens the central sections of a frame, preserving any central details on each 196 * edge, to fit round a given image. 197 * 198 * Called from: 199 * _NG_Extra.def Frame_item.Complex_frame_item 200 */ 201complex_frame frame im_w im_h ov cs es ms bf option= result 202 { 203 cs' = (1 - cs); 204 ms' = (0.5 - (ms/2)); 205 es' = (0.25 - (es/2)); 206 207 r_tl = Region_relative frame 0 0 cs cs; 208 r_tr = fliplr r_tl, option == true 209 = Region_relative frame cs' 0 cs cs; 210 r_bl = Region_relative frame 0 cs' cs cs; 211 r_br = fliplr r_bl, option == true 212 = Region_relative frame cs' cs' cs cs; 213 214 r_mt = Region_relative frame ms' 0 ms cs; 215 r_mb = Region_relative frame ms' cs' ms cs; 216 r_ml = Region_relative frame 0 ms' cs ms; 217 r_mr = fliplr r_ml, option == true 218 = Region_relative frame cs' ms' cs ms; 219 220 r_et = Region_relative frame es' 0 es cs; 221 r_eb = Region_relative frame es' cs' es cs; 222 r_el = Region_relative frame 0 es' cs es; 223 r_er = fliplr r_el, option == true 224 = Region_relative frame cs' es' cs es; 225 226 //Find pixel thickness of frames section 227 s_width = r_el.width - mean (im_profile (map_unary fliplr (r_el.value)?0) 1); 228 s_height = r_et.height - mean (im_profile (map_unary fliptb (r_et.value)?0) 0); 229 230 w_target = im_w + (2 * (s_width - ov)); 231 h_target = im_h + (2 * (s_height - ov)); 232 min_size = foldr1 min_pair [r_tl.width, r_tl.height, 233 r_mt.width, r_mt.height, 234 r_et.width, r_et.height]; 235 blend = bf * min_size; 236 237 cw_target = w_target - (2 * r_tl.width) + (2 * blend); 238 ch_target = h_target - (2 * r_tl.height) + (2 * blend); 239 240 top = complex_edge r_mt r_et cw_target blend 0; 241 bottom = complex_edge r_mb r_eb cw_target blend 0; 242 left = complex_edge r_ml r_el ch_target blend 1; 243 right = complex_edge r_mr r_er ch_target blend 1; 244 middle = Image 245 (image_new top.width left.height left.bands left.format left.coding left.type 0 0 0); 246 247 //Build regions into full frame. 248 row_1 = frame_lr_min r_tl r_tr w_target blend, ( w_target < (r_tl.width * 2)) 249 = merge_array blend [[r_tl, top, r_tr]]; 250 row_2 = frame_lr_min left right w_target blend, ( w_target < (r_tl.width * 2)) 251 = merge_array blend [[left, middle, right]]; 252 row_3 = frame_lr_min r_bl r_br w_target blend, ( w_target < (r_tl.width * 2)) 253 = merge_array blend [[r_bl, bottom, r_br]]; 254 result = frame_tb_min row_1 row_3 h_target blend, (h_target < (r_tl.height * 2)) 255 = merge_array blend [[row_1], [row_2], [row_3]]; 256 }; 257 258//////////////////////////////////////////////////////////////////////////////// 259/* Function called by complex frame, used to produce section 260 * 261 * Called from: 262 * _NG_utilities.def complex_frame 263 */ 264complex_edge ra rb t bl d = rc 265 { 266 e1 = ceil (ra.width - t)/2, d == 0 267 = 0; 268 e2 = 0, d == 0 269 = ceil (ra.height - t)/2; 270 e3 = t, d == 0 271 = ra.width; 272 e4 = ra.height, d == 0 273 = t; 274 275 check = ra.width, d == 0; 276 = ra.height; 277 278 rai = get_image ra; 279 280 t2 = (t - ra.width + (2 * bl))/2, d == 0 281 = (t - ra.height + (2 * bl))/2; 282 283 rc = ra , t <= 0 284 = Image (im_extract_area rai e1 e2 e3 e4), t <= check 285 = merge_array bl [[rb',ra,rb']], d == 0 286 = merge_array bl [[rb'],[ra],[rb']] 287 {rb' = merge_to_scale rb t2 bl d;} 288 }; 289 290////////////////////////////////////////////////////////////////////////////// 291/* Blends two images left/right to produce an image a specific width. 292 * 293 * _NG_utilities build_frame 294 * _NG_utilities complex_frame 295 */ 296frame_lr_min r_l r_r target bw = result 297 { 298 //Calculating the new widh required for each image. 299 no = (target/2 + bw); 300 n_w = no, (r_l.width > no) 301 = r_l.width; 302 303 //Removing excess from what will be the middle of the final image. 304 n_l = im_extract_area r_l.value 0 0 n_w r_l.height; 305 n_r = im_extract_area r_r.value (r_r.width - n_w) 0 n_w r_l.height; 306 307 //Merge the two image together with a bw*2 pixel overlap. 308 result = Image (im_lrmerge n_l n_r ((bw*2) - n_w) 0 bw); 309 }; 310 311////////////////////////////////////////////////////////////////////////////// 312/* Blends two images top/bottom to produce an image a specific width. 313 * 314 * _NG_utilities build_frame 315 * _NG_utilities complex_frame 316 */ 317frame_tb_min r_t r_b target bw = result 318 { 319 //Calculating the new height required for each image. 320 no = (target/2 + bw); 321 n_h = no, (r_t.height > no) 322 = r_t.height; 323 324 //Removing excess from what will be the middle of the final image. 325 n_t = im_extract_area r_t.value 0 0 r_t.width n_h; 326 n_b = im_extract_area r_b.value 0 (r_b.height - n_h) r_b.width n_h; 327 328 //Merge the two image together with a 50 pixel overlap. 329 result = Image (im_tbmerge n_t n_b 0 ((bw*2) -n_h) bw); 330 }; 331 332////////////////////////////////////////////////////////////////////////////// 333/* Resixe canvas of an image to accomodate a frame and possible mount 334 * 335 * Called from: 336 * _NG_Extra.def Frame_item.Frame_corner_item 337 * _NG_Extra.def Frame_item.Simple_frame_item 338 * _NG_Extra.def Frame_item.Complex_frame_item 339 */ 340frame_position_image im ref os colour= result 341 { 342 background = image_new ref.width ref.height 343 im.bands im.format im.coding im.type colour 0 0; 344 345 result = insert_noexpand xp yp im background 346 { 347 xp = (ref.width - im.width)/2; 348 yp = (ref.height - im.height - os)/2; 349 } 350 }; 351 352////////////////////////////////////////////////////////////////////////////// 353/* Merges an array of images together according to blend width bw 354 * 355 * Called from: 356 * _NG_Utilites.def build_frame 357 * _NG_Utilites.def complex_frame 358 * _NG_Utilites.def complex_edge 359 */ 360merge_array bw arr = result 361 { 362 merge_lr bw im1 im2 = im3 363 { 364 bw' = get_header "Xsize" (get_image im1); 365 bw'' = -(bw' - bw); 366 im3 = im_lrmerge (get_image im1) (get_image im2) bw'' 0 bw; 367 } 368 merge_tb bw im1 im2 = im3 369 { 370 bw' = get_header "Ysize" (get_image im1); 371 bw'' = -(bw' - bw); 372 im3 = im_tbmerge (get_image im1) (get_image im2) 0 bw'' bw; 373 } 374 375 im_out = (image_set_origin 0 0 @ 376 foldl1 (merge_tb bw) @ 377 map (foldl1 (merge_lr bw))) arr; 378 result = Image im_out; 379 }; 380 381////////////////////////////////////////////////////////////////////////////// 382/* Repeatably top/bottom add clones of im, with a defined overlap, until final height > target 383 * 384 * Called from: 385 * _NG_Utilites.def build_frame 386 * _NG_Utilites.def complex_edge 387 */ 388merge_to_scale im target blend dir = result 389 { 390 blend' = floor blend; 391 392 //allow fir lr or tb process 393 var_a = im.width, dir == 0 394 = im.height; 395 396 var_w = im.width, dir == 1 397 = target, target > blend' 398 = blend'; 399 var_h = im.height, dir == 0 400 = target, target > blend' 401 = blend'; 402 403 //total numner of copies of im requires, taking overlap into account. 404 no_loops = ceil ((log ((target - blend')/(var_a - blend')))/(log 2)); 405 406 process im no = result 407 { 408 pr_a = get_header "Xsize" (get_image im), dir == 0 409 = get_header "Ysize" (get_image im); 410 pr_b = -(pr_a - blend' + 1); 411 412 im' = im_lrmerge (get_image im) (get_image im) pr_b 0 blend', dir == 0 413 = im_tbmerge (get_image im) (get_image im) 0 pr_b blend'; 414 no' = no - 1; 415 416 result = im', no' < 1 417 = process im' no'; 418 } 419 420 im_tmp = im.value, var_a > target 421 = process im no_loops; 422 423 result = Image (im_extract_area (get_image im_tmp) 0 0 var_w var_h); 424 }; 425 426////////////////////////////////////////////////////////////////////////////// 427/* Selects an elispe based on a line and a width 428 * 429 * Called from: 430 * _NG_Extra.def Select_item.Elipse 431 */ 432select_ellipse line width = mask 433 { 434 im = Image (get_image line); 435 436 //Make a 2 band image whose value equals its coordinates. 437 im_coor = Image (make_xy im.width im.height); 438 439 //Adjust the values to center tham on (line.left, line.top) 440 im_cent = im_coor - Vector [line.left,line.top]; 441 442 w = line.width; 443 h = line.height; 444 445 angle = 270, w == 0 && h < 0 446 = 90, w == 0 && h >= 0 447 = 360 + atan (h/w), w > 0 && h < 0 448 = atan (h/w), w > 0 && h >= 0 449 = 180 + atan (h/w); 450 451 a = ( (h ** 2) + (w ** 2) )**0.5; 452 b = a * width; 453 454 x' = ( (cos angle) * im_cent?0) + ( (sin angle) * im_cent?1); 455 y' = ( (cos angle) * im_cent?1) - ( (sin angle) * im_cent?0); 456 457 mask = ( (b**2) * (x'**2) ) + ( (a**2) * (y'**2) ) <= (a * b)**2; 458 }; 459 460////////////////////////////////////////////////////////////////////////////// 461/* Selects a tetragon based on four points. 462 * 463 * Called from: 464 * _NG_Extra.def Select_item.Tetragon 465 * _NG_Extra.def Perspective_item 466 */ 467select_tetragon p1 p2 p3 p4 = mask 468 { 469 //Put points in clockwise order starting at the top left. 470 pt_list = sort_pts_clockwise [p1, p2, p3, p4]; 471 472 pair_list = [ 473 [ pt_list?0, pt_list?1 ], 474 [ pt_list?1, pt_list?2 ], 475 [ pt_list?2, pt_list?3 ], 476 [ pt_list?3, pt_list?0 ] ]; 477 478 //Make xy image the same size as p1.image; 479 im_xy = Image (make_xy p1.image.width p1.image.height); 480 white = Image (image_new p1.image.width p1.image.height 1 0 Image_coding.NOCODING 1 255 0 0); 481 482 mask = foldl process white pair_list; 483 484 /* Treat each pair of point as a vector going from p1 to p2, 485 * then select all to right of line. This is done for each pair, 486 * the results are all combined to select the area defined by 487 * the four points. 488 */ 489 process im_in pair = im_out 490 { 491 x = (pair?0).left; 492 y = (pair?0).top; 493 x'= (pair?1).left; 494 y'= (pair?1).top; 495 496 w = x' - x; 497 h = y' - y; 498 499 m = 0, x == x' 500 = (y-y')/(x-x'); 501 c = 0, x == x' 502 = ((y*x') - (y'*x))/(x' - x); 503 504 mask= im_xy?1 - (im_xy?0 * m) >= c, w > 0 505 = im_xy?1 - (im_xy?0 * m) <= c, w < 0 506 = im_xy?0 <= x, w == 0 && h > 0 507 = im_xy?0 >= x; 508 509 im_out = im_in & mask; 510 } 511 }; 512 513////////////////////////////////////////////////////////////////////////////// 514/* Selects a tetragon based on four points. 515 * 516 * Called from: 517 * _NG_Extra.def Select_item.Polygon 518 */ 519select_polygon pt_list = mask 520 { 521 group_check = is_Group pt_list; 522 pt_l = pt_list.value, group_check 523 = pt_list; 524 525 im = Image (get_image (pt_l?0)); 526 im_xy = Image (make_xy im.width im.height); 527 black = Image (image_new im_xy.width im_xy.height 1 0 Image_coding.NOCODING 1 0 0 0); 528 529 x = im_xy?0; 530 y = im_xy?1; 531 532 pt_l' = grp_trip pt_l; 533 534 mask = foldl process black pt_l'; 535 536 /*Takes a group adds the first two the end and then creates a lists of 537 *lists [[a, b, c], [b, c, d] .... [x, a, b]] 538 */ 539 grp_trip l = l'' 540 { 541 px = take 2 l; 542 l' = join l px; 543 start = [(take 3 l')]; 544 rest = drop 3 l'; 545 546 process a b = c 547 { 548 x = (last a)?1; 549 x'= (last a)?2; 550 x'' = [[x, x', b]]; 551 c = join a x''; 552 } 553 554 l'' = foldl process start rest; 555 }; 556 557 process im_in triplet = im_out 558 { 559 p1 = triplet?0; 560 p2 = triplet?1; 561 p3 = triplet?2; 562 563 //check for change in x direction between p1-p2 and p2 -p3 564 dir_1 = sign (p2.left - p1.left); 565 dir_2 = sign (p3.left - p2.left); 566 dir = dir_1 + dir_2; 567 568 //define min x limit. 569 min_x = p1.left, p1.left < p2.left 570 = p2.left + 1, dir != 0 571 = p2.left; 572 573 //define max x limit. 574 max_x = p1.left, p1.left > p2.left 575 = p2.left - 1, dir != 0 576 = p2.left; 577 578 //equation of line defined by p1 and p2 579 m = line_m p1 p2; 580 c = line_c p1 p2; 581 582 //Every thing below the line 583 im_test = ((y >= (m * x) + c) & (x >= min_x) & (x <= max_x)); 584 585 im_out = im_in ^ im_test; 586 } 587 588 line_c p1 p2 = c 589 {m = line_m p1 p2; 590 c = p1.top - (m * p1.left);}; 591 592 line_m p1 p2 = (p2.top - p1.top)/(p2.left - p1.left), p2.left != p1.left 593 = 0; 594 }; 595 596////////////////////////////////////////////////////////////////////////////// 597/* Selects a tetragon based on four points. 598 * 599 * Called from: 600 * _NG_Extra.def Perspective_match_item 601 * _NG_Extra.def Perspective_item 602 */ 603perspective_transform to from = trans'' 604 { 605 /* 606 * Tramsformation matrix is calculated on the bases of the following functions: 607 * x' = c0x + c1y + c2xy + c3 608 * y' = c4x + c5y + c6xy + c7 609 * 610 * The functions used in vips im_transform works based on the functions: 611 * x = x' + b0 + b2x' + b4y' + b6x'y' 612 * y = y' + b1 + b3x' + b5y' + b7x'y' 613 * 614 * and is applied in the form of the matrix: 615 * 616 * [[b0, b1], 617 * [b2, b3], 618 * [b4, b5], 619 * [b6, b7]] 620 * 621 * Therefore our required calculated matrix will be 622 * 623 * [[ c3 , c7], 624 * [(c0 - 1) , c4], 625 * [ c1 , (c5 - 1)], 626 * [ c2 , c6]] 627 * 628 * to = [x1, y1, x2, y2, x3, y3, x4, y4] 629 * from = [x1', y1', x2', y2', x3', y3', x4', y4'] 630 * trans = [[c0], [c1], [c2], [c3], [c4], [c5], [c6], [c7]] 631 * 632 */ 633 634 to' = Matrix 635 [[to?0, to?1, ((to?0)*(to?1)), 1, 0, 0, 0, 0], 636 [0, 0, 0, 0, to?0, to?1, ((to?0)*(to?1)), 1], 637 [to?2, to?3, ((to?2)*(to?3)), 1, 0, 0, 0, 0], 638 [0, 0, 0, 0, to?2, to?3, ((to?2)*(to?3)), 1], 639 [to?4, to?5, ((to?4)*(to?5)), 1, 0, 0, 0, 0], 640 [0, 0, 0, 0, to?4, to?5, ((to?4)*(to?5)), 1], 641 [to?6, to?7, ((to?6)*(to?7)), 1, 0, 0, 0, 0], 642 [0, 0, 0, 0, to?6, to?7, ((to?6)*(to?7)), 1]]; 643 644 from' = Matrix (transpose [from]); 645 646 to'' = to' ** (-1); 647 648 trans = to'' * from'; 649 trans' = trans.value; 650 trans''= Matrix [[(trans'?3)?0, (trans'?7)?0 ], 651 [((trans'?0)?0 - 1), (trans'?4)?0 ], 652 [(trans'?1)?0, ((trans'?5)?0 - 1)], 653 [(trans'?2)?0, (trans'?6)?0 ]]; 654 }; 655 656////////////////////////////////////////////////////////////////////////////// 657/* Sort a list of points into clockwise order. 658 * 659 * Called from: 660 * _NG_utilities.def select_tetragon 661 * _NG_Extra.def Perspective_match_item 662 * _NG_Extra.def Perspective_item 663 */ 664sort_pts_clockwise l = l'' 665 { 666 // sort functions: 667 f_top a b = a.top < b.top; 668 f_left a b = a.left < b.left; 669 f_right a b = a.left > b.left; 670 671 l' = sortc f_top l; 672 l'_a = take 2 l'; 673 l'_b = drop 2 l'; 674 675 l''_a = sortc f_left l'_a; 676 l''_b = sortc f_right l'_b; 677 l'' = join l''_a l''_b; 678 }; 679 680Mount_options _ctype _ppcm = class 681 { 682 _vislevel = 3; 683 apply = Toggle "Apply mount options" false; 684 ls = Expression "Lower mount section bigger by (cm)" 0; 685 mount_colour = Colour _ctype [0, 0, 0]; 686 _los = ls.expr * _ppcm; 687 }; 688 689Frame_variables comp = class 690 { 691 _vislevel = 3; 692 693 scale_factor = Expression "scale the size of the frame by" 1; 694 695 /* These sliders define the fraction of the frames width or height is extracted 696 * to produce each of the particular regions. 697 */ 698 corner_section = Scale "Corner section" 0.1 1 0.5; 699 edge_section = Scale "Edge section" 0.1 1 0.2, comp > 0 700 = "Only required for complex frames"; 701 middle_section = Scale "Middle section" 0.1 1 0.2; 702 blend_fraction = Scale "Blend fraction" 0.1 0.9 0.1; 703 option = Toggle "Use mirror of left-side to make right" true; 704 }; 705 706