1function mesh = DetectEdges(CSX, mesh, varargin)
2% mesh = DetectEdges(CSX <, mesh, varargin>)
3%
4% Returns a mesh with the edges added of certain (see below) primitives
5% found in the CSX structure.
6%
7% optional arguments:
8%   mesh:       add edges to an existing (predefined) mesh
9%
10% optional: 'keyword', value
11%   'Debug'         enable debug mode (default is 1)
12%   'AddPropertyType'  add a list of additional property types to detect
13%                   e.g. 'DumpBox' or {'DumpBox','ProbeBox'}
14%   'SetPropertyType'  set the list of property types to detect (override default)
15%                   e.g. 'Metal' or {'Metal','ConductingSheet'}
16%   'ExcludeProperty'  give a list of property names to exclude from
17%                      detection
18%   'SetProperty'  give a list of property names to handly exlusively for detection
19%
20% advanced options: 'keyword', value
21%   '2D_Metal_Edge_Res' define a one-third/two-third metal edge resolution
22%
23% example:
24%     CSX = InitCSX();
25%     % define all properties and primitives to detect
26%     % ...
27%     % ...
28%     mesh = DetectEdges(CSX);
29%     mesh = SmoothMesh(mesh, lambda/20/unit);
30%     CSX = DefineRectGrid(CSX, unit, mesh);
31%
32% Note:
33% - Only primitives contained in Metal, Material, Excitation, LumpedElement
34%   or ConductingSheet properties are processed
35% - Currently this function handles only Box, Polygons, LinPoly and Cylinder.
36%
37% CSXCAD matlab interface
38% -----------------------
39% author: Koen De Vleeschauwer (c) 2012
40% modified by: Thorsten Liebig (c) 2012, 2013
41%
42% See also InitCSX, SmoothMesh, DefineRectGrid
43
44supported_properties = {};
45supported_properties{end+1}='Metal';
46supported_properties{end+1}='Material';
47supported_properties{end+1}='Excitation';
48supported_properties{end+1}='LumpedElement';
49supported_properties{end+1}='ConductingSheet';
50
51exclude_list = {};
52prop_list_only = {};
53
54debug = 1;
55mesh_2D_metal_edges = 0;
56
57for n=1:2:numel(varargin)
58    if (strcmpi(varargin{n},'debug')==1);
59        debug = varargin{n+1};
60    elseif (strcmpi(varargin{n},'AddPropertyType')==1);
61        if iscell(varargin{n+1})
62            supported_properties(end+1) = varargin{n+1};
63        elseif ischar(varargin{n+1})
64            supported_properties{end+1} = varargin{n+1};
65        else
66           error('CSXCAD:DetectEdges','unknown property definition');
67        end
68    elseif (strcmpi(varargin{n},'SetPropertyType')==1);
69        if iscell(varargin{n+1})
70            supported_properties = varargin{n+1};
71        elseif ischar(varargin{n+1})
72            supported_properties = {varargin{n+1}};
73        else
74           error('CSXCAD:DetectEdges','unknown property definition');
75        end
76    elseif (strcmpi(varargin{n},'ExcludeProperty')==1);
77        exclude_list = varargin{n+1};
78    elseif (strcmpi(varargin{n},'SetProperty')==1);
79        prop_list_only = varargin{n+1};
80    elseif (strcmpi(varargin{n},'2D_Metal_Edge_Res')==1);
81        mesh_2D_metal_edges = varargin{n+1}*[-1 2]/3;
82    else
83        warning('CSXCAD:DetectEdges',['unknown argument: ' varargin{n}]);
84    end
85end
86
87if (nargin<2)
88    mesh = [];
89end
90
91if isempty(mesh)
92    if (CSX.ATTRIBUTE.CoordSystem==0)
93        mesh.x = [];
94        mesh.y = [];
95        mesh.z = [];
96    elseif (CSX.ATTRIBUTE.CoordSystem==1)
97        mesh.r = [];
98        mesh.a = [];
99        mesh.z = [];
100    else
101        error('CSXCAD:DetectEdges','unknown coordinate system used');
102    end
103end
104
105edges = {};
106edges.x = [ ];
107edges.y = [ ];
108edges.z = [ ];
109
110if (~isstruct(CSX))
111    error('expected a CSX structure');
112end
113
114CoordSystem = CSX.ATTRIBUTE.CoordSystem;
115
116if (isfield(CSX, 'Properties'))
117    prop_fn = fieldnames(CSX.Properties);
118    for p = 1:numel(prop_fn)
119        if (sum(strcmpi(prop_fn{p}, supported_properties))==0)
120            continue;
121        end
122        isMetal = sum(strcmpi(prop_fn{p},{'Metal','ConductingSheet'}));
123        property_group = CSX.Properties.(prop_fn{p});
124        for m = 1:numel(property_group)
125            property=property_group{m};
126            if ~isfield(property, 'Primitives')
127                continue;
128            end
129            if (sum(strcmpi(property.ATTRIBUTE.Name,exclude_list)))
130                continue;
131            end
132            if (~isempty(prop_list_only) && (sum(strcmpi(property.ATTRIBUTE.Name,prop_list_only))==0))
133                continue;
134            end
135            primitives = property.Primitives;
136            prim_fn = fieldnames(primitives);
137            for n_prim = 1:numel(prim_fn)
138                if (strcmp(prim_fn{n_prim}, 'Box'))
139                    for b = 1:length(primitives.Box)
140                        box = primitives.Box{b};
141                        x1 = box.P1.ATTRIBUTE.X;
142                        y1 = box.P1.ATTRIBUTE.Y;
143                        z1 = box.P1.ATTRIBUTE.Z;
144                        x2 = box.P2.ATTRIBUTE.X;
145                        y2 = box.P2.ATTRIBUTE.Y;
146                        z2 = box.P2.ATTRIBUTE.Z;
147                        % check dimension
148                        dim = (x1~=x2) + (y1~=y2) + (z1~=z2);
149                        if ((dim==2) && isMetal)
150                            % add to global list of edges, with a given 2D
151                            % edge resolution
152                            edges = AddEdge (edges, box, x1+sign(x1-x2)*mesh_2D_metal_edges, y1+sign(y1-y2)*mesh_2D_metal_edges, ...
153                                z1+sign(z1-z2)*mesh_2D_metal_edges, CoordSystem, debug);
154                            edges = AddEdge (edges, box, x2+sign(x2-x1)*mesh_2D_metal_edges, y2+sign(y2-y1)*mesh_2D_metal_edges, ...
155                                z2+sign(z2-z1)*mesh_2D_metal_edges, CoordSystem, debug);
156                        else
157                            % add to global list of edges
158                            edges = AddEdge (edges, box, x1, y1, z1, CoordSystem, debug);
159                            edges = AddEdge (edges, box, x2, y2, z2, CoordSystem, debug);
160                        end
161                    end
162                elseif (strcmp(prim_fn{n_prim}, 'LinPoly') || strcmp(prim_fn{n_prim}, 'Polygon'))
163                    for l = 1:length(primitives.(prim_fn{n_prim}))
164                        poly = primitives.(prim_fn{n_prim}){l};
165                        dir = poly.ATTRIBUTE.NormDir + 1;
166                        dirP = mod(poly.ATTRIBUTE.NormDir+1,3) + 1;
167                        dirPP = mod(poly.ATTRIBUTE.NormDir+2,3) + 1;
168                        lin_length = 0;
169                        if (strcmp(prim_fn{n_prim}, 'LinPoly'))
170                            lin_length = poly.ATTRIBUTE.Length;
171                        end
172                        if (isfield(poly, 'Vertex'))
173                            for v = 1:length(poly.Vertex)
174                                vertex = poly.Vertex{v};
175                                edge(dir) = poly.ATTRIBUTE.Elevation;
176                                edge(dirP) = vertex.ATTRIBUTE.X1;
177                                edge(dirPP) = vertex.ATTRIBUTE.X2;
178                                edges = AddEdge (edges, poly, edge(1), edge(2), edge(3), CoordSystem, debug);
179                                if (lin_length~=0)
180                                    edge(dir) = edge(dir) + lin_length;
181                                    edges = AddEdge (edges, poly, edge(1), edge(2), edge(3), CoordSystem, debug);
182                                end
183                            end
184                        end
185                    end
186                elseif (strcmp(prim_fn{n_prim}, 'Cylinder'))
187                    for c = 1:length(primitives.Cylinder)
188                        cylinder = primitives.Cylinder{c};
189                        r = cylinder.ATTRIBUTE.Radius;
190                        x1 = cylinder.P1.ATTRIBUTE.X;
191                        y1 = cylinder.P1.ATTRIBUTE.Y;
192                        z1 = cylinder.P1.ATTRIBUTE.Z;
193                        x2 = cylinder.P2.ATTRIBUTE.X;
194                        y2 = cylinder.P2.ATTRIBUTE.Y;
195                        z2 = cylinder.P2.ATTRIBUTE.Z;
196                        if ((x1 == x2) && (y1 == y2) && (z1 ~= z2))
197                          % cylinder parallel with z axis
198                          edges = AddEdge (edges, cylinder, x1 - r, y1 - r, z1, CoordSystem, debug);
199                          edges = AddEdge (edges, cylinder, x2 + r, y2 + r, z2, CoordSystem, debug);
200                        elseif ((x1 == x2) && (y1 ~= y2) && (z1 == z2))
201                          % cylinder parallel with y axis
202                          edges = AddEdge (edges, cylinder, x1 - r, y1, z1 - r, CoordSystem, debug);
203                          edges = AddEdge (edges, cylinder, x2 + r, y2, z2 + r, CoordSystem, debug);
204                        elseif ((x1 ~= x2) && (y1 == y2) && (z1 == z2))
205                          % cylinder parallel with x axis
206                          edges = AddEdge (edges, cylinder, x1, y1 - r, z1 - r, CoordSystem, debug);
207                          edges = AddEdge (edges, cylinder, x2, y2 + r, z2 + r, CoordSystem, debug);
208                        elseif (debug > 0)
209                          warning('CSXCAD:DetectEdges',['unsupported primitive of type: "' prim_fn{n_prim} '" found, skipping edges']);
210                        end
211                    end
212                else
213                    if (debug>0)
214                        warning('CSXCAD:DetectEdges',['unsupported primitive of type: "' prim_fn{n_prim} '" found, skipping edges']);
215                    end
216                end
217            end
218        end
219    end
220end
221
222if (CSX.ATTRIBUTE.CoordSystem==0)
223    mesh.x = sort(unique([mesh.x edges.x]));
224    mesh.y = sort(unique([mesh.y edges.y]));
225    mesh.z = sort(unique([mesh.z edges.z]));
226elseif (CSX.ATTRIBUTE.CoordSystem==1)
227    mesh.r = sort(unique([mesh.r edges.x]));
228    mesh.a = sort(unique([mesh.a edges.y]));
229    mesh.z = sort(unique([mesh.z edges.z]));
230else
231    error('CSXCAD:DetectEdges','unknown coordinate system used');
232end
233
234end
235
236
237function edges = AddEdge(edges, csx_prim, x, y, z, CoordSystem, debug)
238% Add edges of CSX primitives including some transformations
239
240xt = unique(x);
241yt = unique(y);
242zt = unique(z);
243
244if isfield(csx_prim.ATTRIBUTE,'CoordSystem')
245    if (csx_prim.ATTRIBUTE.CoordSystem~=CoordSystem)
246        if (debug>2)
247            warning('CSXCAD:DetectEdges','different coordinate systems not supported, skipping edges');
248        end
249        return
250    end
251end
252
253if (isfield(csx_prim, 'Transformation'))
254
255    transformation = csx_prim.Transformation;
256    trans_fn = fieldnames(transformation);
257
258    for t=1:numel(trans_fn)
259        if (strcmp(trans_fn{t}, 'Translate'))
260            xt = xt + transformation.Translate.ATTRIBUTE.Argument(1);
261            yt = yt + transformation.Translate.ATTRIBUTE.Argument(2);
262            zt = zt + transformation.Translate.ATTRIBUTE.Argument(3);
263        else
264            if (debug>0)
265                warning('CSXCAD:DetectEdges','unsupported transformation found in primitive, skipping edges');
266            end
267            return
268        end
269    end
270
271end
272
273% add to global list of edges
274edges.x = [edges.x xt];
275edges.y = [edges.y yt];
276edges.z = [edges.z zt];
277end
278
279