You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

357 lines
8.5 KiB

11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
  1. /*
  2. * KiRouter - a push-and-(sometimes-)shove PCB router
  3. *
  4. * Copyright (C) 2013-2015 CERN
  5. * Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
  6. *
  7. * This program is free software: you can redistribute it and/or modify it
  8. * under the terms of the GNU General Public License as published by the
  9. * Free Software Foundation, either version 3 of the License, or (at your
  10. * option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful, but
  13. * WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License along
  18. * with this program. If not, see <http://www.gnu.or/licenses/>.
  19. */
  20. #ifndef __DIRECTION_H
  21. #define __DIRECTION_H
  22. #include <geometry/seg.h>
  23. #include <geometry/shape_line_chain.h>
  24. /**
  25. * Class DIRECTION_45.
  26. * Represents route directions & corner angles in a 45-degree metric.
  27. */
  28. class DIRECTION_45
  29. {
  30. public:
  31. /**
  32. * Enum Directions
  33. * Represents available directions - there are 8 of them, as on a rectilinear map (north = up) +
  34. * an extra undefined direction, reserved for traces that don't respect 45-degree routing regime.
  35. */
  36. enum Directions
  37. {
  38. N = 0,
  39. NE = 1,
  40. E = 2,
  41. SE = 3,
  42. S = 4,
  43. SW = 5,
  44. W = 6,
  45. NW = 7,
  46. UNDEFINED = -1
  47. };
  48. /**
  49. * Enum AngleType
  50. * Represents kind of angle formed by vectors heading in two DIRECTION_45s.
  51. */
  52. enum AngleType
  53. {
  54. ANG_OBTUSE = 0x01,
  55. ANG_RIGHT = 0x02,
  56. ANG_ACUTE = 0x04,
  57. ANG_STRAIGHT = 0x08,
  58. ANG_HALF_FULL = 0x10,
  59. ANG_UNDEFINED = 0x20
  60. };
  61. DIRECTION_45( Directions aDir = UNDEFINED ) : m_dir( aDir ) {}
  62. /**
  63. * Constructor
  64. * @param aVec vector, whose direction will be translated into a DIRECTION_45.
  65. */
  66. DIRECTION_45( const VECTOR2I& aVec )
  67. {
  68. construct_( aVec );
  69. }
  70. /**
  71. * Constructor
  72. * @param aSeg segment, whose direction will be translated into a DIRECTION_45.
  73. */
  74. DIRECTION_45( const SEG& aSeg )
  75. {
  76. construct_( aSeg.B - aSeg.A );
  77. }
  78. /**
  79. * Function Format()
  80. * Formats the direction in a human readable word.
  81. * @return name of the direction
  82. */
  83. const std::string Format() const
  84. {
  85. switch( m_dir )
  86. {
  87. case N:
  88. return "north";
  89. case NE:
  90. return "north-east";
  91. case E:
  92. return "east";
  93. case SE:
  94. return "south-east";
  95. case S:
  96. return "south";
  97. case SW:
  98. return "south-west";
  99. case W:
  100. return "west";
  101. case NW:
  102. return "north-west";
  103. case UNDEFINED:
  104. return "undefined";
  105. default:
  106. return "<Error>";
  107. }
  108. }
  109. /**
  110. * Function Opposite()
  111. * Returns a direction opposite (180 degree) to (this)
  112. * @return opposite direction
  113. */
  114. DIRECTION_45 Opposite() const
  115. {
  116. const Directions OppositeMap[] = { S, SW, W, NW, N, NE, E, SE, UNDEFINED };
  117. return OppositeMap[m_dir];
  118. }
  119. /**
  120. * Function Angle()
  121. * Returns the type of angle between directions (this) and aOther.
  122. * @param aOther direction to compare angle with
  123. */
  124. AngleType Angle( const DIRECTION_45& aOther ) const
  125. {
  126. if( m_dir == UNDEFINED || aOther.m_dir == UNDEFINED )
  127. return ANG_UNDEFINED;
  128. int d = std::abs( m_dir - aOther.m_dir );
  129. if( d == 1 || d == 7 )
  130. return ANG_OBTUSE;
  131. else if( d == 2 || d == 6 )
  132. return ANG_RIGHT;
  133. else if( d == 3 || d == 5 )
  134. return ANG_ACUTE;
  135. else if( d == 4 )
  136. return ANG_HALF_FULL;
  137. else
  138. return ANG_STRAIGHT;
  139. }
  140. /**
  141. * Function IsObtuse()
  142. * @return true, when (this) forms an obtuse angle with aOther
  143. */
  144. bool IsObtuse( const DIRECTION_45& aOther ) const
  145. {
  146. return Angle( aOther ) == ANG_OBTUSE;
  147. }
  148. /**
  149. * Function IsDiagonal()
  150. * Returns true if the direction is diagonal (e.g. North-West, South-East, etc)
  151. * @return true, when diagonal.
  152. */
  153. bool IsDiagonal() const
  154. {
  155. return ( m_dir % 2 ) == 1;
  156. }
  157. bool IsDefined() const
  158. {
  159. return m_dir != UNDEFINED;
  160. }
  161. /**
  162. * Function BuildInitialTrace()
  163. *
  164. * Builds a 2-segment line chain between points aP0 and aP1 and following 45-degree routing
  165. * regime. If aStartDiagonal is true, the trace starts with a diagonal segment.
  166. * @param aP0 starting point
  167. * @param aP1 ending point
  168. * @param aStartDiagonal whether the first segment has to be diagonal
  169. * @return the trace
  170. */
  171. const SHAPE_LINE_CHAIN BuildInitialTrace( const VECTOR2I& aP0,
  172. const VECTOR2I& aP1,
  173. bool aStartDiagonal = false ) const
  174. {
  175. int w = abs( aP1.x - aP0.x );
  176. int h = abs( aP1.y - aP0.y );
  177. int sw = sign( aP1.x - aP0.x );
  178. int sh = sign( aP1.y - aP0.y );
  179. VECTOR2I mp0, mp1;
  180. // we are more horizontal than vertical?
  181. if( w > h )
  182. {
  183. mp0 = VECTOR2I( ( w - h ) * sw, 0 ); // direction: E
  184. mp1 = VECTOR2I( h * sw, h * sh ); // direction: NE
  185. }
  186. else
  187. {
  188. mp0 = VECTOR2I( 0, sh * ( h - w ) ); // direction: N
  189. mp1 = VECTOR2I( sw * w, sh * w ); // direction: NE
  190. }
  191. bool start_diagonal;
  192. if( m_dir == UNDEFINED )
  193. start_diagonal = aStartDiagonal;
  194. else
  195. start_diagonal = IsDiagonal();
  196. SHAPE_LINE_CHAIN pl;
  197. pl.Append( aP0 );
  198. if( start_diagonal )
  199. pl.Append( aP0 + mp1 );
  200. else
  201. pl.Append( aP0 + mp0 );
  202. pl.Append( aP1 );
  203. pl.Simplify();
  204. return pl;
  205. }
  206. bool operator==( const DIRECTION_45& aOther ) const
  207. {
  208. return aOther.m_dir == m_dir;
  209. }
  210. bool operator!=( const DIRECTION_45& aOther ) const
  211. {
  212. return aOther.m_dir != m_dir;
  213. }
  214. /**
  215. * Function Right()
  216. *
  217. * Returns the direction on the right side of this (i.e. turns right
  218. * by 45 deg)
  219. */
  220. const DIRECTION_45 Right() const
  221. {
  222. DIRECTION_45 r;
  223. if ( m_dir != UNDEFINED )
  224. r.m_dir = static_cast<Directions>( ( m_dir + 1 ) % 8 );
  225. return r;
  226. }
  227. /**
  228. * Function Left()
  229. *
  230. * Returns the direction on the left side of this (i.e. turns left
  231. * by 45 deg)
  232. */
  233. const DIRECTION_45 Left() const
  234. {
  235. DIRECTION_45 l;
  236. if ( m_dir == UNDEFINED )
  237. return l;
  238. if( m_dir == N )
  239. l.m_dir = NW;
  240. else
  241. l.m_dir = static_cast<Directions>( m_dir - 1 );
  242. return l;
  243. }
  244. /**
  245. * Function ToVector()
  246. *
  247. * Returns a unit vector corresponding to our direction.
  248. */
  249. const VECTOR2I ToVector() const
  250. {
  251. switch( m_dir )
  252. {
  253. case N: return VECTOR2I( 0, 1 );
  254. case S: return VECTOR2I( 0, -1 );
  255. case E: return VECTOR2I( 1, 0 );
  256. case W: return VECTOR2I( -1, 0 );
  257. case NE: return VECTOR2I( 1, 1 );
  258. case NW: return VECTOR2I( -1, 1 );
  259. case SE: return VECTOR2I( 1, -1 );
  260. case SW: return VECTOR2I( -1, -1 );
  261. default:
  262. return VECTOR2I( 0, 0 );
  263. }
  264. }
  265. int Mask() const
  266. {
  267. return 1 << ( (int) m_dir );
  268. }
  269. private:
  270. /**
  271. * Function construct()
  272. * Calculates the direction from a vector. If the vector's angle is not a multiple of 45
  273. * degrees, the direction is rounded to the nearest octant.
  274. * @param aVec our vector
  275. */
  276. void construct_( const VECTOR2I& aVec )
  277. {
  278. m_dir = UNDEFINED;
  279. if( aVec.x == 0 && aVec.y == 0 )
  280. return;
  281. double mag = 360.0 - ( 180.0 / M_PI * atan2( (double) aVec.y, (double) aVec.x ) ) + 90.0;
  282. if( mag >= 360.0 )
  283. mag -= 360.0;
  284. if( mag < 0.0 )
  285. mag += 360.0;
  286. int dir = ( mag + 22.5 ) / 45.0;
  287. if( dir >= 8 )
  288. dir = dir - 8;
  289. if( dir < 0 )
  290. dir = dir + 8;
  291. m_dir = (Directions) dir;
  292. return;
  293. }
  294. ///> our actual direction
  295. Directions m_dir;
  296. };
  297. #endif // __DIRECTION_H