2.2 lines: non-intersecting lines
using an intersection test on top of the distance function to join the dots
/**
* Copyright nicoptere ( http://wonderfl.net/user/nicoptere )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/gkXV
*/
package
{
import com.bit101.components.HUISlider;
import com.bit101.components.PushButton;
import flash.display.Sprite;
import flash.events.Event;
import flash.geom.Point;
/**
* @author Nicolas Barradeau
* http://en.nicoptere.net
*/
public class ProximityIntersectDistribution extends Sprite
{
private var points:Vector.<Point> = Vector.<Point>([ new Point(297.48,180.02),new Point(302.56,145.32),new Point(283.75,88.31),new Point(237.16,66.59),new Point(198.93,78.66),new Point(184.90,103.70),new Point(193.26,129.34),new Point(201.62,152.56),new Point(195.35,169.76),new Point(179.52,176.70),new Point(158.32,165.23),new Point(148.46,132.35),new Point(175.64,75.64),new Point(249.40,50.90),new Point(334.51,84.99),new Point(354.52,140.20),new Point(345.56,182.73),new Point(310.92,233.71),new Point(261.05,299.77),new Point(250.00,352.87),new Point(238.35,352.87),new Point(247.31,294.04),new Point(275.68,228.88),new Point(246.12,450.90),new Point(224.02,441.86),new Point(214.76,419.53),new Point(224.02,397.21),new Point(246.12,387.86),new Point(268.52,397.21),new Point(277.47,419.53),new Point(268.22,441.86)]);
private var pairs:Vector.<Point> = new Vector.<Point>();
private var distanceSlider:HUISlider;
private var minDist:Number;
public function ProximityIntersectDistribution()
{
var randomizeBtn:PushButton = new PushButton( this, 200, 10, 'randomize', onRandomizeButtonClick );
distanceSlider = new HUISlider( this, 10, 10, 'distance', onDistanceChange );
distanceSlider.maximum = 500;
distanceSlider.value = 25;
onDistanceChange( null );
}
private function onDistanceChange( e:Event ):void
{
minDist = distanceSlider.value * distanceSlider.value;
redraw();
}
private function redraw():void
{
graphics.clear();
graphics.lineStyle( 0 );
pairs.length = 0; //resets pairs associations
var addPair:Boolean;
var i:int;
var p:Point, pp:Point;
for each( p in points )
{
for each( pp in points )
{
if ( p === pp ) continue;
if ( ( ( p.x - pp.x ) * ( p.x - pp.x ) + ( p.y - pp.y ) * ( p.y - pp.y ) ) < minDist )
{
//if we're under the minimum distance
addPair = true;
//for each existing pair
intersection : for ( i = 0; i < pairs.length; i += 2 )
{
//checks if the segment p-pp intersects any existing segment
if ( lineIntersectLine( pairs[ i ], pairs[ i + 1 ], p, pp ) != null )
{
addPair = false;
break intersection; // this breaks the "intersection" for() loop
}
}
//nothing intersected the segment p-pp
if ( addPair ) pairs.push( p, pp );
}
}
}
//drawing the valid pairs
for ( i = 0; i < pairs.length; i += 2 )
{
graphics.moveTo( pairs[ i ].x, pairs[ i ].y );
graphics.lineTo( pairs[ i + 1 ].x, pairs[ i + 1 ].y );
}
}
/**
* original function by Keith Hair:
* http://keith-hair.net/blog/2008/08/04/find-intersection-point-of-two-lines-in-as3/
*
* extended by Hristo Dachev
* http://blog.controul.com/2009/05/line-segment-intersection/
*
* @param A line 1 point 1
* @param B line 1 point 2
* @param E line 2 point 1
* @param F line 2 point 2
* @param ABasSeg should the test consider line 1 as a segment
* @param EFasSeg should the test consider line 2 as a segment
* @return
*/
public function lineIntersectLine ( A : Point, B : Point,
E : Point, F : Point,
ABasSeg : Boolean = true, EFasSeg : Boolean = true ) : Point
{
var a1:Number = B.y - A.y;
var a2:Number = F.y - E.y;
var b1:Number = A.x - B.x;
var b2:Number = E.x - F.x;
var denom:Number = a1 * b2 - a2 * b1;
if (denom == 0)
{
return null;
}
var c1:Number = B.x * A.y - A.x * B.y;
var c2:Number = F.x * E.y - E.x * F.y;
var ip:Point = new Point( (b1 * c2 - b2 * c1) / denom,
(a2 * c1 - a1 * c2) / denom );
//---------------------------------------------------
//Do checks to see if intersection to endpoints
//distance is longer than actual pairs.
//Return null if it is with any.
//---------------------------------------------------
if ( A.x == B.x )
ip.x = A.x;
else if ( E.x == F.x )
ip.x = E.x;
if ( A.y == B.y )
ip.y = A.y;
else if ( E.y == F.y )
ip.y = E.y;
// Constrain to segment.
if ( ABasSeg )
{
if ( ( A.x < B.x ) ? ip.x < A.x || ip.x > B.x : ip.x > A.x || ip.x < B.x )
return null;
if ( ( A.y < B.y ) ? ip.y < A.y || ip.y > B.y : ip.y > A.y || ip.y < B.y )
return null;
}
if ( EFasSeg )
{
if ( ( E.x < F.x ) ? ip.x < E.x || ip.x > F.x : ip.x > E.x || ip.x < F.x )
return null;
if ( ( E.y < F.y ) ? ip.y < E.y || ip.y > F.y : ip.y > E.y || ip.y < F.y )
return null;
}
return ip;
}
private function onRandomizeButtonClick( e:Event ):void
{
points.sort( randomize );
redraw();
}
private function randomize( a:Point, b:Point ):Number
{
return ( Math.random() > .5 ) ? -1 : 1;
}
}
}