1/* DXFImportSub.m
2 * Subclass of DXFImport managing the creation of graphic objects
3 *
4 * Copyright (C) 1996-2011 by vhf interservice GmbH
5 * Author:   Georg Fleischmann
6 *
7 * created:  1996-05-01
8 * modified: 2011-04-04 (-addLine3D:... added)
9 *           2007-07-13 (-setBounds: continue nur wenn object removed wird (Versatz))
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 <ctype.h>
38#include <VHFShared/vhfCommonFunctions.h>
39#include <VHFShared/types.h>
40#include "DXFImportSub.h"
41#include "messages.h"
42#include "Graphics.h"
43#include "LayerObject.h"
44
45@implementation DXFImportSub
46
47/* here we create the layers needed to store the imported graphics
48 * we return an autoreleased object
49 */
50- (id)allocateList:(NSArray*)layers
51{   int	l;
52
53    layerList = [[NSMutableArray alloc] init];
54
55    /* create a layerList containing a layerObject for each layer */
56    for (l=0; l<(int)[layers count]; l++)
57    {   LayerObject	*layerObject = [LayerObject layerObject];
58        NSDictionary	*dict = [layers objectAtIndex:l];
59
60        [layerObject setString:[dict objectForKey:@"name"]];
61        //if (!([layerInfo intForKey:@"flags"] & LAYERFLAG_FROZEN))
62        // ...
63        [layerList addObject:layerObject];
64    }
65    if (![layers count])
66    {   LayerObject	*layerObject = [LayerObject layerObject];
67
68        [layerObject setString:@"DXF"];
69        [layerList addObject:layerObject];
70    }
71
72    return layerList;
73}
74- (NSMutableArray*)layerArrayWithName:(NSString*)name
75{   int	l;
76
77    /* AC2.10 seems to allow missing LAYER entries */
78    if (!name && [layerList count])
79        return [[layerList objectAtIndex:0] list];
80
81    for (l=0; l<(int)[layerList count]; l++)
82        if ([[[layerList objectAtIndex:l] string] isEqual:name])
83            return [[layerList objectAtIndex:l] list];
84    if ([layerList count])	// return first layer (default)
85        return [[layerList objectAtIndex:0] list];
86    return nil;
87}
88
89/* add list as filled path to layer
90 * we simply add everything in a single list ignoring all layers
91 */
92- (void)addFillList:aList toLayer:(NSString*)layerName
93{   NSMutableArray  *array = [self layerArrayWithName:layerName];
94    VPath           *g = [VPath path];
95
96    if (!array)
97        array = [[layerList objectAtIndex:0] list];
98    [g addList:aList at:[[g list] count]];
99    [g sortList];
100    [g setFilled:YES];
101    [g setWidth:state.width];
102    [g setColor:state.color];
103    [g setFillColor:[state.color copy]];
104    [array addObject:g];
105}
106
107/* add list as stroked path object to layer
108 * we simply add everything in a single list ignoring all layers
109 */
110- (void)addStrokeList:aList toLayer:(NSString*)layerName
111{   NSMutableArray	*array = [self layerArrayWithName:layerName];
112    VPath			*g = [VPath path];
113
114    [g addList:aList at:[[g list] count]];
115    [g sortList];
116    [g setFilled:NO];
117    [g setColor:state.color];
118    [g setFillColor:[state.color copy]];	// turning to filled will fill in the same color
119    [g setWidth:state.width];
120    [array addObject:g];
121}
122
123/* allocate a line object and add it to aList
124 */
125- (void)addLine:(NSPoint)beg :(NSPoint)end toList:(NSMutableArray*)aList
126{   VLine	*g;
127
128    g = [VLine line];
129    [g setVertices:beg :end];
130    [g setWidth:state.width];
131    [g setColor:state.color];
132    [aList addObject:g];
133}
134- (void)addLine:(NSPoint)beg :(NSPoint)end toLayer:(NSString*)layerName
135{   NSMutableArray	*array = [self layerArrayWithName:layerName];
136    VLine		*g;
137
138    if (!array)
139        array = [[layerList objectAtIndex:0] list];
140    g = [VLine line];
141    [g setVertices:beg :end];
142    [g setWidth:state.width];
143    [g setColor:state.color];
144    [array addObject:g];
145}
146
147/* allocate a line object and add it to aList
148 */
149- (void)addLine3D:(V3Point)beg :(V3Point)end toList:(NSMutableArray*)aList
150{   VLine3D	*g;
151
152    g = [VLine3D line3DWithPoints:beg :end];
153    [g setWidth:state.width];
154    [g setColor:state.color];
155    [aList addObject:g];
156}
157- (void)addLine3D:(V3Point)beg :(V3Point)end toLayer:(NSString*)layerName
158{   NSMutableArray	*array = [self layerArrayWithName:layerName];
159    VLine3D *g;
160
161    if (!array)
162        array = [[layerList objectAtIndex:0] list];
163    g = [VLine3D line3DWithPoints:beg :end];
164    [g setWidth:state.width];
165    [g setColor:state.color];
166    [array addObject:g];
167}
168
169/* allocate an arc object and add it to aList
170 * center is the center of the arc
171 * start is the start point
172 * angle is the angle (negative for clockwise direction and positive for ccw direction)
173 */
174- (void)addArc:(NSPoint)center :(NSPoint)start :(float)angle toList:(NSMutableArray*)aList
175{   VArc	*g;
176
177    g = [VArc arc];
178    [g setCenter:center start:start angle:angle];
179    [g setWidth:state.width];
180    [g setColor:state.color];
181    [g setFillColor:[state.color copy]];
182    [aList addObject:g];
183}
184- (void)addArc:(NSPoint)center :(NSPoint)start :(float)angle toLayer:(NSString*)layerName
185{   NSMutableArray	*array = [self layerArrayWithName:layerName];
186    VArc			*g;
187
188    if (!array)
189        array = [[layerList objectAtIndex:0] list];
190    g = [VArc arc];
191    [g setCenter:center start:start angle:angle];
192    [g setWidth:state.width];
193    [g setColor:state.color];
194    [g setFillColor:[state.color copy]];
195    [array addObject:g];
196}
197
198/* allocate a curve object and add it to aList
199 */
200- (void)addCurve:(NSPoint)p0 :(NSPoint)p1 :(NSPoint)p2 :(NSPoint)p3 toList:(NSMutableArray*)aList
201{   VCurve	*g;
202
203    g = [VCurve curve];
204    [g setVertices:p0 :p1 :p2 :p3];
205    [g setWidth:state.width];
206    [g setColor:state.color];
207    [aList addObject:g];
208}
209- (void)addCurve:(NSPoint)p0 :(NSPoint)p1 :(NSPoint)p2 :(NSPoint)p3 toLayer:(NSString*)layerName
210{   NSMutableArray	*array = [self layerArrayWithName:layerName];
211    VCurve		*g;
212
213    if (!array)
214        array = [[layerList objectAtIndex:0] list];
215    g = [VCurve curve];
216    [g setVertices:p0 :p1 :p2 :p3];
217    [g setWidth:state.width];
218    [g setColor:state.color];
219    [array addObject:g];
220}
221
222/* 3D Surface
223 */
224- (void)add3DFace:(V3Point*)pts toLayer:(NSString*)layerName
225{
226    /* TODO: this should be a surface, not 4 lines */
227    [self addLine3D:pts[0] :pts[1] toLayer:layerName];
228    [self addLine3D:pts[1] :pts[2] toLayer:layerName];
229    [self addLine3D:pts[2] :pts[3] toLayer:layerName];
230    [self addLine3D:pts[3] :pts[0] toLayer:layerName];
231}
232
233/* allocate a text object and add it to the layer
234 * parameter: text	the text string
235 *            font	the font name
236 *            angle	rotation angle
237 *            size	the font size in pt
238 *            ar	aspect ratio height/width
239 *            alignment	see genFlags of MTEXT in DXF specs
240 *            layerInfo	the destination layer
241 */
242- (void)addText:(NSString*)text :(NSString*)font :(float)angle :(float)size :(float)ar :(int)alignment at:(NSPoint)p toLayer:(NSString*)layerName
243{   NSMutableArray	*array = [self layerArrayWithName:layerName];
244    id			fontObject;
245    VText		*g = [VText textGraphic];
246    NSRect		bounds;
247
248    if (!array)
249        array = [[layerList objectAtIndex:0] list];
250    [g setColor:state.color];
251    [g setFillColor:[state.color copy]];
252    if (!(fontObject = [NSFont fontWithName:font size:size]))
253        fontObject = [NSFont userFixedPitchFontOfSize:size];	// default
254    [g setFont:fontObject];
255    [g setString:text];
256    [g setRotAngle:angle];
257    bounds = [g coordBounds];
258    switch (alignment)
259    {
260        case 1:	// top left
261            p.y -= bounds.size.height;
262            break;
263        case 2:	// top center
264            p.x -= bounds.size.width / 2.0;
265            p.y -= bounds.size.height;
266            break;
267        case 3:	// top right
268            p.x -= bounds.size.width;
269            p.y -= bounds.size.height;
270            break;
271        case 4:	// middle left
272            p.y -= bounds.size.height / 2.0;
273            break;
274        case 5:	// middle center
275            p.x -= bounds.size.width / 2.0;
276            p.y -= bounds.size.height / 2.0;
277            break;
278        case 6:	// middle right
279            p.x -= bounds.size.width;
280            p.y -= bounds.size.height / 2.0;
281            break;
282        case 7:	// bottom left
283            break;
284        case 8:	// bottom center
285            p.x -= bounds.size.width / 2.0;
286            break;
287        case 9:	// bottom right
288            p.x -= bounds.size.width;
289    }
290    if (alignment >= 7 )	// bottom aligned
291        [g setBaseOrigin:p];
292    else
293        [g moveTo:p];
294    [g setAspectRatio:ar];
295    [array addObject:g];
296    //	[super addText:text :font :angle :size :ar at:p toList:aList];
297}
298
299/* set the bounds
300 * we move the graphic to 0/0 and scale to acceptable size if necessary
301 * modified: 2006-12-11
302 */
303- (void)setBounds:(NSRect)bounds
304{   int		i, l, removed = 0;
305    NSPoint	p;
306    NSPoint	scaleCenter = NSZeroPoint;
307    float	factor = 1.0;
308    BOOL	scale = NO, delete = YES;
309
310    bounds = EnlargedRect(bounds, TOLERANCE);
311
312    p.x = - bounds.origin.x + MMToInternal(10.0);
313    p.y = - bounds.origin.y + MMToInternal(10.0);
314
315#if !defined(GNUSTEP_BASE_VERSION) && !defined(__APPLE__)	// OpenStep 4.2
316    if ( Max(bounds.size.width, bounds.size.height) > 10000.0 )
317    {
318        NSRunAlertPanel(@"", DXFSIZE_STRING, OK_STRING, nil, nil);
319        factor = Max(bounds.size.width, bounds.size.height);
320        while ( factor > 10000.0 )
321            factor /= 10.0;
322        factor = factor / Max(bounds.size.width, bounds.size.height);
323        scale = YES;
324    }
325#endif
326
327    for (l=0; l<(int)[layerList count]; l++)
328    {   NSMutableArray	*array = [[layerList objectAtIndex:l] list];
329
330        for (i=[array count]-1; i>=0; i--)
331        {   id	obj = [array objectAtIndex:i];
332
333            /* object out of bounds */
334            if (!vhfContainsRect(bounds, [obj bounds]) && !vhfIntersectsRect(bounds, [obj bounds]))
335            {
336                if (removed || (delete &&
337                    NSRunAlertPanel(@"", DXFIMPORTOUTOFBOUNDS_STRING, DELETE_STRING, KEEP_STRING, nil)
338                    == NSAlertDefaultReturn))
339                {
340                    [array removeObjectAtIndex:i];
341                    removed ++;
342                    continue;
343                }
344                else
345                    delete = NO;
346            }
347            [obj moveBy:p];
348            if ( scale )
349                [obj scale:factor :factor withCenter:scaleCenter];
350        }
351        /* remove empty layers */
352        if (![array count])
353        {   [layerList removeObjectAtIndex:l];
354            l--;
355        }
356    }
357    if (removed)
358        NSLog(@"DXF-Import: %d Objects removed, which are exceeding drawing extents!", removed);
359}
360
361@end
362