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">
<xslutput method="html"
indent="yes"
encoding="iso-8859-1"/>
<!-- The area to calculate -->
<xslaram name="minX" select="-2"/>
<xslaram name="maxX" select="1.25"/>
<xslaram name="minY" select="-1.25"/>
<xslaram name="maxY" select="1.75"/>
<!-- Maximum number of iterations -->
<xslaram name="maxIterations" select="100"/>
<!-- Cell size -->
<xslaram name="cellSize" select="1"/>
<!-- Number of rows -->
<xslaram 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">
<xslaram 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">
<xslaram name="cellNumber" select="0"/>
<xslaram 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">
<xslaram name="iteration" select="0"/>
<xslaram name="cx"/>
<xslaram name="cy"/>
<xslaram name="a0" select="0"/>
<xslaram 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">
<xslaram 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>
<xsltherwise>
<xsl:call-template name="Dec2Hex">
<xsl:with-param name="dec" select="$div"/>
</xsl:call-template>
</xsltherwise>
</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">
<xslutput method="html"
indent="yes"
encoding="iso-8859-1"/>
<!-- The area to calculate -->
<xslaram name="minX" select="-2"/>
<xslaram name="maxX" select="1.25"/>
<xslaram name="minY" select="-1.25"/>
<xslaram name="maxY" select="1.75"/>
<!-- Maximum number of iterations -->
<xslaram name="maxIterations" select="100"/>
<!-- Cell size -->
<xslaram name="cellSize" select="1"/>
<!-- Number of rows -->
<xslaram 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">
<xslaram 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">
<xslaram name="cellNumber" select="0"/>
<xslaram 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">
<xslaram name="iteration" select="0"/>
<xslaram name="cx"/>
<xslaram name="cy"/>
<xslaram name="a0" select="0"/>
<xslaram 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">
<xslaram 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>
<xsltherwise>
<xsl:call-template name="Dec2Hex">
<xsl:with-param name="dec" select="$div"/>
</xsl:call-template>
</xsltherwise>
</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