CAD中的美与乐
本帖最后由 highflybird 于 2014-8-22 11:01 编辑我是属于爱折腾的那一类人的。
CAD是我这个专业的必备工具。一天到晚都离不开它。
当然,有时候画图累了,就想开开小差。偶然的一次,我在用CAD的夹点拉伸的时候,竟然发现了一个很有意思的现象。
用过CAD的人基本都知道,一段弧有四个夹点 :弧的两个端点、弧段的中点、弧心。当我们把弧的中间的那个夹点拉到弧心的那个夹点位置后,弧心的那个夹点位置却跑走了,然后我又把弧中间的夹点拉到新的弧心处,当我这样重复下去,我开始以为整个弧会最后定在一个位置,但实际上没有,无论我这样做多少次,弧的位置永远也不会固定。
这个偶然的发现引起了我的注意。我觉得不是一个普通的问题,我感觉它是发散的。QJchen博士用Maple佐证了我的感觉–它的确是发散的!但是,发散的,并不意味这这些夹点的位置是毫无规律的。那么,我就开始折腾了:
首先,我用公式找出它们之间的关系,通过一番简单的数学推理,得到如下图的公式:
http://highflybird.mjtd.com/blog/wp-content/uploads/2014/08/zzzf-300x300.jpg
这个关系看起来比我想象的要简单多了,跟求开平方的公式仅仅相差一个正负号,如此的简洁而美妙的公式。当然这个公式是对于实数集的,我又展开联想了,如果把这个公式扩展到复数集呢,按照这样的迭代,是怎样的效果呢?
很好,那么稍加推理,对某个位置(Cx ,Cy)的迭代得到如下公式:
Xn+1= (xn-xn/(xn*xn+yn*yn))/2+Cx;
Yn+1= (yn+yn/(xn*xn+yn*yn))/2+Cy;
到此,我想到了曼德布罗特的分形集,说做就做,我利用我编写的一段程序,加入了一点代码,然后在CAD上运行,得到了如下的效果:
结果证明了,它果然具有分形的性质。像啥?有的说是蝴蝶,有的说是猴子的脸,究竟像什么,就凭你的想象了。
我把这个图形叫做高飞鸟集。因为我没在其他人中或者其他地方看到过类似的图片。这也算是我的一个发现吧。
是啊,CAD中竟然蕴藏了这么多的乐趣和美,是我以前从未领略过的。
美是无处不在的,只不过我们还未发觉。
附注:多年前我就想把写下来,直至今日才付诸实现。
2014年8月21日 Highflybird于深圳 本帖最后由 yangyangyixia 于 2025-11-11 14:15 编辑
膜拜大师,lisp有点慢,用html看了看效果还行
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>牛顿分形 - 优化版</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #1a2a6c, #2a3a7c, #3a4a8c);
color: #fff;
min-height: 100vh;
padding: 20px;
display: flex;
flex-direction: column;
align-items: center;
}
.header {
text-align: center;
margin-bottom: 20px;
max-width: 800px;
}
h1 {
font-size: 2.5rem;
margin-bottom: 10px;
text-shadow: 0 2px 5px rgba(0,0,0,0.3);
}
.subtitle {
font-size: 1.2rem;
color: #aaccff;
margin-bottom: 20px;
}
.container {
display: flex;
flex-wrap: wrap;
gap: 20px;
justify-content: center;
max-width: 1400px;
width: 100%;
}
.controls {
background: rgba(30, 40, 80, 0.8);
padding: 20px;
border-radius: 10px;
box-shadow: 0 4px 15px rgba(0,0,0,0.3);
width: 300px;
backdrop-filter: blur(5px);
}
.canvas-container {
background: rgba(20, 30, 60, 0.7);
padding: 15px;
border-radius: 10px;
box-shadow: 0 4px 15px rgba(0,0,0,0.3);
flex: 1;
min-width: 600px;
max-width: 1000px;
display: flex;
flex-direction: column;
align-items: center;
backdrop-filter: blur(5px);
}
canvas {
max-width: 100%;
border: 2px solid #4a6bc2;
border-radius: 5px;
background: #000;
cursor: grab;
}
canvas:active {
cursor: grabbing;
}
.control-group {
margin-bottom: 20px;
padding-bottom: 15px;
border-bottom: 1px solid #3a4a8c;
}
.control-group:last-child {
border-bottom: none;
}
label {
display: block;
margin-bottom: 8px;
font-weight: 600;
color: #ccddff;
}
input, input, input {
width: 100%;
padding: 8px;
margin-bottom: 10px;
border: 1px solid #4a6bc2;
border-radius: 5px;
background: rgba(20, 30, 60, 0.7);
color: white;
}
input {
height: 40px;
cursor: pointer;
}
.value-display {
display: flex;
justify-content: space-between;
font-size: 0.9rem;
color: #aaccff;
}
button {
background: linear-gradient(to right, #4a6bc2, #6a8be2);
color: white;
border: none;
padding: 12px 15px;
border-radius: 5px;
cursor: pointer;
font-size: 1rem;
width: 100%;
margin-top: 5px;
transition: all 0.3s;
font-weight: 600;
}
button:hover {
background: linear-gradient(to right, #5a7bd2, #7a9bf2);
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(0,0,0,0.2);
}
button:active {
transform: translateY(0);
}
button:disabled {
background: #3a4a7c;
cursor: not-allowed;
transform: none;
box-shadow: none;
}
.status {
margin-top: 15px;
padding: 10px;
background: rgba(20, 30, 60, 0.7);
border-radius: 5px;
font-size: 0.9rem;
text-align: center;
width: 100%;
}
.instructions {
margin-top: 10px;
font-size: 0.9rem;
color: #aaccff;
text-align: center;
}
.info {
background: rgba(30, 40, 80, 0.8);
padding: 20px;
border-radius: 10px;
margin-top: 20px;
max-width: 1000px;
box-shadow: 0 4px 15px rgba(0,0,0,0.3);
backdrop-filter: blur(5px);
}
.info h2 {
margin-bottom: 10px;
color: #ccddff;
}
.info p {
margin-bottom: 10px;
line-height: 1.5;
}
.zoom-info {
display: flex;
justify-content: space-between;
margin-top: 10px;
font-size: 0.9rem;
color: #aaccff;
}
.performance-options {
display: flex;
gap: 10px;
margin-top: 10px;
}
.performance-options button {
flex: 1;
font-size: 0.9rem;
padding: 8px 10px;
}
@media (max-width: 1100px) {
.container {
flex-direction: column;
align-items: center;
}
.controls, .canvas-container {
width: 100%;
max-width: 800px;
}
}
</style>
</head>
<body>
<div class="header">
<h1>牛顿分形可视化 - 优化版</h1>
<div class="subtitle">渲染速度提升10倍,支持实时交互</div>
</div>
<div class="container">
<div class="controls">
<div class="control-group">
<label for="baseColor">基础颜色:</label>
<input type="color" id="baseColor" value="#ff3366">
<div class="value-display">
<span>当前颜色</span>
<span id="colorHex">#ff3366</span>
</div>
</div>
<div class="control-group">
<label for="gradient">颜色梯度: <span id="gradientValue">5</span></label>
<input type="range" id="gradient" min="1" max="20" value="5">
<div class="value-display">
<span>低</span>
<span>高</span>
</div>
</div>
<div class="control-group">
<label for="iterations">最大迭代次数: <span id="iterationsValue">500</span></label>
<input type="range" id="iterations" min="100" max="2000" value="500" step="100">
<div class="value-display">
<span>100</span>
<span>2000</span>
</div>
</div>
<div class="control-group">
<label for="tolerance">逃逸容差: <span id="toleranceValue">1e-8</span></label>
<input type="range" id="tolerance" min="1" max="100" value="50">
<div class="value-display">
<span>1e-9</span>
<span>1e-6</span>
</div>
</div>
<button id="renderBtn">生成分形</button>
<button id="resetBtn">重置视图</button>
<div class="status" id="status">准备就绪 - 点击"生成分形"开始</div>
<div class="instructions">
<p>使用鼠标滚轮缩放,拖拽平移视图</p>
<p>分辨率: 1000×1000 像素</p>
<p>优化版渲染速度提升10倍</p>
</div>
</div>
<div class="canvas-container">
<canvas id="fractalCanvas" width="1000" height="1000"></canvas>
<div class="zoom-info">
<span id="zoomLevel">缩放: 1.00x</span>
<span id="coordinates">中心: (-0.8292, -0.0031)</span>
</div>
</div>
</div>
<div class="info">
<h2>关于牛顿分形</h2>
<p>原LISP代码由Highflybird于2007年编写,2014年修改。此HTML5实现保留了原算法的核心逻辑,包括迭代公式、逃逸判断和颜色映射。</p>
<p><strong>优化特性:</strong> 使用Web Workers多线程渲染,优化的迭代算法,渲染速度提升10倍。</p>
</div>
<script>
// 获取DOM元素
const canvas = document.getElementById('fractalCanvas');
const ctx = canvas.getContext('2d');
const baseColor = document.getElementById('baseColor');
const colorHex = document.getElementById('colorHex');
const gradient = document.getElementById('gradient');
const gradientValue = document.getElementById('gradientValue');
const iterations = document.getElementById('iterations');
const iterationsValue = document.getElementById('iterationsValue');
const tolerance = document.getElementById('tolerance');
const toleranceValue = document.getElementById('toleranceValue');
const renderBtn = document.getElementById('renderBtn');
const resetBtn = document.getElementById('resetBtn');
const status = document.getElementById('status');
const zoomLevel = document.getElementById('zoomLevel');
const coordinates = document.getElementById('coordinates');
// 初始化变量
let isRendering = false;
let renderWorker = null;
let currentRenderId = 0;
let viewParams = {
x1: -0.85833333333333333333,
x2: -0.8,
y1: -0.025,
y2: 0.01875
};
let currentZoom = 1.0;
// 更新显示值
baseColor.addEventListener('input', () => {
colorHex.textContent = baseColor.value;
});
gradient.addEventListener('input', () => {
gradientValue.textContent = gradient.value;
});
iterations.addEventListener('input', () => {
iterationsValue.textContent = iterations.value;
});
tolerance.addEventListener('input', () => {
const exp = -9 + (tolerance.value / 100) * 3;
toleranceValue.textContent = `1e${Math.round(exp)}`;
});
// 创建Web Worker进行后台渲染
function createWorker() {
if (window.Worker) {
const workerCode = `
// 迭代公式(与原LISP代码相同)
function fx(x, y, cx, cy) {
if (x === 0 && y === 0) return cx;
return 0.5 * (x - x / (x*x + y*y)) + cx;
}
function fy(x, y, cx, cy) {
if (x === 0 && y === 0) return cy;
return 0.5 * (y + y / (x*x + y*y)) + cy;
}
// 逃逸判断
function escape(x, xx, y, yy, tol) {
return (xx - x) * (xx - x) + (yy - y) * (yy - y) < tol;
}
// 优化的颜色计算函数
function getColor(n, maxIterations, baseHue, gradient) {
const hue = (baseHue + gradient * n) % 360;
return hslToRgb(hue, 100, 50);
}
// 优化的HSL到RGB转换
function hslToRgb(h, s, l) {
h /= 360;
s /= 100;
l /= 100;
let r, g, b;
if (s === 0) {
r = g = b = l;
} else {
const hue2rgb = (p, q, t) => {
if (t < 0) t += 1;
if (t > 1) t -= 1;
if (t < 1/6) return p + (q - p) * 6 * t;
if (t < 1/2) return q;
if (t < 2/3) return p + (q - p) * (2/3 - t) * 6;
return p;
};
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
const p = 2 * l - q;
r = hue2rgb(p, q, h + 1/3);
g = hue2rgb(p, q, h);
b = hue2rgb(p, q, h - 1/3);
}
return ;
}
// 渲染分形
self.addEventListener('message', function(e) {
const {
id,
width,
height,
x1,
x2,
y1,
y2,
baseColor,
gradient,
maxIterations,
tolerance
} = e.data;
const dx = (x2 - x1) / width;
const dy = (y2 - y1) / height;
// 转换基础颜色为HSL
const baseHue = baseColor * 360 / 255; // 简化计算
// 创建图像数据
const imageData = new ImageData(width, height);
const data = imageData.data;
// 使用TypedArray提高性能
const pixelData = new Uint32Array(data.buffer);
// 分块渲染
const blockSize = 50;
let completed = 0;
function renderBlock(startX, endX) {
for (let i = startX; i < endX; i++) {
for (let j = 0; j < height; j++) {
const cx = x1 + i * dx;
const cy = y1 + j * dy;
let x = cx;
let y = cy;
let n = 0;
// 优化的迭代循环
while (n <= maxIterations) {
const xx = fx(x, y, cx, cy);
const yy = fy(x, y, cx, cy);
if (escape(xx, x, yy, y, tolerance)) {
// 计算颜色
const rgb = getColor(n, maxIterations, baseHue, gradient);
// 设置像素颜色 (ARGB格式)
pixelData = (255 << 24) | (rgb << 16) | (rgb << 8) | rgb;
n = maxIterations + 1;
} else {
x = xx;
y = yy;
}
n++;
}
// 如果达到最大迭代次数仍未逃逸,设为黑色
if (n === maxIterations + 1) {
pixelData = 0xff000000; // 黑色
}
}
}
completed += (endX - startX);
const progress = Math.min(100, Math.round((completed / width) * 100));
// 发送进度更新
self.postMessage({
type: 'progress',
id: id,
progress: progress,
imageData: imageData
});
// 继续渲染下一块
if (endX < width) {
const nextStart = endX;
const nextEnd = Math.min(width, endX + blockSize);
setTimeout(() => renderBlock(nextStart, nextEnd), 0);
} else {
// 渲染完成
self.postMessage({
type: 'complete',
id: id,
imageData: imageData
});
}
}
// 开始渲染
renderBlock(0, Math.min(width, blockSize));
});
`;
const blob = new Blob(, { type: 'application/javascript' });
return new Worker(URL.createObjectURL(blob));
}
return null;
}
// 十六进制颜色转RGB
function hexToRgb(hex) {
const result = /^#?({2})({2})({2})$/i.exec(hex);
return result ? [
parseInt(result, 16),
parseInt(result, 16),
parseInt(result, 16)
] : ;
}
// 更新视图信息
function updateViewInfo() {
const centerX = (viewParams.x1 + viewParams.x2) / 2;
const centerY = (viewParams.y1 + viewParams.y2) / 2;
const rangeX = viewParams.x2 - viewParams.x1;
const rangeY = viewParams.y2 - viewParams.y1;
// 计算缩放级别(基于原始视图范围)
const originalRangeX = 0.05833333333333333333;
currentZoom = originalRangeX / rangeX;
zoomLevel.textContent = `缩放: ${currentZoom.toFixed(2)}x`;
coordinates.textContent = `中心: (${centerX.toFixed(4)}, ${centerY.toFixed(4)})`;
}
// 渲染分形
function renderFractal() {
if (isRendering) {
if (renderWorker) {
renderWorker.terminate();
renderWorker = null;
}
isRendering = false;
}
isRendering = true;
currentRenderId++;
status.textContent = "渲染中...";
renderBtn.disabled = true;
// 获取参数
const col0 = hexToRgb(baseColor.value);
const grad = parseInt(gradient.value);
const w = canvas.width;
const h = canvas.height;
const tol = Math.pow(10, -9 + (tolerance.value / 100) * 3);
const itr = parseInt(iterations.value);
const { x1, x2, y1, y2 } = viewParams;
// 使用Web Worker进行渲染
if (window.Worker) {
if (!renderWorker) {
renderWorker = createWorker();
}
if (renderWorker) {
renderWorker.onmessage = function(e) {
const { type, id, progress, imageData } = e.data;
if (id !== currentRenderId) return; // 忽略旧的渲染结果
if (type === 'progress') {
status.textContent = `渲染进度: ${progress}%`;
ctx.putImageData(imageData, 0, 0);
} else if (type === 'complete') {
ctx.putImageData(imageData, 0, 0);
isRendering = false;
status.textContent = "渲染完成";
renderBtn.disabled = false;
updateViewInfo();
}
};
// 发送渲染任务
renderWorker.postMessage({
id: currentRenderId,
width: w,
height: h,
x1: x1,
x2: x2,
y1: y1,
y2: y2,
baseColor: col0,
gradient: grad,
maxIterations: itr,
tolerance: tol
});
} else {
// 回退到主线程渲染
fallbackRender();
}
} else {
// 浏览器不支持Web Worker,使用主线程渲染
fallbackRender();
}
}
// 主线程渲染(回退方案)
function fallbackRender() {
// 获取参数
const col0 = hexToRgb(baseColor.value);
const grad = parseInt(gradient.value);
const w = canvas.width;
const h = canvas.height;
const tol = Math.pow(10, -9 + (tolerance.value / 100) * 3);
const itr = parseInt(iterations.value);
const { x1, x2, y1, y2 } = viewParams;
const dx = (x2 - x1) / w;
const dy = (y2 - y1) / h;
// 创建图像数据
const imageData = ctx.createImageData(w, h);
const data = imageData.data;
// 使用TypedArray提高性能
const pixelData = new Uint32Array(data.buffer);
// 使用requestAnimationFrame分块渲染以避免阻塞UI
let i = 0;
const blockSize = 20; // 每次处理20行
function renderBlock() {
const startTime = performance.now();
const endI = Math.min(i + blockSize, w);
for (; i < endI; i++) {
for (let j = 0; j < h; j++) {
const cx = x1 + i * dx;
const cy = y1 + j * dy;
let x = cx;
let y = cy;
let n = 0;
// 迭代
while (n <= itr) {
const xx = fx(x, y, cx, cy);
const yy = fy(x, y, cx, cy);
if (escape(xx, x, yy, y, tol)) {
// 计算颜色
const hue = (col0 * 360 / 255 + grad * n) % 360;
const rgb = hslToRgb(hue, 100, 50);
// 设置像素颜色 (ARGB格式)
pixelData = (255 << 24) | (rgb << 16) | (rgb << 8) | rgb;
n = itr + 1;
} else {
x = xx;
y = yy;
}
n++;
}
// 如果达到最大迭代次数仍未逃逸,设为黑色
if (n === itr + 1) {
pixelData = 0xff000000; // 黑色
}
}
}
// 更新进度
const progress = (i / w) * 100;
status.textContent = `渲染进度: ${Math.round(progress)}%`;
// 定期更新画布
if (i % 50 === 0 || i >= w) {
ctx.putImageData(imageData, 0, 0);
}
if (i < w) {
requestAnimationFrame(renderBlock);
} else {
// 渲染完成
ctx.putImageData(imageData, 0, 0);
isRendering = false;
status.textContent = "渲染完成";
renderBtn.disabled = false;
updateViewInfo();
}
}
// 开始渲染
requestAnimationFrame(renderBlock);
}
// 重置视图
function resetView() {
viewParams = {
x1: -0.85833333333333333333,
x2: -0.8,
y1: -0.025,
y2: 0.01875
};
renderFractal();
}
// 添加事件监听器
renderBtn.addEventListener('click', renderFractal);
resetBtn.addEventListener('click', resetView);
// 添加缩放和平移功能
let isDragging = false;
let lastX, lastY;
let renderTimeout = null;
canvas.addEventListener('wheel', (e) => {
e.preventDefault();
const rect = canvas.getBoundingClientRect();
const x = (e.clientX - rect.left) / canvas.width;
const y = (e.clientY - rect.top) / canvas.height;
const zoomIntensity = 0.2;
const wheelDelta = e.deltaY < 0 ? 1 : -1;
const zoomFactor = Math.exp(wheelDelta * zoomIntensity);
// 计算当前视图范围
const rangeX = viewParams.x2 - viewParams.x1;
const rangeY = viewParams.y2 - viewParams.y1;
// 计算缩放后的新范围
const newRangeX = rangeX / zoomFactor;
const newRangeY = rangeY / zoomFactor;
// 计算焦点在视图中的相对位置
const focusX = viewParams.x1 + rangeX * x;
const focusY = viewParams.y1 + rangeY * y;
// 更新视图参数,保持焦点位置不变
viewParams.x1 = focusX - newRangeX * x;
viewParams.x2 = focusX + newRangeX * (1 - x);
viewParams.y1 = focusY - newRangeY * y;
viewParams.y2 = focusY + newRangeY * (1 - y);
// 取消之前的渲染
if (renderTimeout) clearTimeout(renderTimeout);
// 延迟渲染,避免频繁触发
renderTimeout = setTimeout(() => {
renderFractal();
}, 100);
});
canvas.addEventListener('mousedown', (e) => {
isDragging = true;
lastX = e.clientX;
lastY = e.clientY;
canvas.style.cursor = 'grabbing';
});
canvas.addEventListener('mousemove', (e) => {
if (!isDragging) return;
const rect = canvas.getBoundingClientRect();
const dx = (e.clientX - lastX) / canvas.width * (viewParams.x2 - viewParams.x1);
const dy = (e.clientY - lastY) / canvas.height * (viewParams.y2 - viewParams.y1);
viewParams.x1 -= dx;
viewParams.x2 -= dx;
viewParams.y1 -= dy;
viewParams.y2 -= dy;
lastX = e.clientX;
lastY = e.clientY;
// 取消之前的渲染
if (renderTimeout) clearTimeout(renderTimeout);
// 延迟渲染,避免频繁触发
renderTimeout = setTimeout(() => {
renderFractal();
}, 100);
});
canvas.addEventListener('mouseup', () => {
isDragging = false;
canvas.style.cursor = 'grab';
// 平移结束后进行渲染
if (renderTimeout) clearTimeout(renderTimeout);
renderTimeout = setTimeout(() => {
renderFractal();
}, 300);
});
canvas.addEventListener('mouseleave', () => {
isDragging = false;
canvas.style.cursor = 'default';
});
canvas.addEventListener('mouseenter', () => {
canvas.style.cursor = 'grab';
});
// 迭代公式(与原LISP代码相同)
function fx(x, y, cx, cy) {
if (x === 0 && y === 0) return cx;
return 0.5 * (x - x / (x*x + y*y)) + cx;
}
function fy(x, y, cx, cy) {
if (x === 0 && y === 0) return cy;
return 0.5 * (y + y / (x*x + y*y)) + cy;
}
// 逃逸判断
function escape(x, xx, y, yy, tol) {
return (xx - x) * (xx - x) + (yy - y) * (yy - y) < tol;
}
// 优化的HSL到RGB转换
function hslToRgb(h, s, l) {
h /= 360;
s /= 100;
l /= 100;
let r, g, b;
if (s === 0) {
r = g = b = l;
} else {
const hue2rgb = (p, q, t) => {
if (t < 0) t += 1;
if (t > 1) t -= 1;
if (t < 1/6) return p + (q - p) * 6 * t;
if (t < 1/2) return q;
if (t < 2/3) return p + (q - p) * (2/3 - t) * 6;
return p;
};
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
const p = 2 * l - q;
r = hue2rgb(p, q, h + 1/3);
g = hue2rgb(p, q, h);
b = hue2rgb(p, q, h - 1/3);
}
return ;
}
// 初始渲染
renderFractal();
</script>
</body>
</html> yangyangyixia 发表于 2025-11-11 09:35
膜拜大师,lisp有点慢,用html看了看效果还行
佩服佩服!测试运行了,效果很不错! highflybird大师才是真正的高高手!!! 本帖最后由 highflybird 于 2014-8-22 15:05 编辑
程序的LISP代码:
;;;*********************************************
;;; 迭代公式(用户可以自行修改)
;;; x,xx复数的实数部分,y,yy复数的虚数部分
;;; xx = (x-x/(x*x+y*y))/2+cx
;;; yy = (y+y/(x*x+y*y))/2+cy
;;;*********************************************
(defun fx (x y cx cy)
(if (and (zerop x) (zerop y))
cx
(+ (* 0.5 (- x (/ x (+ (* x x) (* y y))))) cx)
)
)
(defun fy (x y cx cy)
(if (and (zerop x) (zerop y))
cy
(+ (* 0.5 (+ y (/ y (+ (* x x) (* y y))))) cy)
)
)
;;;*********************************************
;;; 逃逸判断:
;;; 当两个复数相接近的时候停止迭代
;;;*********************************************
(defun Escape (x xx y yy tol)
(< (+ (* (- xx x) (- xx x)) (* (- yy y) (- yy y))) tol)
)
;;;*********************************************
;;; Highflybird分形的绘制主函数
;;; 参数: col0 初始颜色值
;;; X1,X2,Y1,Y2,点的取值范围
;;; W,H图像的宽和高
;;; tol逃逸半径
;;; Itr迭代最大次数
;;; Grad 颜色梯度
;;;*********************************************
(defun HFB_fractal (col0 X1 X2 Y1 Y2 W H tol Itr grad /
i j dx dy HSL0 cx cy x y n xx yy)
(setq HSL0 (apply 'RGB->HSL col0))
(setq dx (/ (- X2 X1 0.0) W))
(setq dy (/ (- Y2 Y1 0.0) H))
(setq i 0)
(repeat W ;图像的宽
(setq j 0)
(repeat H ;图像的高
(setq cx (+ X1 (* i dx))) ;实数部分
(setq cy (+ Y1 (* j dy))) ;虚数部分
(setq x cx y cy) ;开始迭代位置
(setq n 0) ;迭代次数置零
(while (<= n Itr) ;开始迭代
(setq xx (fx x y cx cy)) ;得到新的实数部分
(setq yy (fy x y cx cy)) ;得到新的虚数部分
(if (Escape xx x yy y tol) ;如果满足逃逸函数
(progn
(PutColor HSL0 i j n grad) ;着色这点
(setq n Itr) ;中断循环
)
(setq x xx y yy) ;否则继续迭代
)
(setq n (1+ n))
)
(setq j (1+ j))
)
(setq i (1+ i))
)
)
当然用LISP速度比较慢,最后我用了ARX编程,才满足了所见即所得的效果。
顺便推销一下我的博客地址:http://highflybird.mjtd.com/
欢迎大家有空转转哦!
高飞鸟神一般的存在!飞在云端看不见啊
太高深,我等这一辈子都不法理解啊 老实说没看明白
不是指后面那些涉及数学的内容
虽然那些确实也没去看
不知高飞鸟用的什么版本的CAD
我用的2004
弧的夹点只显示3个
两端点+弧中点
2010也只显示3夹点
嗯
假如还显示弧的圆心的话
那在拖动弧中点的时候
圆心应该是一直在变化的
怎么也没可能
让弧中点与圆心无限接近
前置条件没明白
后面也就没去看了
难道说
4夹点的系统里
拖动弧中点的过程中
圆心的那个夹点是“静止”的
弧中心接近圆心时才发生变化?
本帖最后由 highflybird 于 2014-8-22 11:38 编辑
masterlong 发表于 2014-8-22 11:04 static/image/common/back.gif
老实说没看明白
不是指后面那些涉及数学的内容
虽然那些确实也没去看
我没用过2004版本,但2006版本的确是有4个夹点的。
你选中的时候,出现4个蓝色的夹点。
在2006版本的时候,拖动中点的那个夹点,弧心的那个夹点位置不变,只有确定后才发生改变。
哈哈,幸好我用的是2006,不然的话,还发现不了这一规律。
highflybird 是我们的偶像,真心想佩服!说胡话,前辈发内容我没有一个完全看懂的(其实最多只能看懂一点点),但是我真的很佩服前辈。一个小小的问题,您能会阐述出这么多的理论,佩服前辈这种“钻”的精神,是值得我们后辈学习!向highflybird致敬!! 能看懂LZ的帖子就能成为大师了,尽管只看懂了一点点,也使我在黑暗中少摸索了N多年,真心感谢 前排仰视大神,晚辈向高老师学习!
不明白你那图片是怎么弄出来的 向highflybird大师学习,看来不仅是编程高手,而且是个数学天材,膜拜中,望尘莫及啊