3030namespace db
3131{
3232
33+ static const std::pair<db::Coord, db::Coord> ext_not_set = std::make_pair (std::numeric_limits<db::Coord>::min (), std::numeric_limits<db::Coord>::min ());
34+
3335struct DEFImporterGroup
3436{
3537 DEFImporterGroup (const std::string &n, const std::string &rn, const std::vector<tl::GlobPattern> &m)
@@ -133,7 +135,7 @@ DEFImporter::get_def_ext (const std::string & /*ln*/, const std::pair<db::Coord,
133135 return std::make_pair (de, de);
134136#else
135137 // This implementation follows the LEFDEF 5.8 spec saying the "default extension is half the wire width":
136- db::Coord de = std::min (wxy.first , wxy.second ) / 2 ;
138+ auto de = std::min (wxy.second , wxy.first ) / 2 ;
137139 return std::make_pair (de, de);
138140#endif
139141}
@@ -355,28 +357,46 @@ DEFImporter::produce_routing_geometry (db::Cell &design, const Polygon *style, u
355357 bool was_path_before = false ;
356358
357359 std::vector<db::Point>::const_iterator pt = pts.begin ();
360+ std::vector<std::pair<db::Coord, db::Coord> >::const_iterator ex = ext.begin ();
361+
358362 while (pt != pts.end ()) {
359363
360- std::vector<db::Point>::const_iterator pt0 = pt;
364+ auto pt0 = pt;
365+ auto ex0 = ex;
361366 ++pt;
367+ ++ex;
362368 if (pt == pts.end ()) {
363369 break ;
364370 }
365371
366372 bool multipart = false ;
367373 if (is_isotropic) {
368- while (pt != pts.end () && (pt[-1 ].x () == pt[0 ].x () || pt[-1 ].y () == pt[0 ].y ())) {
374+ while (pt != pts.end ()) {
375+ if (! (pt[-1 ].x () == pt[0 ].x () || pt[-1 ].y () == pt[0 ].y ())) {
376+ // non-orthogonal segments are treated otherwise, not by paths
377+ break ;
378+ }
379+ if (pt + 1 != pts.end () && ex[0 ] != ext_not_set) {
380+ // connection points feature non-default extensions and should not be represented by paths
381+ break ;
382+ }
369383 ++pt;
384+ ++ex;
370385 multipart = true ;
371386 }
372387 if (multipart) {
373388 --pt;
389+ --ex;
374390 }
375391 }
376392
377- // The next part is the interval [pt0..pt] (pt inclusive )
393+ // The next part is the interval [pt0..pt] (including pt )
378394
379- if (multipart || (pt0->x () == pt0[1 ].x () || pt0->y () == pt0[1 ].y ())) {
395+ if (! multipart && (pt0->x () == pt0[1 ].x () && pt0->y () == pt0[1 ].y ())) {
396+
397+ // ignore single-point paths
398+
399+ } else if (multipart || (pt0->x () == pt0[1 ].x () || pt0->y () == pt0[1 ].y ())) {
380400
381401 db::Coord wxy, wxy_perp;
382402
@@ -388,33 +408,27 @@ DEFImporter::produce_routing_geometry (db::Cell &design, const Polygon *style, u
388408 wxy_perp = w.second ;
389409 }
390410
391- // compute begin extension
411+ // compute begin and end extensions
392412 db::Coord be = 0 ;
393- if (pt0 == pts.begin ()) {
394- if (pt0->x () == pt0 [1 ].x ()) {
395- be = ext.front ().second ;
396- } else {
397- be = ext.front ().first ;
398- }
413+ if (*ex0 != ext_not_set) {
414+ be = (pt0->x () == pt0 [1 ].x ()) ? ex0->second : ex0->first ;
399415 } else if (was_path_before) {
400416 // provides the overlap to the previous segment
401417 be = wxy_perp / 2 ;
402418 }
403419
404- // compute end extension
405420 db::Coord ee = 0 ;
406- if (pt + 1 == pts.end ()) {
407- if (pt [-1 ].x () == pt->x ()) {
408- ee = ext.back ().second ;
409- } else {
410- ee = ext.back ().first ;
411- }
421+ if (*ex != ext_not_set) {
422+ ee = (pt [-1 ].x () == pt->x ()) ? ex->second : ex->first ;
412423 }
413424
414425 auto pt_from = pt0;
415426 auto pt_to = pt + 1 ;
416427
417- // do not split away end segments if they are shorter than half the width
428+ // Pplit paths if "joined_paths" is off. Sorry for spending the effort before to
429+ // compute multipath chains.
430+ // But now we can keep end segments joined if they are shorter than half the width
431+ // to establish a proper path end in that case.
418432
419433 auto pt_from_split = pt_from;
420434 auto pt_to_split = pt_to;
@@ -553,17 +567,16 @@ DEFImporter::read_single_net (std::string &nondefaultrule, Layout &layout, db::C
553567 const std::string *rulename = 0 ;
554568
555569 std::pair<db::Coord, db::Coord> w (0 , 0 );
556- if (specialnets) {
557- db::Coord n = db::coord_traits<db::Coord>::rounded (get_double () * scale);
558- w = std::make_pair (n, n);
559- }
560570
561571 const db::Polygon *style = 0 ;
562572
563573 int sn = std::numeric_limits<int >::max ();
564574
565575 if (specialnets) {
566576
577+ db::Coord n = db::coord_traits<db::Coord>::rounded (get_double () * scale);
578+ w = std::make_pair (n, n);
579+
567580 while (test (" +" )) {
568581
569582 if (test (" STYLE" )) {
@@ -598,11 +611,17 @@ DEFImporter::read_single_net (std::string &nondefaultrule, Layout &layout, db::C
598611 rulename = &nondefaultrule;
599612 }
600613
614+ if (! specialnets) {
615+ w = get_wire_width_for_rule (*rulename, ln, layout.dbu ());
616+ }
617+
618+ // default extension for first and last point
601619 std::pair<db::Coord, db::Coord> def_ext (0 , 0 );
620+ std::pair<db::Coord, db::Coord> def_ext_conn = get_def_ext (ln, w, layout.dbu ());
602621
603622 if (! specialnets) {
604- w = get_wire_width_for_rule (*rulename, ln, layout. dbu ());
605- def_ext = get_def_ext (ln, w, layout. dbu ()) ;
623+ // first and last extensions are half width by default for routed nets
624+ def_ext = def_ext_conn ;
606625 }
607626
608627 std::map<int , db::Polygon>::const_iterator s = m_styles.find (sn);
@@ -694,7 +713,7 @@ DEFImporter::read_single_net (std::string &nondefaultrule, Layout &layout, db::C
694713 y = get_double ();
695714 }
696715 pts.push_back (db::Point (db::DPoint (x * scale, y * scale)));
697- std::pair<db::Coord, db::Coord> ee = def_ext ;
716+ std::pair<db::Coord, db::Coord> ee = ext_not_set ;
698717 if (! peek (" )" )) {
699718 db::Coord e = db::coord_traits<db::Coord>::rounded (get_double () * scale);
700719 ee.first = ee.second = e;
@@ -706,10 +725,20 @@ DEFImporter::read_single_net (std::string &nondefaultrule, Layout &layout, db::C
706725 }
707726
708727 if (pts.size () > 1 ) {
728+
729+ // replace the default extensions
730+ if (ext.front () == ext_not_set) {
731+ ext.front () = def_ext;
732+ }
733+ if (ext.back () == ext_not_set) {
734+ ext.back () = def_ext;
735+ }
736+
709737 std::set <unsigned int > dl = open_layer (layout, ln, specialnets ? SpecialRouting : Routing, mask);
710738 for (std::set<unsigned int >::const_iterator l = dl.begin (); l != dl.end (); ++l) {
711739 produce_routing_geometry (design, style, *l, prop_id, pts, ext, w);
712740 }
741+
713742 }
714743
715744 // continue a segment with the current point and the new mask
0 commit comments