void PNS_LINE::DragSegment ( const VECTOR2I& aP, int aIndex, int aSnappingThreshold ) { SHAPE_LINE_CHAIN path( m_line ); VECTOR2I target( aP ); SEG guideA[2], guideB[2]; int index = aIndex; target = snapToNeighbourSegments( path, aP, aIndex, aSnappingThreshold ); if( index == 0 ) { path.Insert( 0, path.CPoint( 0 ) ); index++; } if( index == path.SegmentCount() - 1 ) { path.Insert( path.PointCount() - 1, path.CPoint( -1 ) ); } SEG dragged = path.CSegment( index ); DIRECTION_45 drag_dir( dragged ); SEG s_prev = path.CSegment( index - 1 ); SEG s_next = path.CSegment( index + 1 ); DIRECTION_45 dir_prev( s_prev ); DIRECTION_45 dir_next( s_next ); if( dir_prev == drag_dir ) { dir_prev = dir_prev.Left(); path.Insert( index, path.CPoint( index ) ); index++; } if( dir_next == drag_dir ) { dir_next = dir_next.Right(); path.Insert( index + 1, path.CPoint( index + 1 ) ); } s_prev = path.CSegment( index - 1 ); s_next = path.CSegment( index + 1 ); dragged = path.CSegment( index ); bool lockEndpointA = true; bool lockEndpointB = true; if( aIndex == 0 ) { if( !lockEndpointA ) guideA[0] = guideA[1] = SEG( dragged.A, dragged.A + drag_dir.Right().Right().ToVector() ); else { guideA[0] = SEG( dragged.A, dragged.A + drag_dir.Right().ToVector() ); guideA[1] = SEG( dragged.A, dragged.A + drag_dir.Left().ToVector() ); } } else { if( dir_prev.IsObtuse(drag_dir ) ) { guideA[0] = SEG( s_prev.A, s_prev.A + drag_dir.Left().ToVector() ); guideA[1] = SEG( s_prev.A, s_prev.A + drag_dir.Right().ToVector() ); } else guideA[0] = guideA[1] = SEG( dragged.A, dragged.A + dir_prev.ToVector() ); } if( aIndex == m_line.SegmentCount() - 1 ) { if( !lockEndpointB ) guideB[0] = guideB[1] = SEG( dragged.B, dragged.B + drag_dir.Right().Right().ToVector() ); else { guideB[0] = SEG( dragged.B, dragged.B + drag_dir.Right().ToVector() ); guideB[1] = SEG( dragged.B, dragged.B + drag_dir.Left().ToVector() ); } } else { if( dir_next.IsObtuse( drag_dir ) ) { guideB[0] = SEG( s_next.B, s_next.B + drag_dir.Left().ToVector() ); guideB[1] = SEG( s_next.B, s_next.B + drag_dir.Right().ToVector() ); } else guideB[0] = guideB[1] = SEG( dragged.B, dragged.B + dir_next.ToVector() ); } SEG s_current( target, target + drag_dir.ToVector() ); int best_len = INT_MAX; SHAPE_LINE_CHAIN best; for( int i = 0; i < 2; i++ ) { for( int j = 0; j < 2; j++ ) { OPT_VECTOR2I ip1 = s_current.IntersectLines( guideA[i] ); OPT_VECTOR2I ip2 = s_current.IntersectLines( guideB[j] ); SHAPE_LINE_CHAIN np; if( !ip1 || !ip2 ) continue; SEG s1( s_prev.A, *ip1 ); SEG s2( *ip1, *ip2 ); SEG s3( *ip2, s_next.B ); OPT_VECTOR2I ip; if( (ip = s1.Intersect( s_next )) ) { np.Append ( s1.A ); np.Append ( *ip ); np.Append ( s_next.B ); } else if( (ip = s3.Intersect( s_prev )) ) { np.Append ( s_prev.A ); np.Append ( *ip ); np.Append ( s3.B ); } else if( (ip = s1.Intersect( s3 )) ) { np.Append( s_prev.A ); np.Append( *ip ); np.Append( s_next.B ); } else { np.Append( s_prev.A ); np.Append( *ip1 ); np.Append( *ip2 ); np.Append( s_next.B ); } if( np.Length() < best_len ) { best_len = np.Length(); best = np; } } } if( !lockEndpointA && aIndex == 0 ) best.Remove( 0, 0 ); if( !lockEndpointB && aIndex == m_line.SegmentCount() - 1 ) best.Remove( -1, -1 ); if( m_line.PointCount() == 1 ) m_line = best; else if( aIndex == 0 ) m_line.Replace( 0, 1, best ); else if( aIndex == m_line.SegmentCount() - 1 ) m_line.Replace( -2, -1, best ); else m_line.Replace( aIndex, aIndex + 1, best ); m_line.Simplify(); }