M
Magnus Henriksson
Hi all,
While getting ready to get rid of an old computer of mine, I came across
this transform that I wrote a few years ago (around 2002 I think). I did
it just to prove that it could be done, so the more mathematically
inclined will no doubt find better ways to do this.
I thought some of you might get a kick out of it.
Do this:
1) Run it trough your favorite XSLT 1.0 processor, output to file. I
recommend a really fast processor, such as SAXON. The transform does not
depend on any input source, so you can use whatever you have lying
around. Wait for it...
2) Open the result in a browser. Wait for it...
Here is the transform:
-- begin mandel.xsl --
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl
utput method="html"
indent="yes"
encoding="iso-8859-1"/>
<!-- The area to calculate -->
<xsl
aram name="minX" select="-2"/>
<xsl
aram name="maxX" select="1.25"/>
<xsl
aram name="minY" select="-1.25"/>
<xsl
aram name="maxY" select="1.75"/>
<!-- Maximum number of iterations -->
<xsl
aram name="maxIterations" select="100"/>
<!-- Cell size -->
<xsl
aram name="cellSize" select="1"/>
<!-- Number of rows -->
<xsl
aram name="rowsMax" select="300"/>
<xsl:variable name="dy" select="($maxY - $minY) div $rowsMax"/>
<xsl:variable name="cellsMax" select="($maxX - $minX) div $dy"/>
<xsl:variable name="dx" select="($maxX - $minX) div $cellsMax"/>
<xsl:template match="/">
<html>
<head>
<title>XSLT Mandelbrot Set</title>
</head>
<body>
<table cellspacing="0"
cellpadding="0"
border="0"
bgcolor="black">
<xsl:call-template name="Rows"/>
</table>
</body>
</html>
</xsl:template>
<xsl:template name="Rows">
<xsl
aram name="rowNumber" select="0"/>
<xsl:if test="$rowNumber < $rowsMax">
<xsl:message>
<xsl:value-of select="concat('Row ', $rowNumber + 1, ' of ',
$rowsMax)"/>
</xsl:message>
<tr>
<xsl:call-template name="Cells">
<xsl:with-param name="rowNumber" select="$rowNumber"/>
</xsl:call-template>
</tr>
<xsl:call-template name="Rows">
<xsl:with-param name="rowNumber" select="$rowNumber + 1"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
<xsl:template name="Cells">
<xsl
aram name="cellNumber" select="0"/>
<xsl
aram name="rowNumber"/>
<xsl:if test="$cellNumber < $cellsMax">
<td width="{$cellSize}" height="{$cellSize}">
<xsl:call-template name="CellColor">
<xsl:with-param name="cx" select="$minX + ($cellNumber * $dx)"/>
<xsl:with-param name="cy" select="$minY + ($rowNumber * $dy)"/>
</xsl:call-template>
</td>
<xsl:call-template name="Cells">
<xsl:with-param name="cellNumber" select="$cellNumber + 1"/>
<xsl:with-param name="rowNumber" select="$rowNumber"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
<xsl:template name="CellColor">
<xsl
aram name="iteration" select="0"/>
<xsl
aram name="cx"/>
<xsl
aram name="cy"/>
<xsl
aram name="a0" select="0"/>
<xsl
aram name="b0" select="0"/>
<xsl:variable name="a1" select="($a0 * $a0) - ($b0 * $b0) + $cx"/>
<xsl:variable name="b1" select="2 * ($a0 * $b0) + $cy"/>
<xsl:variable name="zLength" select="($a1 * $a1) + ($b1 * $b1)"/>
<xsl:if test="$zLength > 4">
<xsl:variable name="color">
<xsl:call-template name="Dec2Hex">
<xsl:with-param name="dec" select="round((16777215 div
$maxIterations) * $iteration)"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="padding"
select="6 - string-length($color)"/>
<xsl:variable name="paddedColor"
select="concat(substring('000000',1,$padding), $color)"/>
<xsl:attribute name="bgcolor">
<xsl:value-of select="concat('#',$paddedColor)"/>
</xsl:attribute>
</xsl:if>
<xsl:if test="$iteration < $maxIterations and $zLength <= 4">
<xsl:call-template name="CellColor">
<xsl:with-param name="iteration" select="$iteration + 1"/>
<xsl:with-param name="cx" select="$cx"/>
<xsl:with-param name="cy" select="$cy"/>
<xsl:with-param name="a0" select="$a1"/>
<xsl:with-param name="b0" select="$b1"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
<xsl:template name="Dec2Hex">
<xsl
aram name="dec" select="0"/>
<xsl:variable name="div" select="floor($dec div 16)"/>
<xsl:variable name="rem" select="$dec - ($div * 16)"/>
<xsl:choose>
<xsl:when test="$dec = 0">0</xsl:when>
<xsl:when test="$dec = 1">1</xsl:when>
<xsl:when test="$dec = 2">2</xsl:when>
<xsl:when test="$dec = 3">3</xsl:when>
<xsl:when test="$dec = 4">4</xsl:when>
<xsl:when test="$dec = 5">5</xsl:when>
<xsl:when test="$dec = 6">6</xsl:when>
<xsl:when test="$dec = 7">7</xsl:when>
<xsl:when test="$dec = 8">8</xsl:when>
<xsl:when test="$dec = 9">9</xsl:when>
<xsl:when test="$dec = 10">A</xsl:when>
<xsl:when test="$dec = 11">B</xsl:when>
<xsl:when test="$dec = 12">C</xsl:when>
<xsl:when test="$dec = 13">D</xsl:when>
<xsl:when test="$dec = 14">E</xsl:when>
<xsl:when test="$dec = 15">F</xsl:when>
<xsl
therwise>
<xsl:call-template name="Dec2Hex">
<xsl:with-param name="dec" select="$div"/>
</xsl:call-template>
</xsl
therwise>
</xsl:choose>
<xsl:if test="$div">
<xsl:call-template name="Dec2Hex">
<xsl:with-param name="dec" select="$rem"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
-- end mandel.xsl --
Other mildly interesting values of the parameters are:
minX = 0.2
maxX = 0.4
minY = 0.5
maxY = 0.7
and
minX = 0.3
maxX = 0.4
minY = 0.5
maxY = 0.6
and
minX = 0.32
maxX = 0.35
minY = 0.52
maxY = 0.55
The smaller the area, the longer it will take. For really small areas it
seems like the processor gets stuck.
// Magnus
While getting ready to get rid of an old computer of mine, I came across
this transform that I wrote a few years ago (around 2002 I think). I did
it just to prove that it could be done, so the more mathematically
inclined will no doubt find better ways to do this.
I thought some of you might get a kick out of it.
Do this:
1) Run it trough your favorite XSLT 1.0 processor, output to file. I
recommend a really fast processor, such as SAXON. The transform does not
depend on any input source, so you can use whatever you have lying
around. Wait for it...
2) Open the result in a browser. Wait for it...
Here is the transform:
-- begin mandel.xsl --
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl
indent="yes"
encoding="iso-8859-1"/>
<!-- The area to calculate -->
<xsl
<xsl
<xsl
<xsl
<!-- Maximum number of iterations -->
<xsl
<!-- Cell size -->
<xsl
<!-- Number of rows -->
<xsl
<xsl:variable name="dy" select="($maxY - $minY) div $rowsMax"/>
<xsl:variable name="cellsMax" select="($maxX - $minX) div $dy"/>
<xsl:variable name="dx" select="($maxX - $minX) div $cellsMax"/>
<xsl:template match="/">
<html>
<head>
<title>XSLT Mandelbrot Set</title>
</head>
<body>
<table cellspacing="0"
cellpadding="0"
border="0"
bgcolor="black">
<xsl:call-template name="Rows"/>
</table>
</body>
</html>
</xsl:template>
<xsl:template name="Rows">
<xsl
<xsl:if test="$rowNumber < $rowsMax">
<xsl:message>
<xsl:value-of select="concat('Row ', $rowNumber + 1, ' of ',
$rowsMax)"/>
</xsl:message>
<tr>
<xsl:call-template name="Cells">
<xsl:with-param name="rowNumber" select="$rowNumber"/>
</xsl:call-template>
</tr>
<xsl:call-template name="Rows">
<xsl:with-param name="rowNumber" select="$rowNumber + 1"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
<xsl:template name="Cells">
<xsl
<xsl
<xsl:if test="$cellNumber < $cellsMax">
<td width="{$cellSize}" height="{$cellSize}">
<xsl:call-template name="CellColor">
<xsl:with-param name="cx" select="$minX + ($cellNumber * $dx)"/>
<xsl:with-param name="cy" select="$minY + ($rowNumber * $dy)"/>
</xsl:call-template>
</td>
<xsl:call-template name="Cells">
<xsl:with-param name="cellNumber" select="$cellNumber + 1"/>
<xsl:with-param name="rowNumber" select="$rowNumber"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
<xsl:template name="CellColor">
<xsl
<xsl
<xsl
<xsl
<xsl
<xsl:variable name="a1" select="($a0 * $a0) - ($b0 * $b0) + $cx"/>
<xsl:variable name="b1" select="2 * ($a0 * $b0) + $cy"/>
<xsl:variable name="zLength" select="($a1 * $a1) + ($b1 * $b1)"/>
<xsl:if test="$zLength > 4">
<xsl:variable name="color">
<xsl:call-template name="Dec2Hex">
<xsl:with-param name="dec" select="round((16777215 div
$maxIterations) * $iteration)"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="padding"
select="6 - string-length($color)"/>
<xsl:variable name="paddedColor"
select="concat(substring('000000',1,$padding), $color)"/>
<xsl:attribute name="bgcolor">
<xsl:value-of select="concat('#',$paddedColor)"/>
</xsl:attribute>
</xsl:if>
<xsl:if test="$iteration < $maxIterations and $zLength <= 4">
<xsl:call-template name="CellColor">
<xsl:with-param name="iteration" select="$iteration + 1"/>
<xsl:with-param name="cx" select="$cx"/>
<xsl:with-param name="cy" select="$cy"/>
<xsl:with-param name="a0" select="$a1"/>
<xsl:with-param name="b0" select="$b1"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
<xsl:template name="Dec2Hex">
<xsl
<xsl:variable name="div" select="floor($dec div 16)"/>
<xsl:variable name="rem" select="$dec - ($div * 16)"/>
<xsl:choose>
<xsl:when test="$dec = 0">0</xsl:when>
<xsl:when test="$dec = 1">1</xsl:when>
<xsl:when test="$dec = 2">2</xsl:when>
<xsl:when test="$dec = 3">3</xsl:when>
<xsl:when test="$dec = 4">4</xsl:when>
<xsl:when test="$dec = 5">5</xsl:when>
<xsl:when test="$dec = 6">6</xsl:when>
<xsl:when test="$dec = 7">7</xsl:when>
<xsl:when test="$dec = 8">8</xsl:when>
<xsl:when test="$dec = 9">9</xsl:when>
<xsl:when test="$dec = 10">A</xsl:when>
<xsl:when test="$dec = 11">B</xsl:when>
<xsl:when test="$dec = 12">C</xsl:when>
<xsl:when test="$dec = 13">D</xsl:when>
<xsl:when test="$dec = 14">E</xsl:when>
<xsl:when test="$dec = 15">F</xsl:when>
<xsl
<xsl:call-template name="Dec2Hex">
<xsl:with-param name="dec" select="$div"/>
</xsl:call-template>
</xsl
</xsl:choose>
<xsl:if test="$div">
<xsl:call-template name="Dec2Hex">
<xsl:with-param name="dec" select="$rem"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
-- end mandel.xsl --
Other mildly interesting values of the parameters are:
minX = 0.2
maxX = 0.4
minY = 0.5
maxY = 0.7
and
minX = 0.3
maxX = 0.4
minY = 0.5
maxY = 0.6
and
minX = 0.32
maxX = 0.35
minY = 0.52
maxY = 0.55
The smaller the area, the longer it will take. For really small areas it
seems like the processor gets stuck.
// Magnus