1/* DINImport.m 2 * DIN import object (Drill data import) 3 * 4 * Copyright (C) 1996-2012 by vhf interservice GmbH 5 * Author: Ilonka Fleischmann 6 * 7 * created: 1996-05-03 8 * modified: 2012-06-18 (leading zero support added (LZ), clean-up) 9 * 2006-11-04 10 * 11 * This file is part of the vhf Import Library. 12 * 13 * This library is free software; you can redistribute it and/or 14 * modify it under the terms of the vhf Public License as 15 * published by the vhf interservice GmbH. Among other things, 16 * the License requires that the copyright notices and this notice 17 * be preserved on all copies. 18 * 19 * This library is distributed in the hope that it will be useful, 20 * but WITHOUT ANY WARRANTY; without even the implied warranty of 21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 22 * See the vhf Public License for more details. 23 * 24 * You should have received a copy of the vhf Public License along 25 * with this library; see the file LICENSE. If not, write to vhf. 26 * 27 * If you want to link this library to your proprietary software, 28 * or for other uses which are not covered by the definitions 29 * laid down in the vhf Public License, vhf also offers a proprietary 30 * license scheme. See the vhf internet pages or ask for details. 31 * 32 * vhf interservice GmbH, Im Marxle 3, 72119 Altingen, Germany 33 * eMail: info@vhf.de 34 * http://www.vhf.de 35 */ 36 37#include <math.h> 38 39#include "DINImport.h" 40#include "../VHFShared/vhfCFGFunctions.h" 41#include "../VHFShared/types.h" 42#include "../VHFShared/VHFStringAdditions.h" 43#include "../VHFShared/vhf2DFunctions.h" 44 45/* r in points/inch */ 46#define InternalToDeviceRes(a, r) ((float)(a) * (float)(r) / 72.0) 47#define DeviceResToInternal(a, r) ((float)(a) * 72.0 / (float)(r)) 48 49/* the following characters may apear as digits in a coordinate */ 50#define DIGITS @".+-0123456789" 51 52 53@interface DINImport(PrivateMethods) 54- importDIN:(NSData*)DINData; 55- (BOOL)checkFileFormat:(NSString*)dinStr; 56- (BOOL)loadApertures:(NSString*)toolStr; 57- (void)loadSM1000Apertures:(NSScanner*)scanner; 58- (void)loadSM3000Apertures:(NSScanner*)scanner; 59- (void)loadExcellonApertures:(NSScanner*)scanner; 60- (BOOL)interpret:(NSString*)dataP; 61- (BOOL)getGraphicFromData:(NSScanner*)scanner :cList; 62- (BOOL)getToolFromData:(NSScanner*)scanner :(NSString*)macroData :(NSString**)code :(float*)w :(float*)h :(NSString**)formCode :(NSString**)macroStr; 63- (BOOL)getTool:(NSScanner*)scanner; 64- (BOOL)getPlotAbs:(NSScanner*)scanner; 65- (BOOL)getPlotRel:(NSScanner*)scanner; 66- (void)setArc:cList; 67- (void)setLine:cList; 68- (void)setMark:cList; 69- (void)updateBounds:(NSPoint)p; 70@end 71 72@implementation DINImport 73 74- init 75{ 76 self = [super init]; 77 78 [self setDefaultParameter]; 79 parameterLoaded = 0; 80 fileFormat = 0; 81 82 res = 1000.0; 83 tz = YES; // trailing zeros 84 85 state.inch = 1; // inch 86 state.pa = 1; 87 88 state.tool = 0; 89 state.point.x = state.point.y = LARGENEG_COORD; 90 state.g = 0; 91 state.x = state.y = 0.0; 92 state.a = state.c = 0.0; 93 state.path = 0; 94 state.offset = 0; 95 return self; 96} 97 98- (void)setDefaultParameter 99{ 100 switch (fileFormat) 101 { 102 case DIN_SM3000: 103 ops.start = @"%%3000"; 104 res = 25400.0; 105 ops.prgend = @"$"; 106 ops.coordC = @"D"; // diameter of tool 107 break; 108 case DIN_SM1000: 109 ops.start = @"%%1000"; 110 res = 25400.0; 111 ops.prgend = @"$"; 112 ops.coordC = @""; // diameter of tool 113 break; 114 default: 115 ops.start = @"%"; 116 res = 10000.0; 117 ops.prgend = @"M30"; 118 ops.coordC = @"C"; // diameter of tool 119 } 120 resMM = 25400.0; 121 tz = YES; // trailing zeros 122 ops.offset = @"M50"; 123 ops.mm = @"M71"; 124 ops.reset = @""; 125 ops.selectTool = @"T"; 126 ops.coordX = @"X"; 127 ops.coordY = @"Y"; 128 ops.coordR = @"R"; // radius of circle 129 ops.plotAbs = @"G90"; 130 ops.plotRel = @"G91"; 131 ops.termi = @"\n"; 132 //ops.polyBegin = @"G41"; // left 133 //ops.polyBegin2 = @"G42"; // right 134 //ops.polyEnd = @"G40"; 135 ops.comment = @"/"; 136 ops.line = @"G1"; // G01 137 ops.circleCW = @"G2"; // G02 138 ops.circleCCW = @"G3"; // G03 139 ops.drill = @"G05"; 140} 141 142- (BOOL)checkFileFormat:(NSString*)dinStr 143{ NSScanner *scanner = [NSScanner scannerWithString:dinStr]; 144 int location; 145 146 location = [scanner scanLocation]; 147 [scanner scanUpToString:@"%%1000" intoString:NULL]; 148 if ( [scanner scanString:@"%%1000" intoString:NULL] ) 149 { fileFormat = DIN_SM1000; 150 return YES; 151 } 152 [scanner setScanLocation:location]; 153 [scanner scanUpToString:@"%%3000" intoString:NULL]; 154 if ( [scanner scanString:@"%%3000" intoString:NULL] ) 155 { fileFormat = DIN_SM3000; 156 return YES; 157 } 158 fileFormat = DIN_EXCELLON; 159 return YES; 160/* 161 [scanner setScanLocation:location]; 162 [scanner scanUpToString:@"G05" intoString:NULL]; // 2 163 if ( [scanner scanString:@"G05" intoString:NULL] ) 164 { fileFormat = DIN_EXCELLON; 165 return YES; 166 } 167 [scanner setScanLocation:location]; 168 [scanner scanUpToString:@"G81" intoString:NULL]; // 1 169 if ( [scanner scanString:@"G81" intoString:NULL] ) 170 { fileFormat = DIN_EXCELLON; 171 return YES; 172 } 173 [scanner setScanLocation:location]; 174 [scanner scanUpToString:@"M72" intoString:NULL]; 175 if ( [scanner scanString:@"M72" intoString:NULL] ) 176 { fileFormat = DIN_EXCELLON; 177 return YES; 178 } 179 [scanner setScanLocation:location]; 180 [scanner scanUpToString:@"M71" intoString:NULL]; 181 if ( [scanner scanString:@"M71" intoString:NULL] ) 182 { fileFormat = DIN_EXCELLON; 183 return YES; 184 } 185 [scanner setScanLocation:location]; 186 [scanner scanUpToString:@"INCH" intoString:NULL]; 187 if ( [scanner scanString:@"INCH" intoString:NULL] ) 188 { fileFormat = DIN_EXCELLON; 189 return YES; 190 } 191 192 [scanner setScanLocation:location]; 193 [scanner scanUpToString:@"METRIC" intoString:NULL]; 194 if ( [scanner scanString:@"METRIC" intoString:NULL] ) 195 { fileFormat = DIN_EXCELLON; 196 return YES; 197 } 198 return NO; 199*/ 200} 201 202/* created: 03.05.96 203 * modified: 07.03.97 204 * parameter: fileName 205 * purpose: load parameter file 206 */ 207- (BOOL)loadParameter:(NSString*)fileName 208{ NSMutableString *parmData; 209 NSString *val; 210 211 [self setDefaultParameter]; 212 213 if ( !(parmData = [NSMutableString stringWithContentsOfFile:fileName]) ) 214 return NO; 215 216 parameterLoaded = 1; 217 218 if ( 1 )// fileFormat == DIN_EXCELLON 219 { vhfGetTypesFromData(parmData, @"f", @"#RMM", &resMM); 220 ops.comment = vhfGetStringFromData(parmData, @"#REM"); 221 ops.mm = vhfGetStringFromData(parmData, @"#UMM"); 222 } 223 vhfGetTypesFromData(parmData, @"f", @"#RES", &res); 224 225 ops.init = vhfGetStringFromData(parmData, @"#INI"); 226 ops.reset = vhfGetStringFromData(parmData, @"#RST"); 227 ops.selectTool = vhfGetStringFromData(parmData, @"#ITL"); 228 if ( (val = vhfGetStringFromData(parmData, @"#IST")) ) 229 ops.start = val; 230 ops.coordX = vhfGetStringFromData(parmData, @"#IXP"); 231 ops.coordY = vhfGetStringFromData(parmData, @"#IYP"); 232 ops.coordC = vhfGetStringFromData(parmData, @"#IDM"); 233 //ops.coordI = vhfGetStringFromData(parmData, @"#IIP"); 234 //ops.coordJ = vhfGetStringFromData(parmData, @"#IJP"); 235 //ops.circle = vhfGetStringFromData(parmData, @"#ICI"); 236 //ops.arc = vhfGetStringFromData(parmData, @"#IAR"); 237 ops.termi = vhfGetStringFromData(parmData, @"#ITM"); 238 239 return YES; 240} 241 242/* 243 * modified: 03.05.93 05.05.96 19.09.96 07.03.97 244 * purpose: load tools from aperture table 245 * parameter: filename 246 * 247 * "code" = "D10" 248 * "formCode" = "C", "O" or "R" 249 * "typeCode" = "L", "P", or "A" 250 * "width" = width of tool 251 * "height" = height od tool 252 */ 253- (BOOL)loadApertures:(NSString*)toolStr 254{ NSScanner *scanner = [NSScanner scannerWithString:toolStr]; 255 256 if ( !scanner ) 257 return NO; 258 259 // NSScanner else jump over \n (default) 260 [scanner setCharactersToBeSkipped:[NSCharacterSet whitespaceCharacterSet]]; 261 262 [tools release]; 263 tools = [[NSMutableArray array] retain]; 264 265 switch (fileFormat) 266 { 267 case DIN_SM1000: [self loadSM1000Apertures:scanner]; break; 268 case DIN_SM3000: [self loadSM3000Apertures:scanner]; break; 269 case DIN_EXCELLON: [self loadExcellonApertures:scanner]; break; 270 default: NSLog(@"DINImport: loadApertures no valid fileFormat."); 271 } 272 return YES; 273} 274 275- (void)loadSM1000Apertures:(NSScanner*)scanner 276{ NSString *parameter = @"$"; 277 int i, value, cnt = 1; 278 279 // $80$50$20$99$15$500 6 times $ at end 280 281 while (![scanner isAtEnd]) 282 { 283 for (i=1; i<7; i++) // six times 284 { 285 [scanner scanUpToString:parameter intoString:NULL]; 286 if ( [scanner scanString:parameter intoString:NULL] && i == 1 ) // first of six values is diameter 287 { NSMutableDictionary *dict = [NSMutableDictionary dictionary]; 288 float dia; 289 290 if ( ![scanner scanInt:&value] ) 291 return; // last $ 292 dia = DeviceResToInternal(value, res); // in same mannor like coordinates 293 if ( !dia ) 294 return; // last - format says 15 tools must be defined - we assume 0 is last 295 [dict setObject:[NSString stringWithFormat:@"T%d", cnt] forKey:@"code"]; 296 [dict setObject:[NSNumber numberWithFloat:dia] forKey:@"diameter"]; 297 [tools addObject:dict]; 298 cnt++; 299 } 300 } 301 } 302} 303 304- (void)loadSM3000Apertures:(NSScanner*)scanner 305{ NSString *parameter = @"$", *parmDia = @"D", *codeStr; 306 int i, value, location = [scanner scanLocation]; 307 float dia; 308 309 // $ 310 // T1D80S50F20R99N15A500T2D50... 311 312 [scanner scanUpToString:parameter intoString:NULL]; 313 if ( ![scanner scanString:parameter intoString:NULL] ) 314 return; // no tools 315 316 while (![scanner isAtEnd]) 317 { 318 [scanner scanUpToString:ops.selectTool intoString:NULL]; 319 if ( [scanner scanString:ops.selectTool intoString:NULL] ) 320 { NSMutableDictionary *dict = [NSMutableDictionary dictionary]; 321 322 if ( ![scanner scanInt:&value] ) 323 return; 324 codeStr = [NSString stringWithFormat:@"T%d", value]; 325 if ( [scanner scanString:parmDia intoString:NULL] ) 326 { if ( ![scanner scanInt:&value] ) 327 return; 328 } 329 dia = DeviceResToInternal(value, res); // in same mannor like coordinates 330 if ( !dia ) 331 return; // we assume 0 is last 332 [dict setObject:codeStr forKey:@"code"]; 333 [dict setObject:[NSNumber numberWithFloat:dia] forKey:@"diameter"]; 334 [tools addObject:dict]; 335 } 336 else 337 break; // no more tools 338 } 339 // if X|Y values are realy floatValues -> 01.123 -> -> res = 1.0 !!!!!!!!!!!!! 340 [scanner setScanLocation:location]; 341 for (i=0; i<3 && ![scanner isAtEnd]; i++) 342 { [scanner scanUpToString:ops.coordX intoString:NULL]; 343 if ( [scanner scanString:ops.coordX intoString:NULL] ) 344 { NSString *str; 345 NSCharacterSet *stopSet = [NSCharacterSet characterSetWithCharactersInString:@"\nY"]; 346 347 if ( [scanner scanUpToCharactersFromSet:stopSet intoString:&str] ) 348 { NSRange range = [str rangeOfString:@"."]; 349 state.inch = 0; 350 if ( range.length && state.inch ) 351 res = 1.0; 352 else if ( range.length && !state.inch ) 353 res = 25.4; 354 return; 355 } 356 } 357 } 358} 359 360- (void)loadExcellonApertures:(NSScanner*)scanner 361{ NSString *parmDia = @"C", *codeStr; 362 int value, location = [scanner scanLocation], inchLoc=0, mmLoc=0; 363 float dia; 364 NSCharacterSet *stopSet = [NSCharacterSet characterSetWithCharactersInString:@"TC"]; 365 366 // get state.inch, state.pa and correct perhaps res 367 368 [scanner scanUpToString:@"LZ" intoString:NULL]; // leading zeros 369 if ( [scanner scanString:@"LZ" intoString:NULL] ) 370 tz = NO; // leading zeros 371 // TODO: there is also "TZ" = trailing zeros, and "FMAT,2" 372 373 [scanner setScanLocation:location]; 374 [scanner scanUpToString:@"G91" intoString:NULL]; // relative 375 if ( [scanner scanString:@"G91" intoString:NULL] ) 376 state.pa = 0; 377 378 [scanner setScanLocation:location]; 379 [scanner scanUpToString:@"INCH" intoString:NULL]; // inch 380 if ( [scanner scanString:@"INCH" intoString:NULL] ) 381 inchLoc = [scanner scanLocation]; 382 [scanner setScanLocation:location]; 383 [scanner scanUpToString:@"M72" intoString:NULL]; // inch 384 if ( [scanner scanString:@"M72" intoString:NULL] ) 385 { if ( !inchLoc || inchLoc > (int)[scanner scanLocation] ) 386 inchLoc = [scanner scanLocation]; 387 } 388 [scanner setScanLocation:location]; 389 [scanner scanUpToString:@"M71" intoString:NULL]; // mm 390 if ( [scanner scanString:@"M71" intoString:NULL] ) 391 mmLoc = [scanner scanLocation]; 392 [scanner setScanLocation:location]; 393 [scanner scanUpToString:@"METRIC" intoString:NULL]; // mm 394 if ( [scanner scanString:@"METRIC" intoString:NULL] ) 395 { if ( !mmLoc || mmLoc > (int)[scanner scanLocation] ) 396 mmLoc = [scanner scanLocation]; 397 } 398 [scanner setScanLocation:location]; 399 [scanner scanUpToString:ops.mm intoString:NULL]; // mm (from device file) 400 if ( [scanner scanString:ops.mm intoString:NULL] ) 401 { if ( !mmLoc || mmLoc > (int)[scanner scanLocation] ) 402 mmLoc = [scanner scanLocation]; 403 } 404 state.inch = ( (mmLoc && inchLoc && mmLoc < inchLoc) || (mmLoc && !inchLoc) ) ? 0 : 1; // mm is first 405 406 // T1 C.04 F200 S65 407 // T2 C.05 F200 S65 408 // % // prg start 409 410 // T1 C.04 411 // X123Y234... 412 413 // T1 no C follows is possible -> than C values must be befor % (start of prg) 414 // else no tools are declared 415 [scanner setScanLocation:location]; 416 while (![scanner isAtEnd]) 417 { 418 [scanner scanUpToCharactersFromSet:stopSet intoString:NULL]; 419 420 if ( [scanner scanString:ops.selectTool intoString:NULL] ) // T 421 { NSMutableDictionary *dict = [NSMutableDictionary dictionary]; 422 423 if (![scanner scanInt:&value]) 424 continue; 425 codeStr = [NSString stringWithFormat:@"T%d", value]; 426 427 [scanner scanUpToCharactersFromSet:stopSet intoString:NULL]; 428 if (![scanner scanString:parmDia intoString:NULL]) // C 429 continue; // METRIC or something ? break; // no C follows -> end of tool init 430 if (![scanner scanFloat:&dia]) 431 continue; 432 if (!state.inch) 433 dia /= 25.4; // mm/ 25.4 -> inch 434 dia *= INCH; // diameter is spezified with dot 435 if ( !dia ) 436 { state.inch = ( mmLoc > inchLoc ) ? 0 : 1; 437 break; // we assume 0 is last 438 } 439 [dict setObject:codeStr forKey:@"code"]; 440 [dict setObject:[NSNumber numberWithFloat:dia] forKey:@"diameter"]; 441 [tools addObject:dict]; 442 } 443 else if (![scanner isAtEnd]) 444 [scanner setScanLocation:[scanner scanLocation]+1]; // break; // no more tools 445 else break; 446 } 447 state.inch = ( mmLoc > inchLoc ) ? 0 : 1; 448 449 if ( !state.inch ) 450 res = resMM; 451 452 // if X|Y values are realy floatValues -> 01.123 -> -> res = 1.0 !!!!!!!!!!!!! 453 [scanner setScanLocation:location]; 454 [scanner scanUpToString:ops.coordX intoString:NULL]; 455 if ( [scanner scanString:ops.coordX intoString:NULL] ) 456 { NSString *str; 457 NSCharacterSet *stopSet = [NSCharacterSet characterSetWithCharactersInString:@"\nY"]; 458 459 if ( [scanner scanUpToCharactersFromSet:stopSet intoString:&str] ) 460 { NSRange range = [str rangeOfString:@"."]; 461 462 if ( range.length && state.inch ) 463 res = 1.0; 464 else if ( range.length && !state.inch ) 465 res = 25.4; 466 } 467 } 468} 469 470/* created: 2001-01-27 471 * modified: 2002-10-26 472 * parameter: DINData the DIN data stream 473 * purpose: start interpretation of the contents of DINData 474 */ 475- importDIN:(NSData*)DINData 476{ NSString *dinStr = [[[NSString alloc] initWithData:DINData 477 encoding:NSASCIIStringEncoding] autorelease]; 478 479 state.color = [NSColor colorWithCalibratedRed:0.0 green:0.0 blue:0.0 alpha:1.0]; 480 state.width = 0.0; 481 482 [self checkFileFormat:dinStr]; 483 484 if ( !parameterLoaded ) 485 [self setDefaultParameter]; 486 487 [self loadApertures:dinStr]; 488 489 if ( ![tools count] ) 490 NSLog(@"No tools loaded !"); 491 492 /* interpret data 493 */ 494 if ( ![self interpret:dinStr] ) 495 return 0; 496 497 return [list autorelease]; 498} 499 500/* private methods 501 */ 502- (BOOL)interpret:(NSString*)dataP 503{ int startLocation; 504 NSRect bounds; 505 NSScanner *scanner = [NSScanner scannerWithString:dataP]; 506 507 digitsSet = [NSCharacterSet characterSetWithCharactersInString:DIGITS]; 508 invDigitsSet = [digitsSet invertedSet]; 509 // NSScanner else jump over \n (default) 510 [scanner setCharactersToBeSkipped:[NSCharacterSet whitespaceCharacterSet]]; 511 512 startLocation = [scanner scanLocation]; 513 /* init bounds */ 514 ll.x = ll.y = LARGE_COORD; 515 ur.x = ur.y = LARGENEG_COORD; 516 517 list = [self allocateList]; 518 519 // set scanner to start of programm (%%1000 or %%3000) 520 // if ( fileFormat != DIN_EXCELLON ) 521 { 522 [scanner scanUpToString:ops.start intoString:NULL]; 523 if ( ![scanner scanString:ops.start intoString:NULL] ) 524 { 525 if ( fileFormat == DIN_EXCELLON ) 526 [scanner setScanLocation:startLocation]; 527 else 528 { NSLog(@"DINImport: No start sign (%@) found", ops.start); 529 return NO; 530 } 531 } 532 } 533 534 while ( ![scanner isAtEnd] ) 535 if ( ![self getGraphicFromData:scanner :list] ) 536 break; 537 538 bounds.origin = ll; 539 bounds.size.width = ur.x - ll.x; 540 bounds.size.height = ur.y - ll.y; 541 542 [self setBounds:bounds]; 543 return YES; 544} 545 546/* we need cp on a number ! 547 */ 548- (BOOL)getGraphicFromData:(NSScanner*)scanner :cList 549{ int location; 550 float value; 551 NSString *str = nil; 552 553 location = [scanner scanLocation]; 554 555 if ( [scanner scanString:ops.termi intoString:NULL] ) // else we jump over \n 556 { 557 if ( state.draw ) 558 { 559 switch (state.g) 560 { 561 case DIN_LINE: 562 [self setLine:cList]; 563 break; 564 case DIN_ARC: 565 [self setArc:cList]; 566 break; 567 /*case DIN_PATH: 568 [self setPath:scanner :cList]; 569 break;*/ 570 default: 571 [self setMark:cList]; 572 } 573 if (!state.offset) 574 { state.point.x = state.x; 575 state.point.y = state.y; 576 } 577 else state.offset = 0; 578 state.draw = 0; 579 } 580 } 581 else if ( [scanner scanString:ops.comment intoString:NULL] ) 582 { [scanner scanUpToString:ops.termi intoString:NULL]; 583 [scanner scanString:ops.termi intoString:NULL]; 584 } 585 else if ( [scanner scanString:ops.offset intoString:NULL] ) // relativ M50 586 state.offset = 1; 587 //else if ( [scanner scanString:ops.drill intoString:NULL] ) 588 // state.g = 0; 589 else if ( [scanner scanString:ops.line intoString:NULL] ) 590 state.g = DIN_LINE; 591 else if ( [scanner scanString:ops.circleCW intoString:NULL] ) 592 { state.g = DIN_ARC; 593 state.ccw = 0; 594 } 595 else if ( [scanner scanString:ops.circleCCW intoString:NULL] ) 596 { state.g = DIN_ARC; 597 state.ccw = 1; 598 } 599 /*else if ( [scanner scanString:ops.polyBegin intoString:NULL] || [scanner scanString:ops.polyBegin2 intoString:NULL] ) 600 { state.g = DIN_PATH; 601 state.path = 1; 602 } 603 else if ( [scanner scanString:ops.polyEnd intoString:NULL] ) 604 { state.g = 0; 605 state.path = 0; 606 }*/ 607 else if ( [scanner scanString:ops.coordX intoString:NULL] ) 608 { 609 if ( [scanner scanCharactersFromSet:digitsSet intoString:&str] ) 610 //if ( [scanner scanFloat:&value] ) 611 { //state.point.x = state.x; 612 value = [str floatValue]; 613 if ( ! tz ) // leading zeros 614 value *= pow(10, 7 - [str length]); 615 state.x = DeviceResToInternal(value, res); 616 state.draw = 1; 617 } 618 else 619 { state.x = 0; 620// NSLog(@"Coordinate X expected at location: %d", [scanner scanLocation]); 621 } 622 } 623 else if ( [scanner scanString:ops.coordY intoString:NULL] ) 624 { 625 if ( [scanner scanCharactersFromSet:digitsSet intoString:&str] ) 626 //if ( [scanner scanFloat:&value] ) 627 { //state.point.y = state.y; 628 value = [str floatValue]; 629 if ( ! tz ) // leading zeros 630 value *= pow(10, 7 - [str length]); 631 state.y = DeviceResToInternal(value, res); 632 state.draw = 1; 633 } 634 else 635 { state.y = 0; 636// NSLog(@"Coordinate Y expected at location: %d", [scanner scanLocation]); 637 } 638 } 639 else if ( [scanner scanString:ops.coordR intoString:NULL] ) 640 { 641 if ( [scanner scanCharactersFromSet:digitsSet intoString:&str] ) 642 //if ( [scanner scanFloat:&value] ) 643 { value = [str floatValue]; 644 if ( ! tz ) // leading zeros 645 value *= pow(10, 7 - [str length]); 646 state.a = DeviceResToInternal(value, res); 647 state.draw = 1; 648 } 649 else 650 NSLog(@"Coordinate R expected at location: %d", [scanner scanLocation]); 651 } 652 else if ( [scanner scanString:ops.selectTool intoString:NULL] ) 653// [self getTool:scanner]; 654 { if (![self getTool:scanner]) 655 { // move 656 state.point.x = state.x; 657 state.point.y = state.y; 658// state.draw = 0; 659 } 660 661 } 662 else if ( [scanner scanString:ops.plotAbs intoString:NULL] ) 663 [self getPlotAbs:scanner]; 664 else if ( [scanner scanString:ops.plotRel intoString:NULL] ) 665 [self getPlotRel:scanner]; 666 else if ( [scanner scanString:ops.prgend intoString:NULL] ) 667 return NO; 668 else 669 { // we cant step until termi cause we run over next statement if blank or \n follows ! 670 if ( [scanner isAtEnd] ) 671 return NO; 672 [scanner setScanLocation:location+1]; 673 return YES; 674 } 675 return YES; 676} 677 678/* 679 * created: 02.05.93 680 * modified: 02.05.93 19.07.93 05.05.96 07.03.97 681 * purpose: return tool number of specified tool (cp = "D10* ...") 682 * parameter: scanner 683 * return value: index of tool 684 */ 685- (int)toolFromString:(NSScanner*)scanner 686{ int i, d, cnt = [tools count]; 687 688 if (![scanner scanInt:&d]) 689 return -2; // move - we need current tool 690 for (i=0; i<cnt; i++) 691 { NSString *code = [[tools objectAtIndex:i] objectForKey:@"code"]; 692 int d1 = [[code substringFromIndex:[code rangeOfCharacterFromSet:digitsSet].location] intValue]; 693 694 if ( d==d1 ) 695 return i; 696 } 697 return -1; 698} 699 700/* 701 * created: xx.12.92 702 * modified: 02.05.93 19.07.93 05.05.96 08.03.97 703 * purpose: get tool 704 * parameter: scanner 705 * state 706 * parms 707 */ 708- (BOOL)getTool:(NSScanner*)scanner 709{ int val; 710 711 if ( (val = [self toolFromString:scanner]) < -1 ) 712 return NO; 713 else if ( val < 0 ) 714 { 715 NSLog(@"Gerber import, Can't find tool at location %d. Default used.", [scanner scanLocation]); 716 state.tool = state.tool + 1; // = 0; 717 return NO; 718 } 719 state.tool = val; 720 return YES; 721} 722 723/* 724 * modified: 16.12.92 725 * purpose: get status plot absolut 726 * parameter: cp 727 * return: cp 728 */ 729- (BOOL)getPlotAbs:(NSScanner*)scanner 730{ 731 state.pa = 1; 732 return YES; 733} 734 735/* 736 * modified: 16.12.92 737 * purpose: get status plot relativ 738 * parameter: cp 739 */ 740- (BOOL)getPlotRel:(NSScanner*)scanner 741{ 742 state.pa = 0; 743 return YES; 744} 745 746/* 747 * created: 07.05.93 748 * modified: 17.06.93 05.05.96 749 * purpose: set arc ccw 750 * parameter: g 751 */ 752- (void)setArc:cList 753{ NSPoint center, start, end; 754 float angle; // ba, ea 755 NSDictionary *tool = [tools objectAtIndex:state.tool]; 756 757 if ( !state.path ) 758 state.width = (tool) ? [[tool objectForKey:@"diameter"] floatValue] : 0.0; 759 760/* if (state.i || state.j) 761 { 762 // center 763 center.x = state.point.x + state.i; 764 center.y = state.point.y + state.j; 765 766 start = state.point; 767 768 end.x = state.x; 769 end.y = state.y; 770 771 // end angle 772 ba = calcAngleOfPointRelativeCenter(start, center); 773 ea = calcAngleOfPointRelativeCenter(end, center); 774 if ( ea <= ba+TOLERANCE ) ea += 360.0; 775 776 if ( !state.ccw ) 777 angle = - (360.0 - (ea-ba)); 778 else 779 angle = ea - ba; 780 781 if ( state.ipolFull && Diff(angle, 360.0) <= TOLERANCE ) 782 { 783 if ( state.path ) 784 [self addCircle:center :sqrt(SqrDistPoints(start, center)) filled:YES toList:cList]; 785 else 786 [self addCircle:center :sqrt(SqrDistPoints(start, center)) filled:NO toList:cList]; 787 } 788 else 789 { 790 if ( !state.ipolFull) // 90 degree interpolation - both angles must be inside one quarter ! 791 { 792 if ( ea <= ba+TOLERANCE ) 793 return; 794 if ( (ba >= 0 && ba < 90) && (ea < 0 || ea > 90) ) 795 return; 796 if ( (ba >= 90 && ba < 180) && (ea < 90 || ea > 180) ) 797 return; 798 if ( (ba >= 180 && ba < 270) && (ea < 180 || ea > 270) ) 799 return; 800 if ( (ba >= 270 && ba < 360) && (ea < 270 || ea > 360) ) 801 return; 802 } 803 [self addArc:center :start :angle toList:cList]; 804 } 805 state.point = end; // end point of arc 806 state.i = state.j = 0; // important if i or j not set -> value is 0 807 } 808 else 809*/ 810 { float b, radius = state.a; 811 NSPoint grad; 812 813 start = state.point; 814 end.x = state.x; 815 end.y = state.y; 816 grad.x = end.x - start.x; 817 grad.y = end.y - start.y; 818 if (SqrDistPoints(start, end) > (radius*radius)*2.0) 819 { 820 angle = 180.0; 821 if ( !(b = sqrt(grad.x*grad.x+grad.y*grad.y)) ) 822 { LineMiddlePoint(start, end, center); } 823 else 824 { center.x = start.x + grad.y*radius*1.0/b; 825 center.y = start.y + grad.x*radius*1.0/b; 826 } 827 [self addArc:center :start :angle toList:cList]; 828 } 829 else if (state.a > 0) // angle smaller or equal 180 degree 830 { NSPoint mp; 831 float hight; 832 833 if ( !(b = sqrt(grad.x*grad.x+grad.y*grad.y)) ) 834 return; 835 LineMiddlePoint(start, end, mp); 836 hight = sqrt(radius*radius - SqrDistPoints(mp, start)); // pythagoras 837 838 // (!state.ccw) -> orthogonal to the right ! 839 center.x = (!state.ccw) ? (mp.x + grad.y*hight*1.0/b) : (mp.x + grad.y*hight*-1.0/b); 840 center.y = (!state.ccw) ? (mp.y - grad.x*hight*1.0/b) : (mp.y - grad.x*hight*-1.0/b); 841 842 angle = vhfAngleBetweenPoints(start, center, end); /* ccw */ 843 if (!state.ccw) 844 angle = -(360.0 - angle); 845 [self addArc:center :start :angle toList:cList]; 846 } 847 else // angle greater 180 degree 848 { NSPoint mp; 849 float hight; 850 851 radius = -radius; 852 if ( !(b = sqrt(grad.x*grad.x+grad.y*grad.y)) ) 853 return; 854 LineMiddlePoint(start, end, mp); 855 hight = sqrt(radius*radius - SqrDistPoints(mp, start)); // pythagoras 856 857 // (!state.ccw) -> orthogonal to the left ! 858 center.x = (!state.ccw) ? (mp.x + grad.y*hight*-1.0/b) : (mp.x + grad.y*hight*1.0/b); 859 center.y = (!state.ccw) ? (mp.y - grad.x*hight*-1.0/b) : (mp.y - grad.x*hight*1.0/b); 860 861 angle = vhfAngleBetweenPoints(start, center, end); /* ccw */ 862 if (!state.ccw) 863 angle = -(360.0 - angle); 864 [self addArc:center :start :angle toList:cList]; 865 } 866 } 867 [self updateBounds:center]; 868 [self updateBounds:start]; 869 [self updateBounds:end]; 870} 871 872/* 873 * modified: 17.06.93 12.06.95 874 * purpose: get line 875 * parameter: g 876 * state 877 * parms 878 */ 879- (void)setLine:cList 880{ float x, y; 881 NSPoint p0, p1; 882 NSDictionary *tool; // = [tools objectAtIndex:state.tool]; 883 884 tool = ([tools count]) ? [tools objectAtIndex:state.tool] : nil; 885 886 x = state.x; 887 y = state.y; 888 889 if ( !state.path ) 890 state.width = (tool) ? [[tool objectForKey:@"diameter"] floatValue] : 0.0; 891 p0 = state.point; 892 893 if (state.pa) 894 { p1.x = x; 895 p1.y = y; 896 } 897 else 898 { p1.x = state.point.x + x; 899 p1.y = state.point.y + y; 900 } 901 902 [self addLine:p0 :p1 toList:cList]; 903 904 state.point = p1; 905 906 [self updateBounds:p0]; 907 [self updateBounds:p1]; 908} 909 910- (void)setMark:cList 911{ NSPoint center, pll, pur; 912 NSDictionary *tool; // = [tools objectAtIndex:state.tool]; 913 914 tool = ([tools count]) ? [tools objectAtIndex:state.tool] : nil; 915 916 state.g = 0; // else we go on with an arc 917 918 // state.width = [[tool objectForKey:@"diameter"] floatValue]; 919 state.width = (tool) ? [[tool objectForKey:@"diameter"] floatValue] : state.tool; 920 921 /* center */ 922 if (state.offset) 923 { center.x = state.point.x + state.x; // !state.x && !state.y -> return 924 center.y = state.point.y + state.y; 925 } 926 else 927 928 { center.x = state.x; 929 center.y = state.y; 930 } 931 [self addMark:center withDiameter:state.width toList:cList]; 932 933 pll.x = center.x - state.a; pll.y = center.y - state.a; 934 pur.x = center.x + state.a; pur.y = center.y + state.a; 935 [self updateBounds:pll]; 936 [self updateBounds:pur]; 937} 938 939- (void)updateBounds:(NSPoint)p 940{ 941 ll.x = Min(ll.x, p.x); 942 ll.y = Min(ll.y, p.y); 943 ur.x = Max(ur.x, p.x); 944 ur.y = Max(ur.y, p.y); 945} 946 947- (void)dealloc 948{ 949 [super dealloc]; 950} 951 952/* methods to be subclassed 953 */ 954- (id)allocateList 955{ 956 return nil; 957} 958 959- (void)addMark:(NSPoint)pt withDiameter:(float)dia toList:aList; 960{ 961 NSLog(@"addMark: %f %f %f", pt.x, pt.y, dia); 962} 963 964- (void)addLine:(NSPoint)beg :(NSPoint)end toList:aList 965{ 966 NSLog(@"line: %f %f %f %f", beg.x, beg.y, end.x, end.y); 967} 968 969- (void)addCircle:(NSPoint)center :(float)radius filled:(BOOL)fill toList:aList 970{ 971 NSLog(@"circle: %f %f %f %d", center.x, center.y, radius, fill); 972} 973 974- (void)addArc:(NSPoint)center :(NSPoint)start :(float)angle toList:aList 975{ 976 NSLog(@"arc: %f %f %f %f %f", center.x, center.y, start.x, start.y, angle); 977} 978 979- (void)addFillList:aList toList:bList 980{ 981 NSLog(@"filled path."); 982} 983 984- (void)setBounds:(NSRect)bounds 985{ 986 NSLog(@"bounds: %f %f %f %f", bounds.origin.x, bounds.origin.y, bounds.size.width, bounds.size.height); 987} 988@end 989