-
-
Save astro/214727 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- not ready !!!1! | |
import Random | |
data Point | |
-- X, Y | |
= Float Float | |
deriving (Show, Eq) | |
data Values = None | |
-- Point1, Angle1, Angle2, Point2 | |
| Point Point Point Point | |
deriving (Show, Eq) | |
data Tree = Nil | |
| Trunk Values Tree Tree Tree | |
| Branch Values Tree Tree | |
deriving (Show, Eq) | |
data TreeType = NilType | |
| TrunkType | |
| BranchType | |
rollDice :: IO Int | |
rollDice = randomRIO (1,6) | |
rollType :: TreeType -> TreeType -> TreeType | |
rollType NilType expected = NilType | |
rollType BranchType expected | |
| r < 4 = BranchType | |
| r < 6 = expected | |
| otherwise = NilType | |
where r = rollDice | |
rollType TrunkType expected | |
| r < 3 = BranchType | |
| r < 6 = expected | |
| otherwise = TrunkType | |
where r = rollDice | |
--parent, start-size, end-size -> tree | |
grow :: TreeType -> Float -> Float -> Tree | |
grow NilType s e = Nil | |
grow TrunkType start end = Trunk None left middle right | |
where left = grow (rollType(TrunkType BranchType) start end) | |
middle = grow (rollType(TrunkType TrunkType) start end) | |
right = grow (rollType(TrunkType BranchType) start end) | |
grow BranchType start end = Branch None left right | |
where left = grow (rollType(BranchType NilType) start end) | |
right = grow (rollType(BranchType NilType) start end) | |
--start-size, end-size -> tree | |
makeTree :: Float -> Float -> Float -> Float -> Float -> Tree | |
makeTree x y size start end | |
| start < 0 = Nil | |
| end < 0 = Nil | |
| start <= end = Nil | |
| otherwise = Trunk None Nil grow(TrunkType start end) Nil | |
main = putStrLn $ makeTree 520 100 30 90 50 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import System.Random | |
import Control.Monad.State | |
type Point = (Double, Double) | |
pointPlus :: Point -> Point -> Point | |
pointPlus (x1, y1) (x2, y2) = (x1 + x2, y1 + y2) | |
polarToPoint :: Double -> Double -> Point | |
polarToPoint angle length | |
= let x = length * sin angle | |
y = length * (- cos angle) | |
in (x, y) | |
data GrowState = GrowState { stRandoms :: [Double] -- ^ (0..1) | |
} | |
type Grow a = State GrowState a | |
genFromRange :: Double -> Double -> Grow Double | |
genFromRange min max | |
= do st <- get | |
let r:randoms = stRandoms st | |
put st { stRandoms = randoms } | |
return $ r * (max - min) + min | |
runGrow :: Grow a -> IO a | |
runGrow f = do gen <- getStdGen | |
let st = GrowState { stRandoms = randomRs (0, 1) gen } | |
return $ evalState f st | |
data Branch = Branch { branchBegin :: Point, | |
branchEnd :: Point, | |
branchAnchor1 :: Point, | |
branchAnchor2 :: Point, | |
branchLength :: Double, | |
branchSize :: Double, | |
branchAngle :: Double } | |
makeBranch :: Branch -- ^parent | |
-> Double -- ^length | |
-> Double -- ^angle | |
-> Branch | |
makeBranch parent length angle | |
= Branch { branchBegin = point1, | |
branchEnd = point2, | |
branchAnchor1 = anchor1, | |
branchAnchor2 = anchor2, | |
branchLength = length', | |
branchSize = branchSize parent - length' / 50, | |
branchAngle = angle } | |
where length' | length <= 80 = length | |
| otherwise = length * 0.9 | |
point1 = branchEnd parent | |
point2 = point1 `pointPlus` (polarToPoint angle length') | |
anchor1 = point1 `pointPlus` (polarToPoint (-branchAngle parent) (length' * 0.6)) | |
anchor2 = point2 `pointPlus` (polarToPoint (-angle) (-length' * 0.4)) | |
branches :: Branch -> Grow [Branch] | |
branches b | branchLength b <= 50 = return [] | |
| otherwise = do angle1 <- (branchAngle b +) `liftM` | |
genFromRange (-40 * pi / 180) (-20 * pi / 180) | |
angle2 <- (branchAngle b +) `liftM` | |
genFromRange (-20 * pi / 180) (20 * pi / 180) | |
angle3 <- (branchAngle b +) `liftM` | |
genFromRange (20 * pi / 180) (40 * pi / 180) | |
length' <- (branchLength b -) `liftM` | |
genFromRange 5 15 | |
let left = makeBranch b length' angle1 | |
middle = makeBranch b length' angle2 | |
right = makeBranch b length' angle3 | |
lefts <- branches left | |
rights <- branches right | |
case () of | |
_ | branchLength b <= 80 -> | |
return $ [left, right] ++ lefts ++ rights | |
_ -> | |
do middles <- branches middle | |
return $ [left, middle, right] ++ | |
lefts ++ | |
middles ++ | |
rights | |
makeTrunk origin size start | |
= Branch origin stem origin stem start size 0 | |
where stem = origin `pointPlus` (polarToPoint 0 start) | |
{- | |
branch :: Value -> Double -> Double -> [Value] | |
branch parent stop angle | |
= leftBranches ++ rightBranches | |
where left = makeValue (angle - 20 * pi / 180) | |
leftBranches = [left] ++ (branch left stop | |
-} | |
--class Growable d where | |
-- drawableNodes :: d -> [Node] | |
branchesToSVG bs = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" ++ | |
"<svg " ++ | |
"xmlns:svg='http://www.w3.org/2000/svg' " ++ | |
"xmlns='http://www.w3.org/2000/svg' " ++ | |
"version='1.0' " ++ | |
"width='210mm' " ++ | |
"height='297mm' " ++ | |
"id='svg2'> " ++ | |
"<defs id='defs4' /> " ++ | |
"<g>" ++ | |
(concat $ map branchToSVGpath bs) ++ | |
"</g>" ++ | |
"</svg>" | |
where branchToSVGpath b | |
= let size = branchSize b | |
color | branchLength b <= 80 = "green" | |
| otherwise = "brown" | |
style = "fill:none;fill-rule:evenodd;stroke:" ++ color ++ | |
";stroke-width:" ++ | |
(show size) ++ "px;" ++ | |
"stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | |
in "<path d='M " ++ (s $ branchBegin b) ++ | |
" C " ++ (s $ branchAnchor1 b) ++ | |
" " ++ (s $ branchAnchor2 b) ++ | |
" " ++ (s $ branchEnd b) ++ | |
"' style='" ++ style ++ "'/>" | |
s (x, y) = (show $ truncate x) ++ "," ++ (show $ truncate y) | |
main = do let trunk = makeTrunk (520, 1000) 30 150 | |
branches' <- ([trunk] ++) `liftM` (runGrow $ branches trunk) | |
putStrLn $ branchesToSVG branches' |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from random import random, choice | |
from math import sin, cos, sqrt, pi, radians as rad | |
#data: | |
class Point: | |
def __init__(self, x, y): | |
self.x = x | |
self.y = y | |
class Tree: | |
color = "000000" | |
def __init__(self, value): | |
self.value = value | |
def __repr__(self): | |
return self.__class__.__name__+hex(id(self))[2:] | |
class Branch(Tree): | |
color = "2D5016" | |
def __init__(self, value, left=None, right=None): | |
super().__init__(value) | |
self.left = left | |
self.right = right | |
def __str__(self): | |
return "<{2} left:{0} right:{1}>".format(self.left,self.right,repr(self)) | |
class Trunk(Branch): | |
color = "552200" | |
def __init__(self, value, left=None, middle=None, right=None): | |
super().__init__(value, left, right) | |
self.middle = middle | |
def __str__(self): | |
return "<{3} left:{0} middle:{1} right:{2}>".format(self.left,self.middle,self.right,repr(self)) | |
class Value: | |
def __init__(self, parent, length, angle, size=None): | |
self.angle = angle | |
if parent: | |
pvalue = parent.value | |
if pvalue: | |
if size is None: size = pvalue.size - length/50 | |
self.angle += pvalue.angle | |
self.point1 = pvalue.point2 | |
self.point2 = Point(pvalue.point2.x+length*cos(rad(self.angle)), | |
pvalue.point2.y+length*sin(rad(self.angle))) | |
if size is None: size = 1 | |
if size < 0: size = 0.2 | |
self.size = size | |
#radom: | |
def rollType(previous, expected): | |
if type(previous) is not type: previous = type(previous) | |
types = [None, Branch, Branch, expected] | |
if previous == Branch: types += [Branch, None] | |
elif previous == Trunk: types += [Branch, Trunk, expected, Trunk] | |
return choice(types) | |
def rollLength(length): | |
return length - random()*10 - 1 | |
def rollAngle(middle,range): | |
return middle - random() * choice([range, -range]) | |
#code | |
def grow(parent, middle, length, stop): | |
if length < stop: return None | |
klass = rollType(parent, Trunk if isinstance(parent, Trunk) else Branch) | |
if not klass: return None | |
l = length*2 if klass == Trunk else length | |
result = klass(Value(parent, l,rollAngle(middle, 20))) | |
result.left = grow(result,-40, rollLength(length), stop) | |
if isinstance(result, Trunk): | |
result.middle = grow(result,0, rollLength(length), stop) | |
result.right = grow(result,40, rollLength(length), stop) | |
x = parent.value.point2.x - parent.value.point1.x | |
y = parent.value.point2.y - parent.value.point1.y | |
r = sqrt(x*x+y*y)+0.000000000001 | |
v = length*0.9; x *= v/r; y *= v/r | |
x += result.value.point1.x | |
y += result.value.point1.y | |
result.value.angle1 = Point(x,y) | |
x, y = 0, 0 | |
if isinstance(result, Branch): | |
if result.left: | |
x += result.left.value.point1.x - result.left.value.point2.x | |
y += result.left.value.point1.y - result.left.value.point2.y | |
if result.right: | |
x += result.right.value.point1.x - result.right.value.point2.x | |
y += result.right.value.point1.y - result.right.value.point2.y | |
if isinstance(result, Trunk): | |
if result.middle: | |
x += result.middle.value.point1.x - result.middle.value.point2.x | |
y += result.middle.value.point1.y - result.middle.value.point2.y | |
r = sqrt(x*x+y*y)+0.000000000001 | |
v = length*0.8; x *= v/r; y *= v/r | |
x += result.value.point2.x | |
y += result.value.point2.y | |
result.value.angle2 = Point(x,y) | |
return result | |
def makeTree(x, y, size, start, stop): | |
result = Trunk(Value(None, start,-90,size)) | |
result.value.point1 = result.value.angle1 = Point(x,y) | |
result.value.point2 = result.value.angle2 = Point(x,y-start) | |
result.middle = grow(result,0, start, stop) | |
return result | |
#output | |
def get_list(node): | |
result = [] | |
if isinstance(node, Tree): | |
result += [(repr(node),node.value.point1.x,node.value.point1.y, | |
node.value.angle1.x,node.value.angle1.y, | |
node.value.angle2.x,node.value.angle2.y, | |
node.value.point2.x,node.value.point2.y,node.value.size,node.color)] | |
if isinstance(node, Branch): | |
result += get_list(node.left) + get_list(node.right) | |
if isinstance(node, Trunk): | |
result += get_list(node.middle) | |
return result | |
header = """<?xml version="1.0" encoding="UTF-8" standalone="no"?> | |
<!-- Created with Inkscape (http://www.inkscape.org/) --> | |
<svg | |
xmlns:svg="http://www.w3.org/2000/svg" | |
xmlns="http://www.w3.org/2000/svg" | |
version="1.0" | |
width="210mm" | |
height="297mm" | |
id="svg2"> | |
<defs id="defs4" /> | |
""" | |
def print_it(tree): | |
l = get_list(tree) | |
svg = '<g id="{0}">'.format(repr(Tree(None))) | |
style = 'style="fill:none;fill-rule:evenodd;stroke:#{1};stroke-width:{0}px;'+\ | |
'stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"' | |
for node in l: | |
s = style.format(*node[9:]) | |
svg += '<path id="{1}" d="M {2:n},{3:n} C {4:n},{5:n} {6:n},{7:n} {8:n},{9:n}" {0} />'.format(s,*node) | |
svg += "</g>\n" | |
print(header+svg+"</svg>") | |
def main(): | |
tree = makeTree(520,1000,30,90,50) | |
print_it( tree ) | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment