1/* ICUTImport.m 2 * i-cut import object 3 * 4 * Copyright (C) 2012 by vhf interservice GmbH 5 * Author: Ilonka Fleischmann 6 * 7 * created: 2011-09-16 8 * modified: 2012-06-22 (shape added, any layer with names possible) 9 * 2012-02-29 (ignore stuff after ops.cutcontour) 10 * 2012-02-13 (ops.cutcontour like ops.corner, state.path = 0 after else) 11 * 12 * This file is part of the vhf Import Library. 13 * 14 * This library is free software; you can redistribute it and/or 15 * modify it under the terms of the vhf Public License as 16 * published by the vhf interservice GmbH. Among other things, 17 * the License requires that the copyright notices and this notice 18 * be preserved on all copies. 19 * 20 * This library is distributed in the hope that it will be useful, 21 * but WITHOUT ANY WARRANTY; without even the implied warranty of 22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 23 * See the vhf Public License for more details. 24 * 25 * You should have received a copy of the vhf Public License along 26 * with this library; see the file LICENSE. If not, write to vhf. 27 * 28 * If you want to link this library to your proprietary software, 29 * or for other uses which are not covered by the definitions 30 * laid down in the vhf Public License, vhf also offers a proprietary 31 * license scheme. See the vhf internet pages or ask for details. 32 * 33 * vhf interservice GmbH, Im Marxle 3, 72119 Altingen, Germany 34 * eMail: info@vhf.de 35 * http://www.vhf.de 36 */ 37 38#include <math.h> 39 40#include "ICUTImport.h" 41#include "functions.h" 42//#include "../VHFShared/vhfCFGFunctions.h" 43#include "../VHFShared/types.h" 44 45#define DIGITS @".+-0123456789" 46#define JUMPDIGITS @",.+-0123456789" 47#define NOP @" \t\r\n," 48 49/* r in points/inch */ 50#define InternalToDeviceRes(a, r) ((float)(a) * (float)(r) / 72.0) 51#define DeviceResToInternal(a, r) ((float)(a) * 72.0 / (float)(r)) 52 53//static int linePattern[9][9] = {{0, -1, -1, -1, -1, -1, -1, -1, -1}, {0, 100, -1, -1, -1, -1, -1, -1, -1}, {50, 50, -1, -1, -1, -1, -1, -1, -1}, {70, 30, -1, -1, -1, -1, -1, -1, -1}, {80, 10, 0, 10, -1, -1, -1, -1, -1}, {70, 10, 10, 10, -1, -1, -1, -1, -1}, {50, 10, 10, 10, 10, 10, -1, -1, -1}, {70, 10, 0, 10, 0, 10, -1, -1, -1}, {50, 10, 0, 10, 10, 10, 0, 10, -1}}; 54 55//static void addToBeginNew(NSString *newOp, NSMutableString *beginNew); 56 57@interface ICUTImport(PrivateMethods) 58- (float)unitFromUnit:(int)u :(float)v; 59- (void)initParameter; 60- (BOOL)setUnitFromData:(NSData*)icutData; 61- (BOOL)interpret:(NSString*)dataP; 62- (BOOL)getGraphicFromData:(NSScanner*)scanner :cList; 63//- (void)setPath:(NSScanner*)scanner :cList; 64- (void)setPath:(NSScanner*)scanner :(NSString*)layerName; 65- (void)updateBounds:(NSPoint)p; 66@end 67 68@implementation ICUTImport 69 70- (float)unitFromUnit:(int)u :(float)v 71{ 72 switch ( u ) 73 { 74 case UNIT_MM: 75 switch ( unit ) 76 { 77 case UNIT_MM: return v; // mm to mm 78 case UNIT_INCH: return ((v)*25.4); // inch to mm 79 default: return ((v) / 72.0*25.4); // point to mm 80 } 81 case UNIT_INCH: 82 switch ( unit ) 83 { 84 case UNIT_MM: return ((v)/25.4); // mm to inch 85 case UNIT_INCH: return v; // inch to inch 86 default: return ((v)/72.0); // point/internal to inch ?????? 87 } 88 default: 89 switch ( unit ) 90 { 91 case UNIT_MM: return ((v)*72.0/25.4); // mm to point 92 case UNIT_INCH: return ((v)*72.0); // inch to point 93 default: return v; // point point do degree to point 94 } 95 } 96 return v; 97} 98 99- init 100{ 101 [super init]; 102 103 unit = UNIT_INCH; 104 fillClosedPaths = NO; 105 originUL = NO; 106 107 state.mode = 0; 108 state.path = 0; 109 state.pindex = 0; 110 state.p0.x = state.p0.y = 0.0; 111 state.p1.x = state.p1.y = 0.0; 112 state.p2.x = state.p2.y = 0.0; 113 state.p3.x = state.p3.y = 0.0; 114 115 return self; 116} 117 118/* created: 03.05.96 119 * modified: 09.03.97 120 * parameter: fileName 121 * purpose: load parameter file 122 */ 123- (void)initParameter 124{ 125 ops.moveto = @"Moveto"; 126 ops.lineto = @"Lineto"; 127 ops.regmark = @"Regmark"; 128 ops.shape = @"Shape"; 129 ops.corner = @"Corner"; 130 ops.bezier = @"Bezier"; 131 ops.open = @"Open"; 132 ops.closed = @"Closed"; 133 ops.cutcontour = @"CutContour"; 134 ops.comma = @","; 135 ops.termi = @"\n"; 136} 137 138- (void)fillClosedPaths:(BOOL)flag 139{ 140 fillClosedPaths = flag; 141} 142- (void)originUL:(BOOL)flag 143{ 144 originUL = flag; 145} 146/*- (void)changeXY:(BOOL)flag 147{ 148 changeXY = flag; 149}*/ 150 151- (BOOL)setUnitFromData:(NSData*)icutData 152{ NSString *dataStr; 153 NSMutableString *unitLineStr = nil; 154 NSScanner *scanner; 155 NSRange range; 156 int location, firstLoc; 157 158 dataStr = [[[NSString alloc] initWithData:icutData encoding:NSASCIIStringEncoding] autorelease]; 159 160 //if ( !(toolData = [NSMutableString stringWithContentsOfFile:fileName]) ) 161 if ( !dataStr ) 162 return NO; 163 164 scanner = [NSScanner scannerWithString:dataStr]; 165 [scanner setCaseSensitive:YES]; 166 firstLoc = location = [scanner scanLocation]; 167 168 [scanner scanUpToString:@"i-cut script" intoString:NULL]; 169 if ( ![scanner scanString:@"i-cut script" intoString:NULL] ) 170 { NSLog(@"ICUTImport: No i-cut File"); 171 return NO; 172 } 173 [scanner scanUpToString:@"SystemUnits" intoString:NULL]; 174 [scanner scanUpToCharactersFromSet:termiSet intoString:&unitLineStr]; 175 176 range = [unitLineStr rangeOfString:@"Inch"]; 177 if ( range.length ) 178 unit = UNIT_INCH; // inch 179 else 180// range = [unitLineStr rangeOfString:@"MM"]; // fixme: we dont know mm or MM 181// if ( range.length ) 182 unit = UNIT_MM; // millimeters 183 184 return YES; 185} 186 187/* created: 1996-01-25 188 * modified: 2002-10-26 189 * parameter: hpglData the HPGL data stream 190 * purpose: start interpretation of the contents of hpglData 191 */ 192- importICUT:(NSData*)icutData 193{ 194 [self initParameter]; 195 196 digitsSet = [NSCharacterSet characterSetWithCharactersInString:DIGITS]; 197 invDigitsSet = [digitsSet invertedSet]; 198 jumpSet = [NSCharacterSet characterSetWithCharactersInString:JUMPDIGITS]; 199 termiSet = [NSCharacterSet characterSetWithCharactersInString:ops.termi]; 200 newLineSet = [NSCharacterSet characterSetWithCharactersInString:@"\r\n"]; 201 202 if ( ![self setUnitFromData:icutData] ) 203 return nil; 204 205 /* interpret data */ 206 if ( ![self interpret:[[[NSString alloc] initWithData:icutData 207 encoding:NSASCIIStringEncoding] autorelease]] ) 208 return nil; 209 210 return [list autorelease]; 211} 212 213/* private methods 214 */ 215- (BOOL)interpret:(NSString*)dataP 216{ NSRect bounds; 217 NSScanner *scanner = [NSScanner scannerWithString:dataP]; 218 NSCharacterSet *skipSet = [NSCharacterSet characterSetWithCharactersInString:NOP]; 219 220 /* init bounds */ 221 ll.x = ll.y = LARGE_COORD; 222 ur.x = ur.y = LARGENEG_COORD; 223 224 list = [self allocateList]; 225 226 [scanner setCharactersToBeSkipped:skipSet]; 227 while ( ![scanner isAtEnd] ) 228 if ( ![self getGraphicFromData:scanner :list] ) 229 break; 230 231 232 bounds.origin = ll; 233 bounds.size.width = ur.x - ll.x; 234 bounds.size.height = ur.y - ll.y; 235 [self setBounds:bounds]; 236 237 return YES; 238} 239 240/* the graphics list 241 */ 242- (id)list; 243{ 244 return list; 245} 246 247/* we need cp on a number ! 248 * modified: 2008-06-15 249 */ 250- (BOOL)getGraphicFromData:(NSScanner*)scanner :cList 251{ int location; 252 253 /* one line per -getGraphicFromData: */ 254 255 location = [scanner scanLocation]; 256 if ( [scanner scanString:ops.regmark intoString:NULL] ) // RegMark f, f, RegMark 257 { float xval, yval; 258 259 if ( state.path ) 260 { 261 [scanner setScanLocation:location]; 262 state.path = 0; 263 return YES; // return to -setPath: 264 } 265 [scanner scanFloat:&xval]; 266 [scanner scanString:ops.comma intoString:NULL]; 267 [scanner scanFloat:&yval]; 268 [scanner scanString:ops.comma intoString:NULL]; 269 if ( [scanner scanString:ops.regmark intoString:NULL] ) 270 { 271 state.p0.x = [self unitFromUnit:UNIT_POINT :xval]; // get internal from Inch 272 state.p0.y = [self unitFromUnit:UNIT_POINT :yval]; // get internal from Inch 273 /*if ( changeXY ) 274 { float bufy = state.p0.y; 275 276 state.p0.y = state.p0.x; 277 state.p0.x = bufy; 278 }*/ 279 [self updateBounds:state.p0]; 280 //[self addMark:state.p0 toList:cList]; 281 [self addMark:state.p0 toLayer:nil]; 282 return YES; 283 } 284 else return NO; 285 } 286 else if ( [scanner scanString:ops.shape intoString:NULL] ) // Shape f, f, f, f, 1, LayerName 287 { float xval, yval, wval, hval; 288 int intval; 289 NSMutableString *layerName = nil; 290 291 if ( state.path ) 292 { 293 [scanner setScanLocation:location]; 294 state.path = 0; 295 return YES; // return to -setPath: 296 } 297 [scanner scanFloat:&xval]; 298 [scanner scanString:ops.comma intoString:NULL]; 299 [scanner scanFloat:&yval]; 300 [scanner scanString:ops.comma intoString:NULL]; 301 [scanner scanFloat:&wval]; 302 [scanner scanString:ops.comma intoString:NULL]; 303 [scanner scanFloat:&hval]; 304 [scanner scanString:ops.comma intoString:NULL]; 305 [scanner scanInt:&intval]; // no idea what this is 306 [scanner scanString:ops.comma intoString:NULL]; 307 //if ( [scanner scanString:ops.regmark intoString:NULL] ) 308 if ( [scanner scanUpToCharactersFromSet:newLineSet intoString:&layerName] ) 309 { NSPoint rsize; 310 311 state.p0.x = [self unitFromUnit:UNIT_POINT :xval]; // get internal from Inch 312 state.p0.y = [self unitFromUnit:UNIT_POINT :yval]; // get internal from Inch 313 rsize.x = [self unitFromUnit:UNIT_POINT :wval]; // get internal from Inch 314 rsize.y = [self unitFromUnit:UNIT_POINT :hval]; // get internal from Inch 315 /*if ( changeXY ) 316 { float bufy = state.p0.y; 317 318 state.p0.y = state.p0.x; 319 state.p0.x = bufy; 320 }*/ 321 [self updateBounds:state.p0]; 322 [self updateBounds:NSMakePoint(state.p0.x+rsize.x, state.p0.y)]; 323 [self updateBounds:NSMakePoint(state.p0.x+rsize.x, state.p0.y+rsize.y)]; 324 [self updateBounds:NSMakePoint(state.p0.x, state.p0.y+rsize.y)]; 325 [self addRect:state.p0 :rsize toLayer:layerName]; 326 return YES; 327 } 328 else return NO; 329 } 330 else if ( [scanner scanString:ops.moveto intoString:NULL] ) // Moveto f, f, Open/Closed, CutContour 331 { float xval, yval; 332 NSMutableString *layerName = nil; 333 334 if ( state.path ) 335 { 336 [scanner setScanLocation:location]; 337 state.path = 0; 338 return YES; // return to -setPath: 339 } 340 state.path = 1; 341 342 [scanner scanFloat:&xval]; 343 [scanner scanString:ops.comma intoString:NULL]; 344 [scanner scanFloat:&yval]; 345 [scanner scanString:ops.comma intoString:NULL]; 346 if ( [scanner scanString:ops.open intoString:NULL] ) 347 state.mode = 0; // openPath 348 if ( [scanner scanString:ops.closed intoString:NULL] ) 349 state.mode = 1; // openPath 350 //if ( [scanner scanString:ops.cutcontour intoString:NULL] ) 351 if ( [scanner scanUpToCharactersFromSet:newLineSet intoString:&layerName] ) 352 { 353 state.p0.x = [self unitFromUnit:UNIT_POINT :xval]; // get internal from Inch 354 state.p0.y = [self unitFromUnit:UNIT_POINT :yval]; // get internal from Inch 355 state.pindex = 1; // p0 ist set, next is p1 356 [self updateBounds:state.p0]; 357 //[self setPath:scanner :cList]; 358 [self setPath:scanner :layerName]; 359 return YES; 360 } 361 else return NO; 362 } 363 else if ( [scanner scanString:ops.lineto intoString:NULL] ) // Lineto f, f, Corner/Bezier 364 { float xval, yval; 365 366 [scanner scanFloat:&xval]; 367 [scanner scanString:ops.comma intoString:NULL]; 368 [scanner scanFloat:&yval]; 369 [scanner scanString:ops.comma intoString:NULL]; 370 if ( [scanner scanString:ops.bezier intoString:NULL] ) 371 { 372 switch (state.pindex) 373 { case 1: 374 state.p1.x = [self unitFromUnit:UNIT_POINT :xval]; // get internal from Inch 375 state.p1.y = [self unitFromUnit:UNIT_POINT :yval]; // get internal from Inch 376 state.pindex = 2; // first crv pt, next is second crv pt 377 [self updateBounds:state.p1]; 378 break; 379 default: 380 //case 2: 381 state.p2.x = [self unitFromUnit:UNIT_POINT :xval]; // get internal from Inch 382 state.p2.y = [self unitFromUnit:UNIT_POINT :yval]; // get internal from Inch 383 state.pindex = 3; // second crv pt, next is end pt 384 [self updateBounds:state.p2]; 385 break; 386 } 387 return YES; 388 } 389 else //if ( [scanner scanString:ops.corner intoString:NULL] || // Corner 390 //[scanner scanString:ops.cutcontour intoString:NULL] ) // CutContour - mh ? 391 { 392 switch (state.pindex) 393 { case 1: 394 state.p1.x = [self unitFromUnit:UNIT_POINT :xval]; // get internal from Inch 395 state.p1.y = [self unitFromUnit:UNIT_POINT :yval]; // get internal from Inch 396 state.pindex = 1; // line end already 1 397 [self updateBounds:state.p1]; 398 [self addLine:state.p0 :state.p1 toList:cList]; 399 state.p0 = state.p1; // is our new p0 ! 400 break; 401 default: 402 //case 3: 403 state.p3.x = [self unitFromUnit:UNIT_POINT :xval]; // get internal from Inch 404 state.p3.y = [self unitFromUnit:UNIT_POINT :yval]; // get internal from Inch 405 state.pindex = 1; // curve end already 1 406 [self updateBounds:state.p3]; 407 [self addCurve:state.p0 :state.p1 :state.p2 :state.p3 toList:cList]; 408 state.p0 = state.p3; // is our new p0 ! 409 break; 410 } 411 return YES; 412 } 413 /* else if ( [scanner scanString:ops.bezier intoString:NULL] ) 414 { 415 switch (state.pindex) 416 { case 1: 417 state.p1.x = [self unitFromUnit:UNIT_POINT :xval]; // get internal from Inch 418 state.p1.y = [self unitFromUnit:UNIT_POINT :yval]; // get internal from Inch 419 state.pindex = 2; // first crv pt, next is second crv pt 420 [self updateBounds:state.p1]; 421 break; 422 default: 423 //case 2: 424 state.p2.x = [self unitFromUnit:UNIT_POINT :xval]; // get internal from Inch 425 state.p2.y = [self unitFromUnit:UNIT_POINT :yval]; // get internal from Inch 426 state.pindex = 3; // second crv pt, next is end pt 427 [self updateBounds:state.p2]; 428 break; 429 } 430 return YES; 431 } 432 else return NO;*/ 433 } 434 else if ( [scanner scanUpToString:ops.termi intoString:NULL] ) 435 { 436 /* if ( state.path ) // hier nicht evtl muell hinter CutContour verhindert sonst Pfadbildung 437 { 438 [scanner setScanLocation:location]; 439 state.path = 0; 440 return YES; // return to -setPath: 441 }*/ 442 return YES; // continue; 443 } 444 else if ( state.path ) 445 { 446 [scanner setScanLocation:location]; 447 state.path = 0; 448 return YES; // return to -setPath: 449 } 450 return YES; 451} 452 453/* 454 * created: 07.05.93 455 * modified: 17.06.93 05.05.96 456 * purpose: set arc ccw 457 * parameter: g 458 */ 459//- (void)setPath:(NSScanner*)scanner :cList // cList is the array of the layer here 460- (void)setPath:(NSScanner*)scanner :(NSString*)layerName // cList is the array of the layer here 461{ NSMutableArray *myList; /* current list */ 462 463 [scanner scanString:ops.termi intoString:NULL]; // little bit faster 464 465 myList = [[[NSMutableArray allocWithZone:[self zone]] init] autorelease]; 466 while (1) 467 { 468 if ( ![self getGraphicFromData:scanner :myList] ) 469 break; 470 471 if ( !state.path ) // end of path ( new Moveto) 472 break; 473 } 474 //add to layer 475 if ( [myList count] > 1 ) 476 { 477 if ( state.mode == 1 && fillClosedPaths ) // openPath 478 //[self addFillList:myList toList:cList]; 479 [self addFillList:myList toLayer:layerName]; 480 else 481 //[self addStrokeList:myList toList:cList]; 482 [self addStrokeList:myList toLayer:layerName]; 483 [myList removeAllObjects]; 484 } 485 else if ( [myList count] ) // add single graphic in myList to cList 486 { 487 //[cList addObject:[myList objectAtIndex:0]]; 488 [self addStrokeList:myList toLayer:layerName]; // add only the single graphic 489 [myList removeAllObjects]; 490 } 491} 492 493- (void)updateBounds:(NSPoint)p 494{ 495 ll.x = Min(ll.x, p.x); 496 ll.y = Min(ll.y, p.y); 497 ur.x = Max(ur.x, p.x); 498 ur.y = Max(ur.y, p.y); 499} 500 501- (void)dealloc 502{ 503 [super dealloc]; 504} 505 506/* methods to be subclassed 507 */ 508- (id)allocateList 509{ 510 return nil; 511} 512 513- (void)addFillList:aList toLayer:(NSString*)layerNamer 514{ 515 NSLog(@"filled path. to layer"); 516} 517- (void)addFillList:aList toList:(NSMutableArray*)bList 518{ 519 NSLog(@"filled path."); 520} 521 522- (void)addStrokeList:aList toLayer:(NSString*)layerNamer 523{ 524 NSLog(@"stroked path. to layer"); 525} 526- (void)addStrokeList:aList toList:(NSMutableArray*)bList 527{ 528 NSLog(@"stroked path."); 529} 530 531- (void)addLine:(NSPoint)beg :(NSPoint)end toLayer:(NSString*)layerNamer 532{ 533 NSLog(@"line: %f %f %f %f, to layer", beg.x, beg.y, end.x, end.y); 534} 535- (void)addLine:(NSPoint)beg :(NSPoint)end toList:(NSMutableArray*)aList 536{ 537 NSLog(@"line: %f %f %f %f", beg.x, beg.y, end.x, end.y); 538} 539 540- (void)addMark:(NSPoint)origin toLayer:(NSString*)layerNamer 541{ 542 NSLog(@"regmark: %f %f, to layer", origin.x, origin.y); 543} 544- (void)addMark:(NSPoint)origin toList:(NSMutableArray*)aList 545{ 546 NSLog(@"regmark: %f %f", origin.x, origin.y); 547} 548 549- (void)addRect:(NSPoint)origin :(NSPoint)rsize toLayer:(NSString*)layerNamer 550{ 551 NSLog(@"rectangle: %f %f %f %f, to layer", origin.x, origin.y, rsize.x, rsize.y); 552} 553- (void)addRect:(NSPoint)origin :(NSPoint)rsize toList:(NSMutableArray*)aList 554{ 555 NSLog(@"rectangle: %f %f %f %f", origin.x, origin.y, rsize.x, rsize.y); 556} 557 558- (void)addCurve:(NSPoint)p0 :(NSPoint)p1 :(NSPoint)p2 :(NSPoint)p3 toLayer:(NSString*)layerNamer 559{ 560 NSLog(@"curve: %f %f %f %f %f %f %f %f, to layer", p0.x, p0.y, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y); 561} 562- (void)addCurve:(NSPoint)p0 :(NSPoint)p1 :(NSPoint)p2 :(NSPoint)p3 toList:(NSMutableArray*)aList 563{ 564 NSLog(@"curve: %f %f %f %f %f %f %f %f", p0.x, p0.y, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y); 565} 566 567- (void)setBounds:(NSRect)bounds 568{ 569 NSLog(@"bounds: %f %f %f %f", bounds.origin.x, bounds.origin.y, bounds.size.width, bounds.size.height); 570} 571@end 572