nec2++ 2.1.1
nec_wire.h
1/*
2 Copyright (C) 2008-2011 Timothy C.A. Molteno
3 tim@physics.otago.ac.nz
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18*/
19#pragma once
20
21#include <algorithm>
22#include <vector>
23#include "math_util.h"
24#include "nec_exception.h"
25
29{
30public:
31 nec_wire(const nec_3vector& a, const nec_3vector& b, nec_float in_radius, int id)
32 : x0(a), x1(b), radius(in_radius), _tag_id(id)
33 {
34 }
35
36 nec_3vector parametrize(nec_float s) const
37 {
38 nec_3vector ret = x0;
39 ret += (x1 - x0)*s;
40 return ret;
41 }
42
43 nec_float distance(const nec_3vector& a, const nec_3vector& b) const
44 {
45 return (a - b).norm();
46 }
47
48 nec_float length() const
49 {
50 return distance(x0, x1);
51 }
52
53 int tag_id() const
54 {
55 return _tag_id;
56 }
57
58 nec_float get_radius() const
59 {
60 return radius;
61 }
62
66std::vector<nec_wire> intersect(nec_wire& b)
67{
68 nec_float d2,sa,sb;
69 int_solve(x0,x1, b.x0, b.x1, d2,sa,sb);
70
71 nec_float epsa = b.radius / length(); // Set by the radius of the other wires
72 nec_float epsb = radius / b.length(); // Set by the radius of the other wires
73
74 std::vector<nec_wire> ret;
75
76 if (d2 > (radius + b.radius)) return ret;
77
78 if ((sa >= -epsa) && (sa <= 1.0 + epsa) && (sb >= -epsb) && (sb <= 1.0 + epsb))
79 {
80 nec_3vector a_pt = parametrize(sa);
81 nec_3vector b_pt = b.parametrize(sb);
82
83 if (sa > epsa) ret.push_back(nec_wire(x0, a_pt, radius,_tag_id));
84 if (sa < 1.0 - epsa) ret.push_back(nec_wire(a_pt, x1, radius,_tag_id));
85
86 if (sb > epsb) ret.push_back(nec_wire(b.x0, b_pt, b.radius,b._tag_id));
87 if (sb < 1.0 - epsb) ret.push_back(nec_wire(b_pt, b.x1, b.radius, b._tag_id));
88 }
89
90 return ret;
91}
92
93
97 bool intersect(nec_3vector& b0)
98 {
99 return axis_distance(b0) <= radius;
100 }
101
107 nec_float axis_distance(const nec_3vector& b0) const
108 {
109 nec_float a0x = x0(0); nec_float a0y = x0(1); nec_float a0z = x0(2);
110 nec_float a1x = x1(0); nec_float a1y = x1(1); nec_float a1z = x1(2);
111
112 nec_float b0x = b0(0); nec_float b0y = b0(1); nec_float b0z = b0(2);
113 /*
114 #
115 # Do the expression for intersection of a cylinder and a point
116 #
117 # aptitude install python-sympy
118 #
119 #
120 from sympy import *
121 from sympy.matrices import Matrix
122
123 a0x = Symbol('a0x')
124 a1x = Symbol('a1x')
125 a0y = Symbol('a0y')
126 a1y = Symbol('a1y')
127 a0z = Symbol('a0z')
128 a1z = Symbol('a1z')
129
130 b0x = Symbol('b0x')
131 b0y = Symbol('b0y')
132 b0z = Symbol('b0z')
133
134 a0 = Matrix([a0x,a0y,a0z])
135 b0 = Matrix([b0x,b0y,b0z])
136
137 a1 = Matrix([a1x,a1y,a1z])
138
139 # Each wire is parametrized by sa and sb
140 sa = Symbol('sa')
141
142 a = a0 + sa*(a1 - a0)
143 b = b0
144
145 # Distance between the two wires is d2
146 delta = (b-a)
147 d2 = delta.dot(delta)
148
149 print "Distance ="
150 print_python(d2)
151
152 # Closest point is the set of parameters (sa,sb) that minimize d2
153 # subject to the constraint that sa and sb are in the range [0,1]
154
155 eqn1 = diff(d2, sa)
156
157 equations = [Eq(eqn1,0)]
158 print "diff(d2,sa) = "
159 print eqn1
160
161
162 solution = solve(equations,[sa])
163
164 print solution
165 */
166
167 /* A degenerate wire with coincident endpoints has no axis to
168 measure against: the squared-length denominator below would be
169 zero and yield NaN. Fail loudly instead. */
170 nec_float sq_len =
171 (a1x-a0x)*(a1x-a0x) + (a1y-a0y)*(a1y-a0y) + (a1z-a0z)*(a1z-a0z);
172 if (sq_len == 0.0)
173 throw nec_exception("nec_wire::axis_distance(): zero-length wire");
174
175 nec_float sa = (a1x*b0x + a1y*b0y + a1z*b0z - a0x*a1x - a0x*b0x - a0y*a1y - a0y*b0y - a0z*a1z - a0z*b0z + a0x*a0x + a0y*a0y + a0z*a0z)/
176 sq_len;
177 if (sa < 0) sa = 0.0;
178 if (sa > 1.0) sa = 1.0;
179
180 nec_3vector a_pt = parametrize(sa);
181
182 return distance(a_pt, b0);
183
184 }
185
186 bool similar(nec_wire& b)
187 {
188 // Check if the wires share two endpoints
189 nec_float d1 = distance(x0, b.x0);
190 nec_float d2 = distance(x0, b.x1);
191 nec_float da = std::min(d1,d2);
192
193 nec_float d3 = distance(x1, b.x1);
194 nec_float d4 = distance(x1, b.x0);
195 nec_float db = std::min(d3,d4);
196
197 if ((std::abs(da) < radius) && (std::abs(db) < radius))
198 return true;
199 else
200 return false;
201 }
202
239 static void int_solve(nec_3vector& a0, nec_3vector& a1,
240 nec_3vector& b0, nec_3vector& b1,
241 nec_float& distance, nec_float& sa, nec_float& sb)
242 {
243 nec_float a0x = a0(0); nec_float a0y = a0(1); nec_float a0z = a0(2);
244 nec_float b0x = b0(0); nec_float b0y = b0(1); nec_float b0z = b0(2);
245 nec_float a1x = a1(0); nec_float a1y = a1(1); nec_float a1z = a1(2);
246 nec_float b1x = b1(0); nec_float b1y = b1(1); nec_float b1z = b1(2);
247
248 nec_float a01x = (a0x - a1x);
249 nec_float a01y = (a0y - a1y);
250 nec_float a01z = (a0z - a1z);
251
252 nec_float b01x = (b0x - b1x);
253 nec_float b01y = (b0y - b1y);
254 nec_float b01z = (b0z - b1z);
255
256 nec_float moda = (a01x*a01x + a01y*a01y + a01z*a01z);
257 nec_float modb = (b01x*b01x + b01y*b01y + b01z*b01z);
258
259 nec_float tmp2 = (a01x*b01x + a01y*b01y + a01z*b01z);
260
261 nec_float den = (-4.0*tmp2*tmp2 + 4.0*moda*modb);
262
263 distance = 9.0e9; sa = 2.0; sb = 2.0;
264 if (0 == den) return;
265
266 nec_float tmp3 = (-4.0*(a0x*a0x + a0y*a0y + a1x*b0x - a0x*(a1x + b0x) + a1y*b0y - a0y*(a1y + b0y) + a01z*(a0z - b0z))*tmp2 + 4.0*moda*((a0x - b0x)*b01x + (a0y - b0y)*b01y + (a0z - b0z)*b01z));
267
268 sa = (a0x*a01x + a0y*a01y + a0z*a01z - a01x*b0x - a01y*b0y - a01z*b0z - tmp3*tmp2/den)/moda;
269
270 sb = -(tmp3/den);
271
272 nec_float d2 = pow((a0x - b0x + sa*(a1x - a0x) - sb*(b1x - b0x)),2) +
273 pow((a0z - b0z + sa*(a1z - a0z) - sb*(b1z - b0z)),2) +
274 pow((a0y - b0y + sa*(a1y - a0y) - sb*(b1y - b0y)),2);
275
276 distance = std::sqrt(d2);
277 }
278
279private:
280 nec_3vector x0, x1;
281 nec_float radius;
282 int _tag_id;
283};
284
Definition nec_exception.h:28
A class to handle properties of wires.
Definition nec_wire.h:29
std::vector< nec_wire > intersect(nec_wire &b)
Calculate whether two wires intersect.
Definition nec_wire.h:66
static void int_solve(nec_3vector &a0, nec_3vector &a1, nec_3vector &b0, nec_3vector &b1, nec_float &distance, nec_float &sa, nec_float &sb)
Definition nec_wire.h:233
nec_float axis_distance(const nec_3vector &b0) const
Measure how far a point lies from the wire axis.
Definition nec_wire.h:107
bool intersect(nec_3vector &b0)
Calculate whether the point is inside the wire.
Definition nec_wire.h:97