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.

736 lines
18 KiB

11 years ago
9 years ago
11 years ago
9 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
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
9 years ago
9 years ago
11 years ago
9 years ago
4 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
4 years ago
4 years ago
11 years ago
4 years ago
4 years ago
9 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
10 years ago
10 years ago
10 years ago
10 years ago
4 years ago
10 years ago
10 years ago
10 years ago
10 years ago
4 years ago
10 years ago
10 years ago
10 years ago
10 years ago
9 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
9 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
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
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
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
11 years ago
11 years ago
11 years ago
  1. /*
  2. * KiRouter - a push-and-(sometimes-)shove PCB router
  3. *
  4. * Copyright (C) 2013-2014 CERN
  5. * Copyright (C) 2016-2022 KiCad Developers, see AUTHORS.txt for contributors.
  6. * Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
  7. *
  8. * This program is free software: you can redistribute it and/or modify it
  9. * under the terms of the GNU General Public License as published by the
  10. * Free Software Foundation, either version 3 of the License, or (at your
  11. * option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful, but
  14. * WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  16. * General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License along
  19. * with this program. If not, see <http://www.gnu.org/licenses/>.
  20. */
  21. #include <base_units.h> // God forgive me doing this...
  22. #include "pns_node.h"
  23. #include "pns_itemset.h"
  24. #include "pns_meander.h"
  25. #include "pns_meander_placer_base.h"
  26. #include "pns_router.h"
  27. #include "pns_debug_decorator.h"
  28. namespace PNS {
  29. const MEANDER_SETTINGS& MEANDER_SHAPE::Settings() const
  30. {
  31. return m_placer->MeanderSettings();
  32. }
  33. const MEANDER_SETTINGS& MEANDERED_LINE::Settings() const
  34. {
  35. return m_placer->MeanderSettings();
  36. }
  37. void MEANDERED_LINE::MeanderSegment( const SEG& aBase, bool aSide, int aBaseIndex )
  38. {
  39. double base_len = aBase.Length();
  40. SHAPE_LINE_CHAIN lc;
  41. bool singleSided = Settings().m_singleSided;
  42. bool side = aSide;
  43. VECTOR2D dir( aBase.B - aBase.A );
  44. if( !m_dual )
  45. AddCorner( aBase.A );
  46. bool turning = false;
  47. bool started = false;
  48. m_last = aBase.A;
  49. do
  50. {
  51. MEANDER_SHAPE m( m_placer, m_width, m_dual );
  52. m.SetBaselineOffset( m_baselineOffset );
  53. m.SetBaseIndex( aBaseIndex );
  54. double thr = (double) m.spacing();
  55. bool fail = false;
  56. double remaining = base_len - ( m_last - aBase.A ).EuclideanNorm();
  57. auto addSingleIfFits = [&]()
  58. {
  59. fail = true;
  60. if( m.Fit( MT_SINGLE, aBase, m_last, side ) )
  61. {
  62. AddMeander( new MEANDER_SHAPE( m ) );
  63. fail = false;
  64. started = false;
  65. }
  66. if( fail && !singleSided )
  67. {
  68. if( m.Fit( MT_SINGLE, aBase, m_last, !side ) )
  69. {
  70. AddMeander( new MEANDER_SHAPE( m ) );
  71. fail = false;
  72. started = false;
  73. side = !side;
  74. }
  75. }
  76. };
  77. if( remaining < Settings( ).m_step )
  78. break;
  79. if( !singleSided && remaining > 3.0 * thr )
  80. {
  81. if( !turning )
  82. {
  83. for( int i = 0; i < 2; i++ )
  84. {
  85. bool checkSide = ( i == 0 ) ? side : !side;
  86. if( m.Fit( MT_CHECK_START, aBase, m_last, checkSide ) )
  87. {
  88. turning = true;
  89. AddMeander( new MEANDER_SHAPE( m ) );
  90. side = !checkSide;
  91. started = true;
  92. break;
  93. }
  94. }
  95. if( !turning )
  96. addSingleIfFits();
  97. }
  98. else
  99. {
  100. bool rv = m.Fit( MT_CHECK_FINISH, aBase, m_last, side );
  101. if( rv )
  102. {
  103. m.Fit( MT_TURN, aBase, m_last, side );
  104. AddMeander( new MEANDER_SHAPE( m ) );
  105. side = !side;
  106. started = true;
  107. }
  108. else
  109. {
  110. m.Fit( MT_FINISH, aBase, m_last, side );
  111. started = false;
  112. AddMeander( new MEANDER_SHAPE( m ) );
  113. turning = false;
  114. }
  115. }
  116. }
  117. else if( !singleSided && started )
  118. {
  119. bool rv = m.Fit( MT_FINISH, aBase, m_last, side );
  120. if( rv )
  121. AddMeander( new MEANDER_SHAPE( m ) );
  122. break;
  123. }
  124. else if( !turning && remaining > thr * 2.0 )
  125. {
  126. addSingleIfFits();
  127. }
  128. else
  129. {
  130. fail = true;
  131. }
  132. remaining = base_len - ( m_last - aBase.A ).EuclideanNorm( );
  133. if( remaining < Settings( ).m_step )
  134. break;
  135. if( fail )
  136. {
  137. MEANDER_SHAPE tmp( m_placer, m_width, m_dual );
  138. tmp.SetBaselineOffset( m_baselineOffset );
  139. tmp.SetBaseIndex( aBaseIndex );
  140. int nextP = tmp.spacing() - 2 * tmp.cornerRadius() + Settings().m_step;
  141. VECTOR2I pn = m_last + dir.Resize( nextP );
  142. if( aBase.Contains( pn ) && !m_dual )
  143. {
  144. AddCorner( pn );
  145. } else
  146. break;
  147. }
  148. } while( true );
  149. if( !m_dual )
  150. AddCorner( aBase.B );
  151. }
  152. int MEANDER_SHAPE::MinAmplitude() const
  153. {
  154. int minAmplitude = Settings().m_minAmplitude;
  155. // DP meanders don't really support smaller amplitudes
  156. minAmplitude = std::max( minAmplitude, std::abs( m_baselineOffset ) * 2 );
  157. // The path length won't be correct with very small arcs
  158. if( m_placer->MeanderSettings().m_cornerStyle == MEANDER_STYLE_ROUND )
  159. minAmplitude = std::max( minAmplitude, m_width + std::abs( m_baselineOffset ) * 2 );
  160. return minAmplitude;
  161. }
  162. int MEANDER_SHAPE::cornerRadius() const
  163. {
  164. // TODO: fix diff-pair meandering so we can use non-100% radii
  165. int rPercent = m_dual ? 100 : Settings().m_cornerRadiusPercentage;
  166. int optCr = (int64_t) spacing() * rPercent / 200;
  167. int minCr = std::abs( m_baselineOffset );
  168. int maxCr = std::min( m_amplitude / 2, spacing() / 2 );
  169. if( maxCr > minCr )
  170. return std::clamp( optCr, minCr, maxCr );
  171. else
  172. return maxCr;
  173. }
  174. int MEANDER_SHAPE::spacing( ) const
  175. {
  176. if( !m_dual )
  177. {
  178. return std::max( m_width + m_placer->Clearance(), Settings().m_spacing );
  179. }
  180. else
  181. {
  182. int sp = m_width + m_placer->Clearance() + ( 2 * std::abs( m_baselineOffset ) );
  183. return std::max( sp, Settings().m_spacing );
  184. }
  185. }
  186. SHAPE_LINE_CHAIN MEANDER_SHAPE::makeMiterShape( const VECTOR2D& aP, const VECTOR2D& aDir,
  187. bool aSide )
  188. {
  189. SHAPE_LINE_CHAIN lc;
  190. if( aDir.EuclideanNorm( ) == 0.0f )
  191. {
  192. lc.Append( aP );
  193. return lc;
  194. }
  195. VECTOR2D dir_u( aDir );
  196. VECTOR2D dir_v( aDir.Perpendicular( ) );
  197. VECTOR2D p = aP;
  198. lc.Append( ( int ) p.x, ( int ) p.y );
  199. // fixme: refactor
  200. switch( m_placer->MeanderSettings().m_cornerStyle )
  201. {
  202. case MEANDER_STYLE_ROUND:
  203. {
  204. VECTOR2D center = aP + dir_v * ( aSide ? -1.0 : 1.0 );
  205. lc.Append( SHAPE_ARC( center, aP, ( aSide ? -ANGLE_90 : ANGLE_90 ) ) );
  206. }
  207. break;
  208. case MEANDER_STYLE_CHAMFER:
  209. {
  210. double radius = (double) aDir.EuclideanNorm();
  211. double correction = 0;
  212. if( m_dual && radius > m_meanCornerRadius )
  213. correction = (double)( -2 * abs(m_baselineOffset) ) * tan( 22.5 * M_PI / 180.0 );
  214. VECTOR2D dir_cu = dir_u.Resize( correction );
  215. VECTOR2D dir_cv = dir_v.Resize( correction );
  216. p = aP - dir_cu;
  217. lc.Append( ( int ) p.x, ( int ) p.y );
  218. p = aP + dir_u + (dir_v + dir_cv) * ( aSide ? -1.0 : 1.0 );
  219. lc.Append( ( int ) p.x, ( int ) p.y );
  220. }
  221. break;
  222. }
  223. p = aP + dir_u + dir_v * ( aSide ? -1.0 : 1.0 );
  224. lc.Append( ( int ) p.x, ( int ) p.y );
  225. return lc;
  226. }
  227. void MEANDER_SHAPE::start( SHAPE_LINE_CHAIN* aTarget, const VECTOR2D& aWhere, const VECTOR2D& aDir )
  228. {
  229. m_currentTarget = aTarget;
  230. m_currentTarget->Clear();
  231. m_currentTarget->Append( aWhere );
  232. m_currentDir = aDir;
  233. m_currentPos = aWhere;
  234. }
  235. void MEANDER_SHAPE::forward( int aLength )
  236. {
  237. m_currentPos += m_currentDir.Resize( aLength );
  238. m_currentTarget->Append( m_currentPos );
  239. }
  240. void MEANDER_SHAPE::turn( const EDA_ANGLE& aAngle )
  241. {
  242. RotatePoint( m_currentDir, aAngle );
  243. }
  244. void MEANDER_SHAPE::miter( int aRadius, bool aSide )
  245. {
  246. if( aRadius <= 0 )
  247. {
  248. turn( aSide ? ANGLE_90 : -ANGLE_90 );
  249. return;
  250. }
  251. VECTOR2D dir = m_currentDir.Resize( (double) aRadius );
  252. SHAPE_LINE_CHAIN lc = makeMiterShape( m_currentPos, dir, aSide );
  253. m_currentPos = lc.CPoint( -1 );
  254. turn( aSide ? ANGLE_90 : -ANGLE_90 );
  255. m_currentTarget->Append( lc );
  256. }
  257. void MEANDER_SHAPE::uShape( int aSides, int aCorner, int aTop )
  258. {
  259. forward( aSides );
  260. miter( aCorner, true );
  261. forward( aTop );
  262. miter( aCorner, true );
  263. forward( aSides );
  264. }
  265. SHAPE_LINE_CHAIN MEANDER_SHAPE::genMeanderShape( const VECTOR2D& aP, const VECTOR2D& aDir,
  266. bool aSide, MEANDER_TYPE aType,
  267. int aBaselineOffset )
  268. {
  269. int cr = cornerRadius();
  270. int offset = aBaselineOffset;
  271. int spc = spacing();
  272. int amplitude = m_amplitude;
  273. int targetBaseLen = m_targetBaseLen;
  274. if( aSide )
  275. offset *= -1;
  276. VECTOR2D dir_u_b( aDir.Resize( offset ) );
  277. VECTOR2D dir_v_b( dir_u_b.Perpendicular() );
  278. if( 2 * cr > amplitude )
  279. {
  280. cr = amplitude / 2;
  281. }
  282. if( 2 * cr > spc )
  283. {
  284. cr = spc / 2;
  285. }
  286. if( cr - offset < 0 )
  287. {
  288. cr = offset;
  289. }
  290. m_meanCornerRadius = cr;
  291. int sCorner = cr - offset;
  292. int uCorner = cr + offset;
  293. int startSide = amplitude - 2 * cr + std::abs( offset );
  294. int turnSide = amplitude - cr;
  295. int top = spc - 2 * cr;
  296. SHAPE_LINE_CHAIN lc;
  297. start( &lc, aP + dir_v_b, aDir );
  298. switch( aType )
  299. {
  300. case MT_EMPTY:
  301. {
  302. lc.Append( aP + dir_v_b + aDir );
  303. break;
  304. }
  305. case MT_START:
  306. {
  307. if( targetBaseLen )
  308. top = std::max( top, targetBaseLen - sCorner - uCorner * 2 + offset );
  309. miter( sCorner, false );
  310. uShape( startSide, uCorner, top );
  311. forward( std::min( sCorner, uCorner ) );
  312. forward( std::abs( offset ) );
  313. break;
  314. }
  315. case MT_FINISH:
  316. {
  317. if( targetBaseLen )
  318. top = std::max( top, targetBaseLen - cr - spc );
  319. start( &lc, aP - dir_u_b, aDir );
  320. turn( -ANGLE_90 );
  321. forward( std::min( sCorner, uCorner ) );
  322. forward( std::abs( offset ) );
  323. uShape( startSide, uCorner, top );
  324. miter( sCorner, false );
  325. if( targetBaseLen >= spc + cr )
  326. lc.Append( aP + dir_v_b + aDir.Resize( targetBaseLen ) );
  327. else
  328. lc.Append( aP + dir_v_b + aDir.Resize( 2 * spc - cr ) );
  329. break;
  330. }
  331. case MT_TURN:
  332. {
  333. if( targetBaseLen )
  334. top = std::max( top, targetBaseLen - uCorner * 2 + offset * 2 );
  335. start( &lc, aP - dir_u_b, aDir );
  336. turn( -ANGLE_90 );
  337. forward( std::abs( offset ) );
  338. uShape( turnSide, uCorner, top );
  339. forward( std::abs( offset ) );
  340. break;
  341. }
  342. case MT_SINGLE:
  343. {
  344. if( targetBaseLen )
  345. top = std::max( top, ( targetBaseLen - sCorner * 2 - uCorner * 2 ) / 2 );
  346. miter( sCorner, false );
  347. uShape( startSide, uCorner, top );
  348. miter( sCorner, false );
  349. lc.Append( aP + dir_v_b + aDir.Resize( 2 * spc ) );
  350. break;
  351. }
  352. default: break;
  353. }
  354. if( aSide )
  355. {
  356. SEG axis( aP, aP + aDir );
  357. lc.Mirror( axis );
  358. }
  359. return lc;
  360. }
  361. bool MEANDERED_LINE::CheckSelfIntersections( MEANDER_SHAPE* aShape, int aClearance )
  362. {
  363. for( int i = m_meanders.size() - 1; i >= 0; i-- )
  364. {
  365. MEANDER_SHAPE* m = m_meanders[i];
  366. if( m->Type() == MT_EMPTY || m->Type() == MT_CORNER )
  367. continue;
  368. const SEG& b1 = aShape->BaseSegment();
  369. const SEG& b2 = m->BaseSegment();
  370. if( b1.ApproxParallel( b2 ) )
  371. continue;
  372. int n = m->CLine( 0 ).SegmentCount();
  373. for( int j = n - 1; j >= 0; j-- )
  374. {
  375. if( aShape->CLine( 0 ).Collide( m->CLine( 0 ) .CSegment( j ), aClearance ) )
  376. return false;
  377. }
  378. }
  379. return true;
  380. }
  381. bool MEANDER_SHAPE::Fit( MEANDER_TYPE aType, const SEG& aSeg, const VECTOR2I& aP, bool aSide )
  382. {
  383. const MEANDER_SETTINGS& st = Settings();
  384. bool checkMode = false;
  385. MEANDER_TYPE prim1, prim2;
  386. if( aType == MT_CHECK_START )
  387. {
  388. prim1 = MT_START;
  389. prim2 = MT_TURN;
  390. checkMode = true;
  391. }
  392. else if( aType == MT_CHECK_FINISH )
  393. {
  394. prim1 = MT_TURN;
  395. prim2 = MT_FINISH;
  396. checkMode = true;
  397. }
  398. if( checkMode )
  399. {
  400. MEANDER_SHAPE m1( m_placer, m_width, m_dual );
  401. MEANDER_SHAPE m2( m_placer, m_width, m_dual );
  402. m1.SetBaselineOffset( m_baselineOffset );
  403. m2.SetBaselineOffset( m_baselineOffset );
  404. bool c1 = m1.Fit( prim1, aSeg, aP, aSide );
  405. bool c2 = false;
  406. if( c1 )
  407. c2 = m2.Fit( prim2, aSeg, m1.End(), !aSide );
  408. if( c1 && c2 )
  409. {
  410. m_type = prim1;
  411. m_shapes[0] = m1.m_shapes[0];
  412. m_shapes[1] = m1.m_shapes[1];
  413. m_baseSeg =aSeg;
  414. m_p0 = aP;
  415. m_side = aSide;
  416. m_amplitude = m1.Amplitude();
  417. m_dual = m1.m_dual;
  418. m_baseSeg = m1.m_baseSeg;
  419. m_baseIndex = m1.m_baseIndex;
  420. updateBaseSegment();
  421. m_baselineOffset = m1.m_baselineOffset;
  422. return true;
  423. }
  424. else
  425. {
  426. return false;
  427. }
  428. }
  429. int minAmpl = MinAmplitude();
  430. int maxAmpl = std::max( st.m_maxAmplitude, minAmpl );
  431. for( int ampl = maxAmpl; ampl >= minAmpl; ampl -= st.m_step )
  432. {
  433. m_amplitude = ampl;
  434. if( m_dual )
  435. {
  436. m_shapes[0] = genMeanderShape( aP, aSeg.B - aSeg.A, aSide, aType, m_baselineOffset );
  437. m_shapes[1] = genMeanderShape( aP, aSeg.B - aSeg.A, aSide, aType, -m_baselineOffset );
  438. }
  439. else
  440. {
  441. m_shapes[0] = genMeanderShape( aP, aSeg.B - aSeg.A, aSide, aType, 0 );
  442. }
  443. m_type = aType;
  444. m_baseSeg = aSeg;
  445. m_p0 = aP;
  446. m_side = aSide;
  447. updateBaseSegment();
  448. if( m_placer->CheckFit( this ) )
  449. return true;
  450. }
  451. return false;
  452. }
  453. void MEANDER_SHAPE::Recalculate()
  454. {
  455. m_shapes[0] = genMeanderShape( m_p0, m_baseSeg.B - m_baseSeg.A, m_side, m_type,
  456. m_dual ? m_baselineOffset : 0 );
  457. if( m_dual )
  458. m_shapes[1] = genMeanderShape( m_p0, m_baseSeg.B - m_baseSeg.A, m_side, m_type,
  459. -m_baselineOffset );
  460. updateBaseSegment();
  461. }
  462. void MEANDER_SHAPE::Resize( int aAmpl )
  463. {
  464. if( aAmpl < 0 )
  465. return;
  466. m_amplitude = aAmpl;
  467. Recalculate();
  468. }
  469. void MEANDER_SHAPE::MakeEmpty()
  470. {
  471. updateBaseSegment();
  472. VECTOR2I dir = m_clippedBaseSeg.B - m_clippedBaseSeg.A;
  473. m_type = MT_EMPTY;
  474. m_amplitude = 0;
  475. m_shapes[0] = genMeanderShape( m_p0, dir, m_side, m_type, m_dual ? m_baselineOffset : 0 );
  476. if( m_dual )
  477. m_shapes[1] = genMeanderShape( m_p0, dir, m_side, m_type, -m_baselineOffset );
  478. }
  479. void MEANDERED_LINE::AddCorner( const VECTOR2I& aA, const VECTOR2I& aB )
  480. {
  481. MEANDER_SHAPE* m = new MEANDER_SHAPE( m_placer, m_width, m_dual );
  482. m->MakeCorner( aA, aB );
  483. m_last = aA;
  484. m_meanders.push_back( m );
  485. }
  486. void MEANDERED_LINE::AddArc( const SHAPE_ARC& aArc1, const SHAPE_ARC& aArc2 )
  487. {
  488. MEANDER_SHAPE* m = new MEANDER_SHAPE( m_placer, m_width, m_dual );
  489. m->MakeArc( aArc1, aArc2 );
  490. m_last = aArc1.GetP1();
  491. m_meanders.push_back( m );
  492. }
  493. void MEANDERED_LINE::AddArcAndPt( const SHAPE_ARC& aArc1, const VECTOR2I& aPt2 )
  494. {
  495. SHAPE_ARC arc2( aPt2, aPt2, aPt2, 0 );
  496. AddArc( aArc1, arc2 );
  497. }
  498. void MEANDERED_LINE::AddPtAndArc( const VECTOR2I& aPt1, const SHAPE_ARC& aArc2 )
  499. {
  500. SHAPE_ARC arc1( aPt1, aPt1, aPt1, 0 );
  501. AddArc( arc1, aArc2 );
  502. }
  503. void MEANDER_SHAPE::MakeCorner( const VECTOR2I& aP1, const VECTOR2I& aP2 )
  504. {
  505. SetType( MT_CORNER );
  506. m_shapes[0].Clear();
  507. m_shapes[1].Clear();
  508. m_shapes[0].Append( aP1 );
  509. m_shapes[1].Append( aP2 );
  510. m_clippedBaseSeg.A = aP1;
  511. m_clippedBaseSeg.B = aP1;
  512. }
  513. void MEANDER_SHAPE::MakeArc( const SHAPE_ARC& aArc1, const SHAPE_ARC& aArc2 )
  514. {
  515. SetType( MT_CORNER );
  516. m_shapes[0].Clear();
  517. m_shapes[1].Clear();
  518. m_shapes[0].Append( aArc1 );
  519. m_shapes[1].Append( aArc2 );
  520. m_clippedBaseSeg.A = aArc1.GetP1();
  521. m_clippedBaseSeg.B = aArc1.GetP1();
  522. }
  523. void MEANDERED_LINE::AddMeander( MEANDER_SHAPE* aShape )
  524. {
  525. m_last = aShape->BaseSegment().B;
  526. m_meanders.push_back( aShape );
  527. }
  528. void MEANDERED_LINE::Clear()
  529. {
  530. for( MEANDER_SHAPE* m : m_meanders )
  531. {
  532. delete m;
  533. }
  534. m_meanders.clear( );
  535. }
  536. int MEANDER_SHAPE::BaselineLength() const
  537. {
  538. return m_clippedBaseSeg.Length();
  539. }
  540. long long int MEANDER_SHAPE::CurrentLength() const
  541. {
  542. return CLine( 0 ).Length();
  543. }
  544. long long int MEANDER_SHAPE::MinTunableLength() const
  545. {
  546. MEANDER_SHAPE copy = *this;
  547. copy.SetTargetBaselineLength( BaselineLength() );
  548. copy.Resize( copy.MinAmplitude() );
  549. return copy.CurrentLength();
  550. }
  551. void MEANDER_SHAPE::updateBaseSegment( )
  552. {
  553. if( m_dual )
  554. {
  555. VECTOR2I midpA = ( CLine( 0 ).CPoint( 0 ) + CLine( 1 ).CPoint( 0 ) ) / 2;
  556. VECTOR2I midpB = ( CLine( 0 ).CPoint( -1 ) + CLine( 1 ).CPoint( -1 ) ) / 2;
  557. m_clippedBaseSeg.A = m_baseSeg.LineProject( midpA );
  558. m_clippedBaseSeg.B = m_baseSeg.LineProject( midpB );
  559. }
  560. else
  561. {
  562. m_clippedBaseSeg.A = m_baseSeg.LineProject( CLine( 0 ).CPoint( 0 ) );
  563. m_clippedBaseSeg.B = m_baseSeg.LineProject( CLine( 0 ).CPoint( -1 ) );
  564. }
  565. }
  566. }