572 lines
82 KiB
HTML
572 lines
82 KiB
HTML
<!DOCTYPE html><html lang="zh-CN" data-theme="light"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0,viewport-fit=cover"><title>OpenGL-直线的扫描转换 | Bi's Blog</title><meta name="author" content="biss"><meta name="copyright" content="biss"><meta name="format-detection" content="telephone=no"><meta name="theme-color" content="#ffffff"><meta name="description" content="这篇文章来介绍直线扫描转换算法 DDA数值微分线段算法算法简介数值微分法即DDA法(Digital Differential Analyzer),是一种基于微分方程来生成直线的方法。在计算机图形学中,并没有线段的概念,而是一个个像素点组成了线段。 DDA法生成线段的步骤一般如下: 有了起始点($x_1,y_1$)和终点($x_n,y_n$); $$\Delta x =|x_n-x_1|">
|
||
<meta property="og:type" content="article">
|
||
<meta property="og:title" content="OpenGL-直线的扫描转换">
|
||
<meta property="og:url" content="https://blog.biss.click/posts/7207243b/index.html">
|
||
<meta property="og:site_name" content="Bi's Blog">
|
||
<meta property="og:description" content="这篇文章来介绍直线扫描转换算法 DDA数值微分线段算法算法简介数值微分法即DDA法(Digital Differential Analyzer),是一种基于微分方程来生成直线的方法。在计算机图形学中,并没有线段的概念,而是一个个像素点组成了线段。 DDA法生成线段的步骤一般如下: 有了起始点($x_1,y_1$)和终点($x_n,y_n$); $$\Delta x =|x_n-x_1|">
|
||
<meta property="og:locale" content="zh_CN">
|
||
<meta property="og:image" content="https://pic.biss.click/image/c5457adc-214c-4a18-9aa6-43fbc0bfc2f4.webp">
|
||
<meta property="article:published_time" content="2026-04-11T11:01:02.000Z">
|
||
<meta property="article:modified_time" content="2026-04-11T11:56:17.367Z">
|
||
<meta property="article:author" content="biss">
|
||
<meta property="article:tag" content="OpenGL">
|
||
<meta name="twitter:card" content="summary">
|
||
<meta name="twitter:image" content="https://pic.biss.click/image/c5457adc-214c-4a18-9aa6-43fbc0bfc2f4.webp"><script type="application/ld+json">{
|
||
"@context": "https://schema.org",
|
||
"@type": "BlogPosting",
|
||
"headline": "OpenGL-直线的扫描转换",
|
||
"url": "https://blog.biss.click/posts/7207243b/",
|
||
"image": "https://pic.biss.click/image/c5457adc-214c-4a18-9aa6-43fbc0bfc2f4.webp",
|
||
"datePublished": "2026-04-11T11:01:02.000Z",
|
||
"dateModified": "2026-04-11T11:56:17.367Z",
|
||
"author": [
|
||
{
|
||
"@type": "Person",
|
||
"name": "biss",
|
||
"url": "https://blog.biss.click"
|
||
}
|
||
]
|
||
}</script><link rel="shortcut icon" href="/images/Bi.ico"><link rel="canonical" href="https://blog.biss.click/posts/7207243b/index.html"><link rel="preconnect" href="//unpkg.com"><link rel="stylesheet" href="/css/index.css"><link rel="stylesheet" href="https://unpkg.com/@fortawesome/fontawesome-free/css/all.min.css"><link rel="stylesheet" href="https://unpkg.com/node-snackbar/dist/snackbar.min.css" media="print" onload="this.media='all'"><link rel="stylesheet" href="https://unpkg.com/@fancyapps/ui/dist/fancybox/fancybox.css" media="print" onload="this.media='all'"><script>
|
||
(() => {
|
||
|
||
const saveToLocal = {
|
||
set: (key, value, ttl) => {
|
||
if (!ttl) return
|
||
const expiry = Date.now() + ttl * 86400000
|
||
localStorage.setItem(key, JSON.stringify({ value, expiry }))
|
||
},
|
||
get: key => {
|
||
const itemStr = localStorage.getItem(key)
|
||
if (!itemStr) return undefined
|
||
const { value, expiry } = JSON.parse(itemStr)
|
||
if (Date.now() > expiry) {
|
||
localStorage.removeItem(key)
|
||
return undefined
|
||
}
|
||
return value
|
||
}
|
||
}
|
||
|
||
window.btf = {
|
||
saveToLocal,
|
||
getScript: (url, attr = {}) => new Promise((resolve, reject) => {
|
||
const script = document.createElement('script')
|
||
script.src = url
|
||
script.async = true
|
||
Object.entries(attr).forEach(([key, val]) => script.setAttribute(key, val))
|
||
script.onload = script.onreadystatechange = () => {
|
||
if (!script.readyState || /loaded|complete/.test(script.readyState)) resolve()
|
||
}
|
||
script.onerror = reject
|
||
document.head.appendChild(script)
|
||
}),
|
||
getCSS: (url, id) => new Promise((resolve, reject) => {
|
||
const link = document.createElement('link')
|
||
link.rel = 'stylesheet'
|
||
link.href = url
|
||
if (id) link.id = id
|
||
link.onload = link.onreadystatechange = () => {
|
||
if (!link.readyState || /loaded|complete/.test(link.readyState)) resolve()
|
||
}
|
||
link.onerror = reject
|
||
document.head.appendChild(link)
|
||
}),
|
||
addGlobalFn: (key, fn, name = false, parent = window) => {
|
||
if (!true && key.startsWith('pjax')) return
|
||
const globalFn = parent.globalFn || {}
|
||
globalFn[key] = globalFn[key] || {}
|
||
globalFn[key][name || Object.keys(globalFn[key]).length] = fn
|
||
parent.globalFn = globalFn
|
||
}
|
||
}
|
||
|
||
|
||
const activateDarkMode = () => {
|
||
document.documentElement.setAttribute('data-theme', 'dark')
|
||
if (document.querySelector('meta[name="theme-color"]') !== null) {
|
||
document.querySelector('meta[name="theme-color"]').setAttribute('content', '#0d0d0d')
|
||
}
|
||
}
|
||
const activateLightMode = () => {
|
||
document.documentElement.setAttribute('data-theme', 'light')
|
||
if (document.querySelector('meta[name="theme-color"]') !== null) {
|
||
document.querySelector('meta[name="theme-color"]').setAttribute('content', '#ffffff')
|
||
}
|
||
}
|
||
|
||
btf.activateDarkMode = activateDarkMode
|
||
btf.activateLightMode = activateLightMode
|
||
|
||
const theme = saveToLocal.get('theme')
|
||
|
||
theme === 'dark' ? activateDarkMode() : theme === 'light' ? activateLightMode() : null
|
||
|
||
|
||
const asideStatus = saveToLocal.get('aside-status')
|
||
if (asideStatus !== undefined) {
|
||
document.documentElement.classList.toggle('hide-aside', asideStatus === 'hide')
|
||
}
|
||
|
||
|
||
const detectApple = () => {
|
||
if (/iPad|iPhone|iPod|Macintosh/.test(navigator.userAgent)) {
|
||
document.documentElement.classList.add('apple')
|
||
}
|
||
}
|
||
detectApple()
|
||
|
||
})()
|
||
</script><script>const GLOBAL_CONFIG = {
|
||
root: '/',
|
||
algolia: undefined,
|
||
localSearch: undefined,
|
||
translate: {"defaultEncoding":2,"translateDelay":0,"msgToTraditionalChinese":"繁","msgToSimplifiedChinese":"簡"},
|
||
highlight: {"plugin":"highlight.js","highlightCopy":true,"highlightLang":true,"highlightHeightLimit":200,"highlightFullpage":true,"highlightMacStyle":false},
|
||
copy: {
|
||
success: '复制成功',
|
||
error: '复制失败',
|
||
noSupport: '浏览器不支持'
|
||
},
|
||
relativeDate: {
|
||
homepage: false,
|
||
post: false
|
||
},
|
||
runtime: '',
|
||
dateSuffix: {
|
||
just: '刚刚',
|
||
min: '分钟前',
|
||
hour: '小时前',
|
||
day: '天前',
|
||
month: '个月前'
|
||
},
|
||
copyright: undefined,
|
||
lightbox: 'fancybox',
|
||
Snackbar: {"chs_to_cht":"已切换为繁体中文","cht_to_chs":"已切换为简体中文","day_to_night":"已切换为深色模式","night_to_day":"已切换为浅色模式","bgLight":"#49b1f5","bgDark":"#1f1f1f","position":"bottom-left"},
|
||
infinitegrid: {
|
||
js: 'https://unpkg.com/@egjs/infinitegrid/dist/infinitegrid.min.js',
|
||
buttonText: '加载更多'
|
||
},
|
||
isPhotoFigcaption: false,
|
||
islazyloadPlugin: false,
|
||
isAnchor: false,
|
||
percent: {
|
||
toc: true,
|
||
rightside: true,
|
||
},
|
||
autoDarkmode: false
|
||
}</script><script id="config-diff">var GLOBAL_CONFIG_SITE = {
|
||
title: 'OpenGL-直线的扫描转换',
|
||
isHighlightShrink: false,
|
||
isToc: true,
|
||
pageType: 'post'
|
||
}</script><link rel="stylesheet" href="/css/shuoshuo.css"><link rel="stylesheet" href="/css/shuoshuoshouye.css"><link rel="stylesheet" href="/css/nav.css"><link rel="stylesheet" href="/css/style.css"><link rel="stylesheet" href="/css/poem.css"><link rel="stylesheet" href="/css/swiper.css"><link rel="stylesheet" href="https://cdn.jsdmirror.com/npm/instantsearch.css/themes/reset-min.css"><link rel="stylesheet" href="https://cdn.jsdmirror.com/gh/bishshi/welcomemessage/welcome.css"><link rel="stylesheet" href="https://cdn.jsdmirror.com/gh/bishshi/sidecalendar/calendar.css"><link rel="stylesheet" href="https://cdn.jsdmirror.com/gh/bishshi/rightmenu/rightmenu.css"><link rel="stylesheet" href="https://cdn.jsdmirror.com/gh/bishshi/webfont/font.css"><link rel="stylesheet" href="https://cdn.jsdmirror.com/npm/aplayer/dist/APlayer.min.css" media="all" onload="this.media="all""><!-- hexo injector head_end start --><link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/Swiper/5.4.5/css/swiper.min.css" media="print" onload="this.media='all'"><link rel="stylesheet" href="https://cdn1.tianli0.top/npm/hexo-butterfly-swiper/lib/swiperstyle.css" media="print" onload="this.media='all'"><!-- hexo injector head_end end --><style type="text/css">
|
||
.spoiler {
|
||
display: inline;
|
||
}
|
||
p.spoiler {
|
||
display: flex;
|
||
}
|
||
.spoiler a {
|
||
pointer-events: none;
|
||
}
|
||
.spoiler-blur, .spoiler-blur > * {
|
||
transition: text-shadow .5s ease;
|
||
}
|
||
.spoiler .spoiler-blur, .spoiler .spoiler-blur > * {
|
||
color: rgba(0, 0, 0, 0);
|
||
background-color: rgba(0, 0, 0, 0);
|
||
text-shadow: 0 0 10px grey;
|
||
cursor: pointer;
|
||
}
|
||
.spoiler .spoiler-blur:hover, .spoiler .spoiler-blur:hover > * {
|
||
text-shadow: 0 0 5px grey;
|
||
}
|
||
.spoiler-box, .spoiler-box > * {
|
||
transition: color .5s ease,
|
||
background-color .5s ease;
|
||
}
|
||
.spoiler .spoiler-box, .spoiler .spoiler-box > * {
|
||
color: black;
|
||
background-color: black;
|
||
text-shadow: none;
|
||
}</style><meta name="generator" content="Hexo 8.1.1"><link rel="alternate" href="/atom.xml" title="Bi's Blog" type="application/atom+xml">
|
||
</head><body><div class="bg-animation" id="web_bg" style="background-image: url(/images/background.png);"></div><div id="sidebar"><div id="menu-mask"></div><div id="sidebar-menus"><div class="avatar-img text-center"><img src="https://free.picui.cn/free/2025/08/10/689845496a283.png" onerror="this.onerror=null;this.src='/img/friend_404.gif'" alt="avatar"></div><div class="site-data text-center"><a href="/archives/"><div class="headline">文章</div><div class="length-num">38</div></a><a href="/tags/"><div class="headline">标签</div><div class="length-num">12</div></a><a href="/categories/"><div class="headline">分类</div><div class="length-num">6</div></a></div><div class="menus_items"><div class="menus_item"><a class="site-page" href="/"><i class="fa-fw fas fa-home"></i><span> 首页</span></a></div><div class="menus_item"><a class="site-page" href="/archives/"><i class="fa-fw fas fa-archive"></i><span> 存档</span></a></div><div class="menus_item"><a class="site-page" href="/tags/"><i class="fa-fw fas fa-tags"></i><span> 标签</span></a></div><div class="menus_item"><a class="site-page" href="/categories/"><i class="fa-fw fas fa-folder-open"></i><span> 分类</span></a></div><div class="menus_item"><a class="site-page" href="/shuoshuo/"><i class="fa-fw fa-regular fa-comment"></i><span> 说说</span></a></div><div class="menus_item"><a class="site-page" href="/link/"><i class="fa-fw fas fa-link"></i><span> 友链</span></a></div><div class="menus_item"><a class="site-page" href="/about/"><i class="fa-fw fas fa-heart"></i><span> 关于</span></a></div></div></div></div><div class="post" id="body-wrap"><header class="post-bg fixed" id="page-header" style="background-image: url(https://pic.biss.click/image/c5457adc-214c-4a18-9aa6-43fbc0bfc2f4.webp);"><nav id="nav"><span id="blog-info"><div id="ls-menu-container"><i class="fas fa-fingerprint"></i><div id="ls-menu-panel"><div class="ls-section"><div class="ls-title">😀 个人网站</div><div class="ls-grid"><a href="/"><i class="fas fa-rss"></i> 个人博客</a><a target="_blank" rel="noopener" href="https://github.com/bishshi"><i class="fab fa-github"></i> Github</a><a target="_blank" rel="noopener" href="https://space.bilibili.com/20665809"><i class="fab fa-bilibili"></i> 哔哩哔哩</a></div></div><div class="ls-section"><div class="ls-title">😎 常用服务</div><div class="ls-grid"><a target="_blank" rel="noopener" href="https://git.biss.click/biss"><i class="fas fa-code"></i> 代码仓库</a><a target="_blank" rel="noopener" href="https://mm.biss.click"><i class="fas fa-pen-nib"></i> 日常说说</a><a target="_blank" rel="noopener" href="https://pic.biss.click"><i class="fas fa-image"></i> 图床</a><a target="_blank" rel="noopener" href="https://git.biss.click"><i class="fas fa-code-branch"></i> 代码仓库</a></div></div><div class="ls-section"><div class="ls-title">🛸 实用工具</div><div class="ls-grid"><a target="_blank" rel="noopener" href="https://cover.biss.click"><i class="fas fa-palette"></i> 封面设计</a><a target="_blank" rel="noopener" href="https://doc.biss.click"><i class="fas fa-file"></i> 文档服务</a><a target="_blank" rel="noopener" href="https://status.biss.click"><i class="fas fa-server"></i> 服务监测</a><a target="_blank" rel="noopener" href="https://typesense.biss.click"><i class="fas fa-magnifying-glass"></i> 搜索后端</a></div></div></div></div><a class="nav-site-title" href="/"><span class="site-name">Bi's Blog</span></a></span><a class="nav-page-title" href="javascript:void(0);" onclick="btf.scrollToDest(0, 500)"><span class="site-name">OpenGL-直线的扫描转换</span></a><div id="nav-right"><div id="menus"><div class="menus_items"><div class="menus_item"><a class="site-page" href="/"><i class="fa-fw fas fa-home"></i><span> 首页</span></a></div><div class="menus_item"><a class="site-page" href="/archives/"><i class="fa-fw fas fa-archive"></i><span> 存档</span></a></div><div class="menus_item"><a class="site-page" href="/tags/"><i class="fa-fw fas fa-tags"></i><span> 标签</span></a></div><div class="menus_item"><a class="site-page" href="/categories/"><i class="fa-fw fas fa-folder-open"></i><span> 分类</span></a></div><div class="menus_item"><a class="site-page" href="/shuoshuo/"><i class="fa-fw fa-regular fa-comment"></i><span> 说说</span></a></div><div class="menus_item"><a class="site-page" href="/link/"><i class="fa-fw fas fa-link"></i><span> 友链</span></a></div><div class="menus_item"><a class="site-page" href="/about/"><i class="fa-fw fas fa-heart"></i><span> 关于</span></a></div></div></div><div id="random-post-button"><a class="site-page social-icon" id="random-post-link" href="javascript:void(0);" onclick="randomPost()"><i class="fas fa-solid fa-shuffle"></i></a></div><div id="search-button"><a class="site-page social-icon search-typesense-trigger"><i class="fas fa-search fa-fw"></i></a></div><div id="toggle-menu"><span class="site-page"><i class="fas fa-bars fa-fw"></i></span></div></div></nav><div id="post-info"><h1 class="post-title">OpenGL-直线的扫描转换</h1><div id="post-meta"><div class="meta-firstline"><span class="post-meta-date"><i class="far fa-calendar-alt fa-fw post-meta-icon"></i><span class="post-meta-label">发表于</span><time class="post-meta-date-created" datetime="2026-04-11T11:01:02.000Z" title="发表于 2026-04-11 19:01:02">2026-04-11</time><span class="post-meta-separator">|</span><i class="fas fa-history fa-fw post-meta-icon"></i><span class="post-meta-label">更新于</span><time class="post-meta-date-updated" datetime="2026-04-11T11:56:17.367Z" title="更新于 2026-04-11 19:56:17">2026-04-11</time></span><span class="post-meta-categories"><span class="post-meta-separator">|</span><i class="fas fa-inbox fa-fw post-meta-icon"></i><a class="post-meta-categories" href="/categories/technology/">技术</a><i class="fas fa-angle-right post-meta-separator"></i><i class="fas fa-inbox fa-fw post-meta-icon"></i><a class="post-meta-categories" href="/categories/technology/learning/">学习</a></span></div><div class="meta-secondline"><span class="post-meta-separator">|</span><span class="post-meta-wordcount"><i class="far fa-file-word fa-fw post-meta-icon"></i><span class="post-meta-label">总字数:</span><span class="word-count">2k</span><span class="post-meta-separator">|</span><i class="far fa-clock fa-fw post-meta-icon"></i><span class="post-meta-label">阅读时长:</span><span>8分钟</span></span><span class="post-meta-separator">|</span><span id="" data-flag-title=""><i class="far fa-eye fa-fw post-meta-icon"></i><span class="post-meta-label">浏览量:</span><span id="twikoo_visitors"><i class="fa-solid fa-spinner fa-spin"></i></span></span><span class="post-meta-separator">|</span><span class="post-meta-commentcount"><i class="far fa-comments fa-fw post-meta-icon"></i><span class="post-meta-label">评论数:</span><a href="/posts/7207243b/#post-comment"><span id="twikoo-count"><i class="fa-solid fa-spinner fa-spin"></i></span></a></span></div></div></div></header><main class="layout" id="content-inner"><div id="post"><article class="container post-content" id="article-container"><div class="ai-summary"><div class="ai-explanation" style="display: block;" data-summary="这篇文章介绍了三种直线扫描转换算法:DDA算法、中点画线算法和Bresenham算法。 DDA算法通过计算直线起点和终点的坐标差值来确定步数和增量,依次绘制直线上的点。算法实现简单,适用于任意直线,但精度较低。 中点画线算法仅适用于斜率为0或1的直线,通过计算中点和斜率来确定直线上的像素点,效率较高。 Bresenham算法根据直线的斜率和误差项来确定像素点的位置,适用于任意直线,且精度高,但实现稍复杂。">AI正在绞尽脑汁想思路ING···</div><div class="ai-title"> <div class="ai-title-left"> <i class="fa-brands fa-slack"></i><div class="ai-title-text">BiのAI摘要</div></div><div class="ai-tag" id="ai-tag">HunYuan-Lite</div></div></div><div id="post-outdate-notice" data="{"limitDay":365,"messagePrev":"It has been","messageNext":"days since the last update, the content of the article may be outdated.","postUpdate":"2026-04-11 19:56:17"}" hidden=""></div><p>这篇文章来介绍直线扫描转换算法</p>
|
||
<h1 id="DDA数值微分线段算法"><a href="#DDA数值微分线段算法" class="headerlink" title="DDA数值微分线段算法"></a>DDA数值微分线段算法</h1><h2 id="算法简介"><a href="#算法简介" class="headerlink" title="算法简介"></a>算法简介</h2><p>数值微分法即DDA法(Digital Differential Analyzer),是一种基于微分方程来生成直线的方法。在计算机图形学中,并没有线段的概念,而是一个个像素点组成了线段。</p>
|
||
<p>DDA法生成线段的步骤一般如下:</p>
|
||
<ol>
|
||
<li>有了起始点($x_1,y_1$)和终点($x_n,y_n$);</li>
|
||
<li>$$\Delta x =|x_n-x_1|, \Delta y=|y_n-y_1|$$</li>
|
||
<li>比较$\Delta x$和$\Delta y$的大小;<br> steps=$\Delta x$和$\Delta y$中较大者;</li>
|
||
<li>$$step_x=\frac{\Delta x}{steps},step_y=\frac{\Delta y}{steps}$$</li>
|
||
</ol>
|
||
<h2 id="算法实现"><a href="#算法实现" class="headerlink" title="算法实现"></a>算法实现</h2><p>DDA算法实现如下:</p>
|
||
<figure class="highlight cpp"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cmath></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><iostream></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><GL/glut.h></span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 窗口宽度和高度</span></span><br><span class="line"><span class="type">const</span> <span class="type">int</span> WIDTH = <span class="number">640</span>;</span><br><span class="line"><span class="type">const</span> <span class="type">int</span> HEIGHT = <span class="number">480</span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">drawDDALine</span><span class="params">(<span class="type">int</span> x1, <span class="type">int</span> y1, <span class="type">int</span> x2, <span class="type">int</span> y2)</span> </span>{</span><br><span class="line"> <span class="type">float</span> x = x1;</span><br><span class="line"> <span class="type">float</span> y = y1;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 计算差值</span></span><br><span class="line"> <span class="type">int</span> dx = x2 - x1;</span><br><span class="line"> <span class="type">int</span> dy = y2 - y1;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 确定步数,取 dx 和 dy 中绝对值较大的那个</span></span><br><span class="line"> <span class="type">int</span> steps = std::<span class="built_in">abs</span>(dx) > std::<span class="built_in">abs</span>(dy) ? std::<span class="built_in">abs</span>(dx) : std::<span class="built_in">abs</span>(dy); <span class="comment">//三元表达式</span></span><br><span class="line"></span><br><span class="line"> <span class="comment">// 计算每一步的增量</span></span><br><span class="line"> <span class="type">float</span> xIncrement = (<span class="type">float</span>)dx / steps;</span><br><span class="line"> <span class="type">float</span> yIncrement = (<span class="type">float</span>)dy / steps;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 开始绘制点</span></span><br><span class="line"> <span class="built_in">glBegin</span>(GL_POINTS);</span><br><span class="line"> <span class="built_in">glVertex2i</span>((<span class="type">int</span>)<span class="built_in">round</span>(x), (<span class="type">int</span>)<span class="built_in">round</span>(y)); <span class="comment">// 绘制起点</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> k = <span class="number">0</span>; k < steps; k++) {</span><br><span class="line"> x += xIncrement;</span><br><span class="line"> y += yIncrement;</span><br><span class="line"> <span class="comment">// 将浮点坐标四舍五入取整转换为整数像素坐标</span></span><br><span class="line"> std::cout << (<span class="type">int</span>)<span class="built_in">round</span>(x) << <span class="string">", "</span> << (<span class="type">int</span>)<span class="built_in">round</span>(y)<<<span class="string">"\n"</span>;</span><br><span class="line"> <span class="built_in">glVertex2i</span>((<span class="type">int</span>)<span class="built_in">round</span>(x), (<span class="type">int</span>)<span class="built_in">round</span>(y));</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">glEnd</span>();</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// 显示回调函数</span></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">display</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="built_in">drawDDALine</span>(<span class="number">0</span>, <span class="number">0</span>, <span class="number">50</span>, <span class="number">20</span>);</span><br><span class="line"> <span class="built_in">glFlush</span>();</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// 初始化 OpenGL 设置</span></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">init</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="comment">// 设置背景颜色为白色</span></span><br><span class="line"> <span class="built_in">glClearColor</span>(<span class="number">1.0f</span>, <span class="number">1.0f</span>, <span class="number">1.0f</span>, <span class="number">1.0f</span>);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 设置投影矩阵为 2D 正交投影</span></span><br><span class="line"> <span class="built_in">glMatrixMode</span>(GL_PROJECTION);</span><br><span class="line"> <span class="built_in">glLoadIdentity</span>();</span><br><span class="line"> <span class="comment">// 定义可视区域,左下角(0,0),右上角(WIDTH, HEIGHT)</span></span><br><span class="line"> <span class="built_in">gluOrtho2D</span>(<span class="number">0.0</span>, WIDTH, <span class="number">0.0</span>, HEIGHT);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span>** argv)</span> </span>{</span><br><span class="line"> <span class="comment">// 初始化 GLUT</span></span><br><span class="line"> <span class="built_in">glutInit</span>(&argc, argv);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 设置显示模式:单缓冲、RGB 颜色模式</span></span><br><span class="line"> <span class="built_in">glutInitDisplayMode</span>(GLUT_SINGLE | GLUT_RGB);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 设置窗口大小和位置</span></span><br><span class="line"> <span class="built_in">glutInitWindowSize</span>(WIDTH, HEIGHT);</span><br><span class="line"> <span class="built_in">glutInitWindowPosition</span>(<span class="number">100</span>, <span class="number">100</span>);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 创建窗口</span></span><br><span class="line"> <span class="built_in">glutCreateWindow</span>(<span class="string">"DDA算法"</span>);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 注册回调函数</span></span><br><span class="line"> <span class="built_in">glutDisplayFunc</span>(display);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 初始化设置</span></span><br><span class="line"> <span class="built_in">init</span>();</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 进入主循环</span></span><br><span class="line"> <span class="built_in">glutMainLoop</span>();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
|
||
|
||
<h1 id="中点画线算法"><a href="#中点画线算法" class="headerlink" title="中点画线算法"></a>中点画线算法</h1><h2 id="算法简介-1"><a href="#算法简介-1" class="headerlink" title="算法简介"></a>算法简介</h2><p>只考虑当直线的斜率$|k|< 1$时的情况,假设现在有一条直线$(x_1,y_1,x_2,y_2)$,那么第一个点一定是$(x_1,y_1)$无疑,下一个点的$x$坐标为$x_1+1$,$y$坐标要么为$y1$要么为$y1+1$。关键在于每次取下一个点时,是取前一个的$y1$呢,还是$y1+1$,这时一定是取直线上点最靠近的那个了,而判断取哪个点就用到了中点,我们将中点代入直线中 $d=F(x_1+1,y_1+0.5)=a \cdot (x_1+1)+b \cdot (y_1+0.5)+c$。</p>
|
||
<ol>
|
||
<li>如果直线$d>=0$,则取下边的点也就是$(x_1+1,y_1)$。</li>
|
||
<li>如果直线$d<0$,则取上边的点也就是$(x_1+1,y_1+1)$。</li>
|
||
</ol>
|
||
<p>它的实际过程就是这样每次根据前边的点判断下一个点在哪,然后进行打亮,但这样每次判断的时候都得代入直线方程计算太麻烦了,我们将这俩种情况分别代入直线方程中可以找出规律:</p>
|
||
<ol>
|
||
<li>当直线$d>=0$时,经过化解得$d_1=d+a$;</li>
|
||
<li>当直线$d<0$时,经过化解得$d_2=d+a+b$;</li>
|
||
<li>初始值$d_0=a+0.5b$。</li>
|
||
</ol>
|
||
<p>也就是说每次的增量要么为$a$,要么为$a+b$,那么这样判断的时候就简单多了,因为我们每次只是判断它的正负。所以给等式同时乘2,将其中浮点数0.5化为整数,这样硬件操作时无疑更快了。</p>
|
||
<h2 id="算法实现-1"><a href="#算法实现-1" class="headerlink" title="算法实现"></a>算法实现</h2><figure class="highlight cpp"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><GL/freeglut.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><iostream></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cmath></span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 中点画线算法函数 (仅针对斜率 0 <= k <= 1 的情况进行演示,其它象限需类比处理)</span></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">drawLineMidpoint</span><span class="params">(<span class="type">int</span> x0, <span class="type">int</span> y0, <span class="type">int</span> x1, <span class="type">int</span> y1)</span> </span>{</span><br><span class="line"> <span class="type">int</span> a = y0 - y1;</span><br><span class="line"> <span class="type">int</span> b = x1 - x0;</span><br><span class="line"> <span class="type">int</span> d = <span class="number">2</span> * a + b;</span><br><span class="line"> <span class="type">int</span> d1 = <span class="number">2</span> * a;</span><br><span class="line"> <span class="type">int</span> d2 = <span class="number">2</span> * (a + b);</span><br><span class="line"></span><br><span class="line"> <span class="type">int</span> x = x0, y = y0;</span><br><span class="line"></span><br><span class="line"> <span class="built_in">glBegin</span>(GL_POINTS);</span><br><span class="line"> <span class="built_in">glVertex2i</span>(x, y); <span class="comment">// 画起点</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">while</span> (x < x1) {</span><br><span class="line"> <span class="keyword">if</span> (d < <span class="number">0</span>) {</span><br><span class="line"> x++;</span><br><span class="line"> y++;</span><br><span class="line"> d += d2;</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> x++;</span><br><span class="line"> d += d1;</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">glVertex2i</span>(x, y);</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">glEnd</span>();</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// 渲染回调函数</span></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">display</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="built_in">glClear</span>(GL_COLOR_BUFFER_BIT);</span><br><span class="line"> <span class="built_in">glColor3f</span>(<span class="number">1.0</span>, <span class="number">1.0</span>, <span class="number">1.0</span>); <span class="comment">// 设置画笔颜色为白色</span></span><br><span class="line"></span><br><span class="line"> <span class="comment">// 调用算法画一条直线 (x0, y0) 到 (x1, y1)</span></span><br><span class="line"> <span class="comment">// 注意:此处的坐标对应屏幕像素坐标</span></span><br><span class="line"> <span class="built_in">drawLineMidpoint</span>(<span class="number">50</span>, <span class="number">50</span>, <span class="number">450</span>, <span class="number">300</span>);</span><br><span class="line"></span><br><span class="line"> <span class="built_in">glFlush</span>();</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// 初始化设置</span></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">init</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="built_in">glClearColor</span>(<span class="number">0.0</span>, <span class="number">0.0</span>, <span class="number">0.0</span>, <span class="number">1.0</span>); <span class="comment">// 背景设为黑色</span></span><br><span class="line"> <span class="built_in">glMatrixMode</span>(GL_PROJECTION);</span><br><span class="line"> <span class="built_in">glLoadIdentity</span>();</span><br><span class="line"> <span class="comment">// 设置正交投影矩阵,使坐标系与窗口像素对应</span></span><br><span class="line"> <span class="built_in">gluOrtho2D</span>(<span class="number">0</span>, <span class="number">500</span>, <span class="number">0</span>, <span class="number">500</span>); </span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span>** argv)</span> </span>{</span><br><span class="line"> <span class="built_in">glutInit</span>(&argc, argv);</span><br><span class="line"> <span class="built_in">glutInitDisplayMode</span>(GLUT_SINGLE | GLUT_RGB);</span><br><span class="line"> <span class="built_in">glutInitWindowSize</span>(<span class="number">500</span>, <span class="number">500</span>);</span><br><span class="line"> <span class="built_in">glutInitWindowPosition</span>(<span class="number">100</span>, <span class="number">100</span>);</span><br><span class="line"> <span class="built_in">glutCreateWindow</span>(<span class="string">"Midpoint Line Algorithm - FreeGLUT"</span>);</span><br><span class="line"></span><br><span class="line"> <span class="built_in">init</span>();</span><br><span class="line"> <span class="built_in">glutDisplayFunc</span>(display);</span><br><span class="line"> <span class="built_in">glutMainLoop</span>();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
|
||
|
||
<h1 id="Bresenham算法"><a href="#Bresenham算法" class="headerlink" title="Bresenham算法"></a>Bresenham算法</h1><h2 id="算法简介-2"><a href="#算法简介-2" class="headerlink" title="算法简介"></a>算法简介</h2><p>假设我们需要由$(x_0, y_0)$这一点,绘画一直线至右下角的另一点$(x_1, y_1)$,x,y分别代表其水平及垂直坐标,并且$x_1 - x_0 > y_1 - y_0$。在此我们使用电脑系统常用的坐标系,即$x$坐标值沿$x$轴向右增长,$y$坐标值沿$y$轴向下增长。</p>
|
||
<p>因此x及y之值分别向右及向下增加,而两点之水平距离为$x_{1}-x_{0}$且垂直距离为$y_{1}-y_{0}$。由此得之,该线的斜率必定介乎于$0$至$1$之间。而此算法之目的,就是找出在$x_{0}$与$x_{1}$之间,第$x$行相对应的第$y$列,从而得出一像素点,使得该像素点的位置最接近原本的线。</p>
|
||
<p>对于由$(x_0, y_0)$及$(x_1, y_1)$两点所组成之直线,公式如下:<br>$$y-y_{0}={\frac {y_{1}-y_{0}}{x_{1}-x_{0}}}(x-x_{0})$$<br>因此,对于每一点的x,其y的值是<br>$${\frac {y_{1}-y_{0}}{x_{1}-x_{0}}}(x-x_{0})+y_{0}$$<br>因为$x$及$y$皆为整数,但并非每一点$x$所对应的$y$皆为整数,故此没有必要去计算每一点x所对应之$y$值。反之由于此线之斜率介乎于$1$至$0$之间,故此我们只需要找出当$x$到达那一个数值时,会使$y$上升$1$,若$x$尚未到此值,则$y$不变。至于如何找出相关的$x$值,则需依靠斜率。斜率之计算方法为$m=(y_{1}-y_{0})/(x_{1}-x_{0})$。由于此值不变,故可于运算前预先计算,减少运算次数。</p>
|
||
<p>要实行此算法,我们需计算每一像素点与该线之间的误差。于上述例子中,误差应为每一点$x$中,其相对的像素点之$y$值与该线实际之$y$值的差距。每当$y$的值增加$1$,误差的值就会增加$m$。每当误差的值超出$0.5$,线就会比较靠近下一个映像点,因此$y$的值便会加$1$,且误差减$1$。</p>
|
||
<h2 id="算法实现-2"><a href="#算法实现-2" class="headerlink" title="算法实现"></a>算法实现</h2><figure class="highlight cpp"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><GL/freeglut.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><iostream></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cmath></span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 通用 Bresenham 画线算法</span></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">drawLineBresenham</span><span class="params">(<span class="type">int</span> x0, <span class="type">int</span> y0, <span class="type">int</span> x1, <span class="type">int</span> y1)</span> </span>{</span><br><span class="line"> <span class="type">int</span> dx = <span class="built_in">abs</span>(x1 - x0);</span><br><span class="line"> <span class="type">int</span> dy = <span class="built_in">abs</span>(y1 - y0);</span><br><span class="line"> <span class="type">int</span> sx = (x0 < x1) ? <span class="number">1</span> : <span class="number">-1</span>; <span class="comment">// X 方向步进</span></span><br><span class="line"> <span class="type">int</span> sy = (y0 < y1) ? <span class="number">1</span> : <span class="number">-1</span>; <span class="comment">// Y 方向步进</span></span><br><span class="line"> <span class="type">int</span> err = dx - dy; <span class="comment">// 初始误差项</span></span><br><span class="line"></span><br><span class="line"> <span class="built_in">glBegin</span>(GL_POINTS);</span><br><span class="line"> <span class="keyword">while</span> (<span class="literal">true</span>) {</span><br><span class="line"> <span class="built_in">glVertex2i</span>(x0, y0); <span class="comment">// 绘制当前点</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (x0 == x1 && y0 == y1) <span class="keyword">break</span>; <span class="comment">// 到达终点</span></span><br><span class="line"></span><br><span class="line"> <span class="type">int</span> e2 = <span class="number">2</span> * err;</span><br><span class="line"> <span class="comment">// 判断是否在 X 方向步进</span></span><br><span class="line"> <span class="keyword">if</span> (e2 > -dy) {</span><br><span class="line"> err -= dy;</span><br><span class="line"> x0 += sx;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 判断是否在 Y 方向步进</span></span><br><span class="line"> <span class="keyword">if</span> (e2 < dx) {</span><br><span class="line"> err += dx;</span><br><span class="line"> y0 += sy;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">glEnd</span>();</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// 渲染回调</span></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">display</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="built_in">glClear</span>(GL_COLOR_BUFFER_BIT);</span><br><span class="line"> <span class="built_in">glColor3f</span>(<span class="number">0.0f</span>, <span class="number">0.8f</span>, <span class="number">0.4f</span>); <span class="comment">// 设置一个好看的绿色(类似你图中的图标颜色)</span></span><br><span class="line"></span><br><span class="line"> <span class="comment">// 绘制几条不同方向的线来测试算法的健壮性</span></span><br><span class="line"> <span class="built_in">drawLineBresenham</span>(<span class="number">50</span>, <span class="number">50</span>, <span class="number">450</span>, <span class="number">400</span>); <span class="comment">// 第一象限</span></span><br><span class="line"> <span class="built_in">drawLineBresenham</span>(<span class="number">50</span>, <span class="number">400</span>, <span class="number">450</span>, <span class="number">50</span>); <span class="comment">// 第四象限</span></span><br><span class="line"> <span class="built_in">drawLineBresenham</span>(<span class="number">250</span>, <span class="number">50</span>, <span class="number">250</span>, <span class="number">450</span>); <span class="comment">// 垂直线</span></span><br><span class="line"> <span class="built_in">drawLineBresenham</span>(<span class="number">50</span>, <span class="number">250</span>, <span class="number">450</span>, <span class="number">250</span>); <span class="comment">// 水平线</span></span><br><span class="line"></span><br><span class="line"> <span class="built_in">glFlush</span>();</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">init</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="built_in">glClearColor</span>(<span class="number">0.1f</span>, <span class="number">0.1f</span>, <span class="number">0.1f</span>, <span class="number">1.0f</span>); <span class="comment">// 深色背景</span></span><br><span class="line"> <span class="built_in">glMatrixMode</span>(GL_PROJECTION);</span><br><span class="line"> <span class="built_in">glLoadIdentity</span>();</span><br><span class="line"> <span class="built_in">gluOrtho2D</span>(<span class="number">0</span>, <span class="number">500</span>, <span class="number">0</span>, <span class="number">500</span>); <span class="comment">// 建立 500x500 的直角坐标系</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span>** argv)</span> </span>{</span><br><span class="line"> <span class="built_in">glutInit</span>(&argc, argv);</span><br><span class="line"> <span class="built_in">glutInitDisplayMode</span>(GLUT_SINGLE | GLUT_RGB);</span><br><span class="line"> <span class="built_in">glutInitWindowSize</span>(<span class="number">600</span>, <span class="number">600</span>);</span><br><span class="line"> <span class="built_in">glutCreateWindow</span>(<span class="string">"Bresenham Line Algorithm"</span>);</span><br><span class="line"> <span class="built_in">init</span>();</span><br><span class="line"> <span class="built_in">glutDisplayFunc</span>(display);</span><br><span class="line"> <span class="built_in">glutMainLoop</span>();</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure></article><div class="post-copyright"><div class="post-copyright__author"><span class="post-copyright-meta"><i class="fas fa-circle-user fa-fw"></i>文章作者: </span><span class="post-copyright-info"><a href="https://blog.biss.click">biss</a></span></div><div class="post-copyright__type"><span class="post-copyright-meta"><i class="fas fa-square-arrow-up-right fa-fw"></i>文章链接: </span><span class="post-copyright-info"><a href="https://blog.biss.click/posts/7207243b/">https://blog.biss.click/posts/7207243b/</a></span></div><div class="post-copyright__notice"><span class="post-copyright-meta"><i class="fas fa-circle-exclamation fa-fw"></i>版权声明: </span><span class="post-copyright-info">本博客所有文章除特别声明外,均采用 <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/" target="_blank">CC BY-NC-SA 4.0</a> 许可协议。转载请注明来源 <a href="https://blog.biss.click" target="_blank">Bi's Blog</a>!</span></div></div><div class="tag_share"><div class="post-meta__tag-list"><a class="post-meta__tags" href="/tags/OpenGL/">OpenGL</a></div><div class="post-share"><style>#web-share-btn {
|
||
background: var(--btn-bg);
|
||
color: var(--btn-color);
|
||
border: none;
|
||
padding: 0.5rem 1rem;
|
||
border-radius: 8px;
|
||
cursor: pointer;
|
||
transition: all 0.3s;
|
||
}
|
||
#web-share-btn:hover {
|
||
background: var(--btn-hover-color);
|
||
}
|
||
</style><div id="web-share-component"><button id="web-share-btn" title="分享本文"><i class="fas fa-share-alt"></i><span> 分享</span></button></div><script>(() => {
|
||
const setupWebShare = () => {
|
||
const btn = document.getElementById('web-share-btn')
|
||
if (!btn) return
|
||
|
||
// 点击事件处理
|
||
btn.addEventListener('click', async () => {
|
||
if (navigator.share) {
|
||
try {
|
||
await navigator.share({
|
||
title: 'OpenGL-直线的扫描转换',
|
||
text: '...',
|
||
url: window.location.href
|
||
})
|
||
} catch (err) {
|
||
console.log('分享取消或失败', err)
|
||
}
|
||
} else {
|
||
// 降级处理:比如弹出提示或复制链接
|
||
const shareData = window.location.href
|
||
navigator.clipboard.writeText(shareData).then(() => {
|
||
btf.snackbarShow('系统不支持分享,已将链接复制到剪贴板')
|
||
})
|
||
}
|
||
})
|
||
}
|
||
|
||
// 考虑到 Butterfly 的 Pjax 跳转,需要重新绑定
|
||
setupWebShare()
|
||
document.addEventListener('pjax:complete', setupWebShare)
|
||
})()</script></div></div><nav class="pagination-post" id="pagination"><a class="pagination-related full-width" href="/posts/437a5198/" title="OpenGL-基础程序"><img class="cover" src="https://pic.biss.click/image/2fcb9566-f7f6-4132-81cb-4cd646967519.webp" onerror="onerror=null;src='/img/404.jpg'" alt="cover of next post"><div class="info text-right"><div class="info-1"><div class="info-item-1">下一篇</div><div class="info-item-2">OpenGL-基础程序</div></div><div class="info-2"><div class="info-item-1">代码展示我们先从基本的OpenGL程序开始吧,这是一个简单的OpenGL程序: 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354#include<GL/glut.h>using namespace std;// 回调函数void myDisplay(){ // 清除缓冲区 glClearColor(0.0, 0.0, 0.0, 0.0); glClear(GL_COLOR_BUFFER_BIT); // 正交模式 glMatrixMode(GL_PROJECTION); gluOrtho2D(0.0, 500.0, 0.0, 500.0); glColor4f(0.0, 1.0, 0.0, 0.0); glRectf(50.0, 50.0, 400.0, 400.0); // 划线 glColor3f(1.0, 1.0, 0.0); glBegin(GL_LINES); glVertex2f(50.0, 50....</div></div></div></a></nav><div class="relatedPosts"><div class="headline"><i class="fas fa-thumbs-up fa-fw"></i><span>相关推荐</span></div><div class="relatedPosts-list"><a class="pagination-related" href="/posts/c4477b0c/" title="配置OpenGL环境"><img class="cover" src="https://pic.biss.click/image/d19b9e03-9442-4b85-94a0-a3780b9f4440.webp" alt="cover"><div class="info text-center"><div class="info-1"><div class="info-item-1"><i class="far fa-calendar-alt fa-fw"></i> 2026-04-02</div><div class="info-item-2">配置OpenGL环境</div></div><div class="info-2"><div class="info-item-1">最近要学计算机图形学,所以会用到OpenGL,配置环境有点繁琐,记录了下来。 安装Visual Studio现在我们先来安装Visual Studio:visual studio,下载后安装即可|在安装时选择“使用C++的桌面开发”,这样安装时就会安装C++的编译器了。 安装 Cmake这个可选,因为我们可以使用Visual Studio的编译器MSVC来编译项目。Cmake是一个开源的跨平台软件构建工具,它可以生成不同系统的构建文件,比如Makefile,Ninja,VS项目文件等等。我们可以下载Cmake:cmake,下载后安装即可。 安装GLFWOpenGL有许多工具,比如GLFW,GLEW等等,这里我们安装GLFW。 工具 类别 主要职责 特点 GLUT 窗口管理 + 工具库 创建窗口、处理鼠标键盘、提供内置渲染循环。 古老、简单。使用“固定管线”(老旧技术),适合教学。 GLFW 窗口管理库 创建窗口、处理输入、管理多个上下文。 现代、轻量。只管窗口和输入,不负责渲染逻辑,是目前的主流。 GLAD 配置/加载库 加载 OpenGL 函数指针...</div></div></div></a><a class="pagination-related" href="/posts/437a5198/" title="OpenGL-基础程序"><img class="cover" src="https://pic.biss.click/image/2fcb9566-f7f6-4132-81cb-4cd646967519.webp" alt="cover"><div class="info text-center"><div class="info-1"><div class="info-item-1"><i class="far fa-calendar-alt fa-fw"></i> 2026-04-11</div><div class="info-item-2">OpenGL-基础程序</div></div><div class="info-2"><div class="info-item-1">代码展示我们先从基本的OpenGL程序开始吧,这是一个简单的OpenGL程序: 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354#include<GL/glut.h>using namespace std;// 回调函数void myDisplay(){ // 清除缓冲区 glClearColor(0.0, 0.0, 0.0, 0.0); glClear(GL_COLOR_BUFFER_BIT); // 正交模式 glMatrixMode(GL_PROJECTION); gluOrtho2D(0.0, 500.0, 0.0, 500.0); glColor4f(0.0, 1.0, 0.0, 0.0); glRectf(50.0, 50.0, 400.0, 400.0); // 划线 glColor3f(1.0, 1.0, 0.0); glBegin(GL_LINES); glVertex2f(50.0, 50....</div></div></div></a></div></div><hr class="custom-hr"><div id="post-comment"><div class="comment-head"><div class="comment-headline"><i class="fas fa-comments fa-fw"></i><span> 评论</span></div></div><div class="comment-wrap"><div><div id="twikoo-wrap"></div></div></div></div></div><div class="aside-content" id="aside-content"><div class="card-widget card-info text-center"><div class="avatar-img"><img src="https://free.picui.cn/free/2025/08/10/689845496a283.png" onerror="this.onerror=null;this.src='/img/friend_404.gif'" alt="avatar"></div><div class="author-info-name">biss</div><div class="author-info-description"></div><div class="site-data"><a href="/archives/"><div class="headline">文章</div><div class="length-num">38</div></a><a href="/tags/"><div class="headline">标签</div><div class="length-num">12</div></a><a href="/categories/"><div class="headline">分类</div><div class="length-num">6</div></a></div><a id="card-info-btn" target="_blank" rel="noopener" href="https://github.com/bishshi"><i class="fab fa-github"></i><span>Follow Me</span></a><div class="card-info-social-icons"><a class="social-icon" href="https://github.com/bishshi" target="_blank" title="Github"><i class="fab fa-github" style="color: #24292e;"></i></a><a class="social-icon" href="mailto:bishsh2006@gmail.com" target="_blank" title="Email"><i class="fas fa-envelope" style="color: #4a7dbe;"></i></a></div></div><div class="card-widget card-announcement"><div class="item-headline"><i class="fas fa-bullhorn fa-shake"></i><span>公告</span></div><div class="announcement_content"></div><div id="welcome-ip-location-info"></div></div><div class="card-widget" id="card-poem"><div id="poem_sentence"></div><div id="poem_info"><div id="poem_dynasty"></div><div id="poem_author"></div></div></div><script src="https://cdn.liumingye.cn/npm/js-heo@1.0.11/poem/jinrishici.js" charset="utf-8"></script><script type="text/javascript">jinrishici.load(function(result) {
|
||
var sentence = document.querySelector("#poem_sentence")
|
||
var author = document.querySelector("#poem_author")
|
||
var dynasty = document.querySelector("#poem_dynasty")
|
||
var sentenceText = result.data.content
|
||
sentenceText = sentenceText.substr(0, sentenceText.length - 1);
|
||
sentence.innerHTML = sentenceText
|
||
dynasty.innerHTML = result.data.origin.dynasty
|
||
author.innerHTML = result.data.origin.author + '《' + result.data.origin.title + '》'
|
||
});</script><div class="sticky_layout"><div class="card-widget" id="card-toc"><div class="item-headline"><i class="fas fa-stream"></i><span>目录</span><span class="toc-percentage"></span></div><div class="toc-content"><ol class="toc"><li class="toc-item toc-level-1"><a class="toc-link" href="#DDA%E6%95%B0%E5%80%BC%E5%BE%AE%E5%88%86%E7%BA%BF%E6%AE%B5%E7%AE%97%E6%B3%95"><span class="toc-number">1.</span> <span class="toc-text">DDA数值微分线段算法</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%AE%97%E6%B3%95%E7%AE%80%E4%BB%8B"><span class="toc-number">1.1.</span> <span class="toc-text">算法简介</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%AE%97%E6%B3%95%E5%AE%9E%E7%8E%B0"><span class="toc-number">1.2.</span> <span class="toc-text">算法实现</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#%E4%B8%AD%E7%82%B9%E7%94%BB%E7%BA%BF%E7%AE%97%E6%B3%95"><span class="toc-number">2.</span> <span class="toc-text">中点画线算法</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%AE%97%E6%B3%95%E7%AE%80%E4%BB%8B-1"><span class="toc-number">2.1.</span> <span class="toc-text">算法简介</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%AE%97%E6%B3%95%E5%AE%9E%E7%8E%B0-1"><span class="toc-number">2.2.</span> <span class="toc-text">算法实现</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#Bresenham%E7%AE%97%E6%B3%95"><span class="toc-number">3.</span> <span class="toc-text">Bresenham算法</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%AE%97%E6%B3%95%E7%AE%80%E4%BB%8B-2"><span class="toc-number">3.1.</span> <span class="toc-text">算法简介</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%AE%97%E6%B3%95%E5%AE%9E%E7%8E%B0-2"><span class="toc-number">3.2.</span> <span class="toc-text">算法实现</span></a></li></ol></li></ol></div></div><div class="card-widget card-post-series"><div class="item-headline"><i class="fa-solid fa-layer-group"></i><span>系列文章</span></div><div class="aside-list"><div class="aside-list-item"><a class="thumbnail" href="/posts/7207243b/" title="OpenGL-直线的扫描转换"><img src="https://pic.biss.click/image/c5457adc-214c-4a18-9aa6-43fbc0bfc2f4.webp" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="OpenGL-直线的扫描转换"></a><div class="content"><a class="title" href="/posts/7207243b/" title="OpenGL-直线的扫描转换">OpenGL-直线的扫描转换</a><time datetime="2026-04-11T11:01:02.000Z" title="发表于 2026-04-11 19:01:02">2026-04-11</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/posts/437a5198/" title="OpenGL-基础程序"><img src="https://pic.biss.click/image/2fcb9566-f7f6-4132-81cb-4cd646967519.webp" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="OpenGL-基础程序"></a><div class="content"><a class="title" href="/posts/437a5198/" title="OpenGL-基础程序">OpenGL-基础程序</a><time datetime="2026-04-11T10:20:34.000Z" title="发表于 2026-04-11 18:20:34">2026-04-11</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/posts/c4477b0c/" title="配置OpenGL环境"><img src="https://pic.biss.click/image/d19b9e03-9442-4b85-94a0-a3780b9f4440.webp" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="配置OpenGL环境"></a><div class="content"><a class="title" href="/posts/c4477b0c/" title="配置OpenGL环境">配置OpenGL环境</a><time datetime="2026-04-01T20:52:16.000Z" title="发表于 2026-04-02 04:52:16">2026-04-02</time></div></div></div></div><div class="card-widget card-recent-post"><div class="item-headline"><i class="fas fa-history"></i><span>最新文章</span></div><div class="aside-list"><div class="aside-list-item"><a class="thumbnail" href="/posts/7207243b/" title="OpenGL-直线的扫描转换"><img src="https://pic.biss.click/image/c5457adc-214c-4a18-9aa6-43fbc0bfc2f4.webp" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="OpenGL-直线的扫描转换"></a><div class="content"><a class="title" href="/posts/7207243b/" title="OpenGL-直线的扫描转换">OpenGL-直线的扫描转换</a><time datetime="2026-04-11T11:01:02.000Z" title="发表于 2026-04-11 19:01:02">2026-04-11</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/posts/437a5198/" title="OpenGL-基础程序"><img src="https://pic.biss.click/image/2fcb9566-f7f6-4132-81cb-4cd646967519.webp" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="OpenGL-基础程序"></a><div class="content"><a class="title" href="/posts/437a5198/" title="OpenGL-基础程序">OpenGL-基础程序</a><time datetime="2026-04-11T10:20:34.000Z" title="发表于 2026-04-11 18:20:34">2026-04-11</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/posts/c4477b0c/" title="配置OpenGL环境"><img src="https://pic.biss.click/image/d19b9e03-9442-4b85-94a0-a3780b9f4440.webp" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="配置OpenGL环境"></a><div class="content"><a class="title" href="/posts/c4477b0c/" title="配置OpenGL环境">配置OpenGL环境</a><time datetime="2026-04-01T20:52:16.000Z" title="发表于 2026-04-02 04:52:16">2026-04-02</time></div></div><div class="aside-list-item no-cover"><div class="content"><a class="title" href="/posts/b559997d/" title="opencv应用-算术运算">opencv应用-算术运算</a><time datetime="2026-03-17T05:13:08.000Z" title="发表于 2026-03-17 13:13:08">2026-03-17</time></div></div><div class="aside-list-item no-cover"><div class="content"><a class="title" href="/posts/e8f95ead/" title="opencv应用-基础操作">opencv应用-基础操作</a><time datetime="2026-03-15T01:56:51.000Z" title="发表于 2026-03-15 09:56:51">2026-03-15</time></div></div></div></div></div></div></main><footer id="footer"><div class="footer-other"><div class="footer-copyright"><span class="copyright">© 2025 - 2026 By biss</span><span class="framework-info"><span>框架 </span><a target="_blank" rel="noopener" href="https://hexo.io">Hexo</a><span class="footer-separator">|</span><span>主题 </span><a target="_blank" rel="noopener" href="https://github.com/jerryc127/hexo-theme-butterfly">Butterfly</a></span></div><div class="footer_custom_text"><p> <a style="margin-inline:5px" target="_blank" href="https://hexo.io/zh-cn/"><img src="https://img.shields.io/badge/Frame-Hexo-blue?style=flat&logo=hexo" title="hexo 8.1"></a> <a style="margin-inline:5px" target="_blank" href="https://butterfly.js.org"><img src="https://img.shields.io/badge/Theme-Butterfly-pink?style=flat" title="butterfly主题"></a> <a style="margin-inline:5px" target="_blank" href="https://creativecommons.org/licenses/by-nc-sa/4.0/"><img src="https://img.shields.io/badge/Copyright-BY--NC--SA-red?style=flat&logo=alchemy" title="CC BY-NC-SA 4.0"></a> <a href="https://www.trustssl.cc/ipv6.php?domain=blog.biss.click" title="本站已支持IPv6访问" target="_blank"><img src="https://static.coolcdn.cn/images/ipv6.svg"></a> </p></div></div></footer></div><div id="rightside"><div id="rightside-config-hide"><button id="readmode" type="button" title="阅读模式"><i class="fas fa-book-open"></i></button><button id="translateLink" type="button" title="简繁转换">繁</button><button id="darkmode" type="button" title="日间和夜间模式切换"><i class="fas fa-adjust"></i></button><button id="hide-aside-btn" type="button" title="单栏和双栏切换"><i class="fas fa-arrows-alt-h"></i></button></div><div id="rightside-config-show"><button id="rightside-config" type="button" title="设置"><i class="fas fa-cog fa-spin"></i></button><button class="close" id="mobile-toc-button" type="button" title="目录"><i class="fas fa-list-ul"></i></button><a id="to_comment" href="#post-comment" title="前往评论"><i class="fas fa-comments"></i></a><button id="go-up" type="button" title="回到顶部"><span class="scroll-percent"></span><i class="fas fa-arrow-up"></i></button></div></div><div><script src="/js/utils.js"></script><script src="/js/main.js"></script><script src="/js/tw_cn.js"></script><script src="https://unpkg.com/@fancyapps/ui/dist/fancybox/fancybox.umd.js"></script><script src="https://unpkg.com/node-snackbar/dist/snackbar.min.js"></script><div class="js-pjax"><script>(() => {
|
||
const loadMathjax = () => {
|
||
if (!window.MathJax) {
|
||
window.MathJax = {
|
||
loader: {
|
||
load: [
|
||
// Four font extension packages (optional)
|
||
//- '[tex]/bbm',
|
||
//- '[tex]/bboldx',
|
||
//- '[tex]/dsfont',
|
||
'[tex]/mhchem'
|
||
],
|
||
paths: {
|
||
'mathjax-newcm': '[mathjax]/../@mathjax/mathjax-newcm-font',
|
||
|
||
//- // Four font extension packages (optional)
|
||
//- 'mathjax-bbm-extension': '[mathjax]/../@mathjax/mathjax-bbm-font-extension',
|
||
//- 'mathjax-bboldx-extension': '[mathjax]/../@mathjax/mathjax-bboldx-font-extension',
|
||
//- 'mathjax-dsfont-extension': '[mathjax]/../@mathjax/mathjax-dsfont-font-extension',
|
||
'mathjax-mhchem-extension': '[mathjax]/../@mathjax/mathjax-mhchem-font-extension'
|
||
}
|
||
},
|
||
output: {
|
||
font: 'mathjax-newcm',
|
||
},
|
||
tex: {
|
||
inlineMath: [['$', '$'], ['\\(', '\\)']],
|
||
tags: 'none',
|
||
packages: {
|
||
'[+]': [
|
||
'mhchem'
|
||
]
|
||
}
|
||
},
|
||
chtml: {
|
||
scale: 1.1
|
||
},
|
||
options: {
|
||
enableMenu: true,
|
||
menuOptions: {
|
||
settings: {
|
||
enrich: false // Turn off Braille and voice narration text automatic generation
|
||
}
|
||
},
|
||
renderActions: {
|
||
findScript: [10, doc => {
|
||
for (const node of document.querySelectorAll('script[type^="math/tex"]')) {
|
||
const display = !!node.type.match(/; *mode=display/)
|
||
const math = new doc.options.MathItem(node.textContent, doc.inputJax[0], display)
|
||
const text = document.createTextNode('')
|
||
node.parentNode.replaceChild(text, node)
|
||
math.start = {node: text, delim: '', n: 0}
|
||
math.end = {node: text, delim: '', n: 0}
|
||
doc.math.push(math)
|
||
}
|
||
}, '']
|
||
}
|
||
}
|
||
}
|
||
|
||
const script = document.createElement('script')
|
||
script.src = 'https://unpkg.com/mathjax/tex-mml-chtml.js'
|
||
script.id = 'MathJax-script'
|
||
script.async = true
|
||
document.head.appendChild(script)
|
||
} else {
|
||
MathJax.startup.document.state(0)
|
||
MathJax.texReset()
|
||
MathJax.typesetPromise()
|
||
}
|
||
}
|
||
|
||
btf.addGlobalFn('encrypt', loadMathjax, 'mathjax')
|
||
window.pjax ? loadMathjax() : window.addEventListener('load', loadMathjax)
|
||
})()</script><script>(() => {
|
||
const applyThemeDefaultsConfig = theme => {
|
||
if (theme === 'dark-mode') {
|
||
Chart.defaults.color = "rgba(255, 255, 255, 0.8)"
|
||
Chart.defaults.borderColor = "rgba(255, 255, 255, 0.2)"
|
||
Chart.defaults.scale.ticks.backdropColor = "transparent"
|
||
} else {
|
||
Chart.defaults.color = "rgba(0, 0, 0, 0.8)"
|
||
Chart.defaults.borderColor = "rgba(0, 0, 0, 0.1)"
|
||
Chart.defaults.scale.ticks.backdropColor = "transparent"
|
||
}
|
||
}
|
||
|
||
// Recursively traverse the config object and automatically apply theme-specific color schemes
|
||
const applyThemeConfig = (obj, theme) => {
|
||
if (typeof obj !== 'object' || obj === null) return
|
||
|
||
Object.keys(obj).forEach(key => {
|
||
const value = obj[key]
|
||
// If the property is an object and has theme-specific options, apply them
|
||
if (typeof value === 'object' && value !== null) {
|
||
if (value[theme]) {
|
||
obj[key] = value[theme] // Apply the value for the current theme
|
||
} else {
|
||
// Recursively process child objects
|
||
applyThemeConfig(value, theme)
|
||
}
|
||
}
|
||
})
|
||
}
|
||
|
||
const runChartJS = ele => {
|
||
window.loadChartJS = true
|
||
|
||
Array.from(ele).forEach((item, index) => {
|
||
const chartSrc = item.firstElementChild
|
||
const chartID = item.getAttribute('data-chartjs-id') || ('chartjs-' + index) // Use custom ID or default ID
|
||
const width = item.getAttribute('data-width')
|
||
const existingCanvas = document.getElementById(chartID)
|
||
|
||
// If a canvas already exists, remove it to avoid rendering duplicates
|
||
if (existingCanvas) {
|
||
existingCanvas.parentNode.remove()
|
||
}
|
||
|
||
const chartDefinition = chartSrc.textContent
|
||
const canvas = document.createElement('canvas')
|
||
canvas.id = chartID
|
||
|
||
const div = document.createElement('div')
|
||
div.className = 'chartjs-wrap'
|
||
|
||
if (width) {
|
||
div.style.width = width
|
||
}
|
||
|
||
div.appendChild(canvas)
|
||
chartSrc.insertAdjacentElement('afterend', div)
|
||
|
||
const ctx = document.getElementById(chartID).getContext('2d')
|
||
|
||
const config = JSON.parse(chartDefinition)
|
||
|
||
const theme = document.documentElement.getAttribute('data-theme') === 'dark' ? 'dark-mode' : 'light-mode'
|
||
|
||
// Set default styles (initial setup)
|
||
applyThemeDefaultsConfig(theme)
|
||
|
||
// Automatically traverse the config and apply dual-mode color schemes
|
||
applyThemeConfig(config, theme)
|
||
|
||
new Chart(ctx, config)
|
||
})
|
||
}
|
||
|
||
const loadChartJS = () => {
|
||
const chartJSEle = document.querySelectorAll('#article-container .chartjs-container')
|
||
if (chartJSEle.length === 0) return
|
||
|
||
window.loadChartJS ? runChartJS(chartJSEle) : btf.getScript('https://unpkg.com/chart.js/dist/chart.umd.js').then(() => runChartJS(chartJSEle))
|
||
}
|
||
|
||
// Listen for theme change events
|
||
btf.addGlobalFn('themeChange', loadChartJS, 'chartjs')
|
||
btf.addGlobalFn('encrypt', loadChartJS, 'chartjs')
|
||
|
||
window.pjax ? loadChartJS() : document.addEventListener('DOMContentLoaded', loadChartJS)
|
||
})()</script><script>(() => {
|
||
const isShuoshuo = GLOBAL_CONFIG_SITE.pageType === 'shuoshuo'
|
||
const option = null
|
||
|
||
const getCount = () => {
|
||
const countELement = document.getElementById('twikoo-count')
|
||
if(!countELement) return
|
||
twikoo.getCommentsCount({
|
||
envId: 'https://comment.biss.click',
|
||
region: '',
|
||
urls: [window.location.pathname],
|
||
includeReply: false
|
||
}).then(res => {
|
||
countELement.textContent = res[0].count
|
||
}).catch(err => {
|
||
console.error(err)
|
||
})
|
||
}
|
||
|
||
const init = (el = document, path = location.pathname) => {
|
||
twikoo.init({
|
||
el: el.querySelector('#twikoo-wrap'),
|
||
envId: 'https://comment.biss.click',
|
||
region: '',
|
||
onCommentLoaded: () => {
|
||
btf.loadLightbox(document.querySelectorAll('#twikoo .tk-content img:not(.tk-owo-emotion)'))
|
||
},
|
||
...option,
|
||
path: isShuoshuo ? path : (option && option.path) || path
|
||
})
|
||
|
||
GLOBAL_CONFIG_SITE.pageType === 'post' && getCount()
|
||
|
||
isShuoshuo && (window.shuoshuoComment.destroyTwikoo = () => {
|
||
if (el.children.length) {
|
||
el.innerHTML = ''
|
||
el.classList.add('no-comment')
|
||
}
|
||
})
|
||
}
|
||
|
||
const loadTwikoo = (el, path) => {
|
||
if (typeof twikoo === 'object') setTimeout(() => init(el, path), 0)
|
||
else btf.getScript('https://unpkg.com/twikoo/dist/twikoo.min.js').then(() => init(el, path))
|
||
}
|
||
|
||
if (isShuoshuo) {
|
||
'Twikoo' === 'Twikoo'
|
||
? window.shuoshuoComment = { loadComment: loadTwikoo }
|
||
: window.loadOtherComment = loadTwikoo
|
||
return
|
||
}
|
||
|
||
if ('Twikoo' === 'Twikoo' || !false) {
|
||
if (false) btf.loadComment(document.getElementById('twikoo-wrap'), loadTwikoo)
|
||
else loadTwikoo()
|
||
} else {
|
||
window.loadOtherComment = loadTwikoo
|
||
}
|
||
})()</script></div><script src="https://code.jquery.com/jquery-4.0.0.min.js"></script><script src="/js/random.js"></script><script src="/js/shuoshuoshouye.js"></script><script src="/js/ai-summary.js"></script><script src="/js/search/typesense-search.js"></script><script src="/js/footer.js" <script=""></script><script src="https://cdn.jsdmirror.com/gh/bishshi/welcomemessage/txmap.js"></script><script src="https://cdn.jsdmirror.com/gh/bishshi/rightmenu@1.2/rightmenu.js"></script><script src="https://cdn.jsdmirror.com/gh/bishshi/sidecalendar@latest/calendar.js"></script><script src="https://cdn.jsdmirror.com/npm/chinese-lunar@0.1.4/lib/chinese-lunar.js"></script><script src="https://cdn.jsdmirror.com/npm/instantsearch.js@4.56.0"></script><script src="https://cdn.jsdmirror.com/npm/typesense-instantsearch-adapter@2.7.0/dist/typesense-instantsearch-adapter.min.js"></script><script src="https://unpkg.com/pjax/pjax.min.js" defer="defer"></script><script>document.addEventListener('DOMContentLoaded', () => {
|
||
const pjaxSelectors = ["head > title","#config-diff","#body-wrap","#rightside-config-hide","#rightside-config-show",".js-pjax"]
|
||
|
||
window.pjax = new Pjax({
|
||
elements: 'a:not([target="_blank"])',
|
||
selectors: pjaxSelectors,
|
||
cacheBust: false,
|
||
analytics: false,
|
||
scrollRestoration: false
|
||
})
|
||
|
||
const triggerPjaxFn = (val) => {
|
||
if (!val) return
|
||
Object.values(val).forEach(fn => {
|
||
try {
|
||
fn()
|
||
} catch (err) {
|
||
console.debug('Pjax callback failed:', err)
|
||
}
|
||
})
|
||
}
|
||
|
||
document.addEventListener('pjax:send', () => {
|
||
// removeEventListener
|
||
btf.removeGlobalFnEvent('pjaxSendOnce')
|
||
btf.removeGlobalFnEvent('themeChange')
|
||
|
||
// reset readmode
|
||
const $bodyClassList = document.body.classList
|
||
if ($bodyClassList.contains('read-mode')) $bodyClassList.remove('read-mode')
|
||
|
||
triggerPjaxFn(window.globalFn.pjaxSend)
|
||
})
|
||
|
||
document.addEventListener('pjax:complete', () => {
|
||
btf.removeGlobalFnEvent('pjaxCompleteOnce')
|
||
document.querySelectorAll('script[data-pjax]').forEach(item => {
|
||
const newScript = document.createElement('script')
|
||
const content = item.text || item.textContent || item.innerHTML || ""
|
||
Array.from(item.attributes).forEach(attr => newScript.setAttribute(attr.name, attr.value))
|
||
newScript.appendChild(document.createTextNode(content))
|
||
item.parentNode.replaceChild(newScript, item)
|
||
})
|
||
|
||
triggerPjaxFn(window.globalFn.pjaxComplete)
|
||
})
|
||
|
||
document.addEventListener('pjax:error', e => {
|
||
if (e.request.status === 404) {
|
||
true
|
||
? pjax.loadUrl('/404.html')
|
||
: window.location.href = e.request.responseURL
|
||
}
|
||
})
|
||
})</script></div><div class="js-pjax" id="rightMenu"><div class="rightMenu-group rightMenu-small"><a class="rightMenu-item" href="javascript:window.history.back();"><i class="fa fa-arrow-left"></i></a><a class="rightMenu-item" href="javascript:window.history.forward();"><i class="fa fa-arrow-right"></i></a><a class="rightMenu-item" href="javascript:window.location.reload();"><i class="fa fa-refresh"></i></a><a class="rightMenu-item" href="javascript:window.scrollTo(0, 0);"><i class="fa fa-arrow-up"></i></a></div><div class="rightMenu-group rightMenu-line hide" id="menu-text"><a class="rightMenu-item" href="javascript:rmf.copySelect();"><i class="fa fa-copy"></i><span>复制</span></a><a class="rightMenu-item" href="javascript:rmf.searchinThisPage();"><i class="fas fa-search"></i><span>站内搜索</span></a></div><div class="rightMenu-group rightMenu-line hide" id="menu-too"><a class="rightMenu-item" href="javascript:window.open(window.getSelection().toString());window.location.reload();"><i class="fa fa-link"></i><span>转到链接</span></a></div><div class="rightMenu-group rightMenu-line hide" id="menu-paste"><a class="rightMenu-item" href="javascript:rmf.paste()"><i class="fa fa-copy"></i><span>粘贴</span></a></div><div class="rightMenu-group rightMenu-line hide" id="menu-post"><a class="rightMenu-item" href="javascript:rmf.copyWordsLink()"><i class="fa fa-link"></i><span>复制本文地址</span></a></div><div class="rightMenu-group rightMenu-line hide" id="menu-to"><a class="rightMenu-item" href="javascript:rmf.openWithNewTab()"><i class="fa fa-window-restore"></i><span>新窗口打开</span></a><a class="rightMenu-item" href="javascript:rmf.open()"><i class="fa fa-link"></i><span>转到链接</span></a><a class="rightMenu-item" href="javascript:rmf.copyLink()"><i class="fa fa-copy"></i><span>复制链接</span></a></div><div class="rightMenu-group rightMenu-line hide" id="menu-img"><a class="rightMenu-item" href="javascript:rmf.saveAs()"><i class="fa fa-download"></i><span>保存图片</span></a><a class="rightMenu-item" href="javascript:rmf.openWithNewTab()"><i class="fa fa-window-restore"></i><span>在新窗口打开</span></a><a class="rightMenu-item" href="javascript:rmf.click()"><i class="fa fa-arrows-alt"></i><span>全屏显示</span></a><a class="rightMenu-item" href="javascript:rmf.copyLink()"><i class="fa fa-copy"></i><span>复制图片链接</span></a></div><div class="rightMenu-group rightMenu-line"><a class="rightMenu-item" href="javascript:randomPost()"><i class="fa fa-paper-plane"></i><span>随便逛逛</span></a><a class="rightMenu-item" href="javascript:rmf.switchDarkMode();"><i class="fa fa-moon"></i><span>昼夜切换</span></a><a class="rightMenu-item" href="javascript:rmf.translate();"><i class="iconfont icon-fanti"></i><span>繁简转换</span></a><a class="rightMenu-item" href="javascript:rmf.switchReadMode();"><i class="fa fa-book"></i><span>阅读模式</span></a><a class="rightMenu-item" href="javascript:pjax.loadUrl("/privacy/");"><i class="fa fa-info-circle"></i><span>隐私声明</span></a><a class="rightMenu-item" href="javascript:pjax.loadUrl("/cookie/");"><i class="fa fa-info-circle"></i><span>Cookie协议</span></a><a class="rightMenu-item" href="javascript:pjax.loadUrl("/cc/");"><i class="fa fa-info-circle"></i><span>版权声明</span></a></div></div><!-- hexo injector body_end start --><script data-pjax="">
|
||
function butterfly_swiper_injector_config(){
|
||
var parent_div_git = document.getElementById('recent-posts');
|
||
var item_html = '<div class="recent-post-item" style="height: auto;width: 100%"><div class="blog-slider swiper-container-fade swiper-container-horizontal" id="swiper_container"><div class="blog-slider__wrp swiper-wrapper" style="transition-duration: 0ms;"><div class="blog-slider__item swiper-slide" style="background:url(https://pic.biss.click/image/fca16741-64fa-495b-aa5e-a2ef077461ef.webp);border-radius:12px;opacity: 1; transform: translate3d(0px, 0px, 0px); transition-duration: 0ms;"><div class="blog-slider__content"><span class="blog-slider__code">2026-02-23</span><a class="blog-slider__title" onclick="pjax.loadUrl("posts/56f57c0b/");" href="javascript:void(0);" alt="">自建renovate-bot</a><div class="blog-slider__text">还不知道怎么描述哦</div></div></div><div class="blog-slider__item swiper-slide" style="background:url(https://pic.biss.click/image/63a5c345-cb40-4e92-bc7b-7dc4daaf5b74.webp);border-radius:12px;opacity: 1; transform: translate3d(0px, 0px, 0px); transition-duration: 0ms;"><div class="blog-slider__content"><span class="blog-slider__code">2025-09-28</span><a class="blog-slider__title" onclick="pjax.loadUrl("posts/b57500e9/");" href="javascript:void(0);" alt="">在Openwrt上安装AdguardHome</a><div class="blog-slider__text">还不知道怎么描述哦</div></div></div><div class="blog-slider__item swiper-slide" style="background:url(https://pic.biss.click/image/961bc881-cb0a-4ab7-ace5-9990e71c30a0.webp);border-radius:12px;opacity: 1; transform: translate3d(0px, 0px, 0px); transition-duration: 0ms;"><div class="blog-slider__content"><span class="blog-slider__code">2026-02-07</span><a class="blog-slider__title" onclick="pjax.loadUrl("posts/34725d47/");" href="javascript:void(0);" alt="">安装gitea</a><div class="blog-slider__text">还不知道怎么描述哦</div></div></div></div><div class="blog-slider__pagination swiper-pagination-clickable swiper-pagination-bullets"></div><div class="swiper-button-prev"></div><div class="swiper-button-next"></div></div></div>';
|
||
console.log('已挂载butterfly_swiper')
|
||
parent_div_git.insertAdjacentHTML("afterbegin",item_html)
|
||
}
|
||
var elist = 'undefined'.split(',');
|
||
var cpage = location.pathname;
|
||
var epage = '/';
|
||
var flag = 0;
|
||
|
||
for (var i=0;i<elist.length;i++){
|
||
if (cpage.includes(elist[i])){
|
||
flag++;
|
||
}
|
||
}
|
||
|
||
if ((epage ==='all')&&(flag == 0)){
|
||
butterfly_swiper_injector_config();
|
||
}
|
||
else if (epage === cpage){
|
||
butterfly_swiper_injector_config();
|
||
}
|
||
</script><script defer="" src="https://cdnjs.cloudflare.com/ajax/libs/Swiper/5.4.5/js/swiper.min.js"></script><script defer="" data-pjax="" src="https://npm.elemecdn.com/hexo-butterfly-swiper-lyx/lib/swiper_init.js"></script><!-- hexo injector body_end end --></body></html> |