[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Re: Overlapping circles - modelling living populations

Gavin Kistner

9/9/2006 3:45:00 PM

Here's a slightly better version that uses the overlapping status of a circle to change its color. (It doesn't do anything with pairs of circles, though that'd also be easy...you just have to know how you'd want to visualize it.)

# http://downloads.sourceforge.jp/ruby-svg/2288/ruby-svg-1....
require 'svg/svg'

class Array
def each_unique_pair
self.each_with_index{ |a,i|
self[(i+1)..-1].each{ |b| yield a,b }
}
end
end

class SVG::Circle
# test (and save) result
def overlaps?( other_circle )
center_distance = Math.sqrt(
( cx - other_circle.cx ) ** 2 +
( cy - other_circle.cy ) ** 2
)

intersects = center_distance < ( r + other_circle.r )

# Save the result on both circles
other_circle.overlaps[ self ] = intersects
self.overlaps[ other_circle ] = intersects
end

def overlaps
# Make sure we have a hash to save a set of overlappers
@overlapping_circles ||= {}
end

# An array of all circles this one overlaps
def overlapping_list
# Make sure we have a hash to save a set of overlappers
@overlapping_circles ||= {}
@overlapping_circles.select{ |circle,status|
status == true
}.map{ |circle,status|
circle
}
end
end

# Create/manage your populations
populations = []
20.times{
# Randomly add populations
x = rand 800 + 100
y = rand 800 + 100
radius = rand 100 + 10
populations << SVG::Circle.new( x, y, radius )
}

# Make sure the overlapping list is valid
populations.each_unique_pair{ |a,b|
a.overlaps?( b )
}

# Make the picture
svg = SVG.new('100%', '100%', '0 0 1000 1000')

# Your grid here
0.step( 1000, 20 ){ |i|
svg << SVG::Line.new( i, 0, i, 1000 )
svg << SVG::Line.new( 0, i, 1000, i )
}

# Make all circles have a common style
svg << g = SVG::Group.new{
self.style = SVG::Style.new(
:fill => '#ffe', :stroke => 'blue', :stroke_width => 1.5
)
}

# Need opacity per element, not on the group
low_opacity = SVG::Style.new( :opacity => 0.6 )

# Override style for circles that overlap
olap_style = SVG::Style.new( :fill=>'#ff9', :stroke=>'red', :opacity=>0.4 )

populations.each{ |circle|
if circle.overlapping_list.empty?
circle.style = low_opacity
else
circle.style = olap_style
end
g << circle
}

File.open( 'populations.svg', 'w' ){ |file|
file << svg.to_s
}

# view in your favorite SVG viewer, like FF 1.5
# for an example, see http://phrogz.net/svg/popul...
1 Answer

Phil Rhoades

9/9/2006 5:38:00 PM

0

Gavin,


On Sun, 2006-09-10 at 00:44 +0900, Gavin Kistner wrote:
> Here's a slightly better version that uses the overlapping status of a circle to change its color. (It doesn't do anything with pairs of circles, though that'd also be easy...you just have to know how you'd want to visualize it.)
>
> # http://downloads.sourceforge.jp/ruby-svg/2288/ruby-svg-1....
> require 'svg/svg'
>
> class Array
> def each_unique_pair
> self.each_with_index{ |a,i|
> self[(i+1)..-1].each{ |b| yield a,b }
> }
> end
> end
>
> class SVG::Circle
> # test (and save) result
> def overlaps?( other_circle )
> center_distance = Math.sqrt(
> ( cx - other_circle.cx ) ** 2 +
> ( cy - other_circle.cy ) ** 2
> )
>
> intersects = center_distance < ( r + other_circle.r )
>
> # Save the result on both circles
> other_circle.overlaps[ self ] = intersects
> self.overlaps[ other_circle ] = intersects
> end
>
> def overlaps
> # Make sure we have a hash to save a set of overlappers
> @overlapping_circles ||= {}
> end
>
> # An array of all circles this one overlaps
> def overlapping_list
> # Make sure we have a hash to save a set of overlappers
> @overlapping_circles ||= {}
> @overlapping_circles.select{ |circle,status|
> status == true
> }.map{ |circle,status|
> circle
> }
> end
> end
>
> # Create/manage your populations
> populations = []
> 20.times{
> # Randomly add populations
> x = rand 800 + 100
> y = rand 800 + 100
> radius = rand 100 + 10
> populations << SVG::Circle.new( x, y, radius )
> }
>
> # Make sure the overlapping list is valid
> populations.each_unique_pair{ |a,b|
> a.overlaps?( b )
> }
>
> # Make the picture
> svg = SVG.new('100%', '100%', '0 0 1000 1000')
>
> # Your grid here
> 0.step( 1000, 20 ){ |i|
> svg << SVG::Line.new( i, 0, i, 1000 )
> svg << SVG::Line.new( 0, i, 1000, i )
> }
>
> # Make all circles have a common style
> svg << g = SVG::Group.new{
> self.style = SVG::Style.new(
> :fill => '#ffe', :stroke => 'blue', :stroke_width => 1.5
> )
> }
>
> # Need opacity per element, not on the group
> low_opacity = SVG::Style.new( :opacity => 0.6 )
>
> # Override style for circles that overlap
> olap_style = SVG::Style.new( :fill=>'#ff9', :stroke=>'red', :opacity=>0.4 )
>
> populations.each{ |circle|
> if circle.overlapping_list.empty?
> circle.style = low_opacity
> else
> circle.style = olap_style
> end
> g << circle
> }
>
> File.open( 'populations.svg', 'w' ){ |file|
> file << svg.to_s
> }
>
> # view in your favorite SVG viewer, like FF 1.5
> # for an example, see http://phrogz.net/svg/popul...


Many thanks for that! I will have to go over this in detail to
understand what is happening but it looks nice! A couple of things:

1. There seems to be some doubt about the survival of SVG . .

2. Opera supports SVG natively! (which seems to go against the first
point)

Regards,

Phil.
--
Philip Rhoades

Pricom Pty Limited (ACN 003 252 275 ABN 91 003 252 275)
GPO Box 3411
Sydney NSW 2001
Australia
Mobile: +61:(0)411-185-652
Fax: +61:(0)2-8221-9599
E-mail: phil@pricom.com.au