用 three.js 绘制三维带箭头线 (线内箭头)
在LineMaterial.js基础上修改的ArrowLineMaterial.js代码:

/**
* @author WestLangley / http://github.com/WestLangley
*
* parameters = {
* color: <hex>,
* linewidth: <float>,
* dashed: <boolean>,
* dashScale: <float>,
* dashSize: <float>,
* gapSize: <float>,
* resolution: <Vector2>, // to be set by renderer
* }
*/ import {
ShaderLib,
ShaderMaterial,
UniformsLib,
UniformsUtils,
Vector2
} from "../build/three.module.js"; UniformsLib.line = { linewidth: { value: 1 },
resolution: { value: new Vector2(1, 1) },
dashScale: { value: 1 },
dashSize: { value: 1 },
gapSize: { value: 1 } // todo FIX - maybe change to totalSize }; ShaderLib['line'] = { uniforms: UniformsUtils.merge([
UniformsLib.common,
UniformsLib.fog,
UniformsLib.line
]), vertexShader:
`
#include <common>
#include <color_pars_vertex>
#include <fog_pars_vertex>
#include <logdepthbuf_pars_vertex>
#include <clipping_planes_pars_vertex> uniform float linewidth;
uniform vec2 resolution; attribute vec3 instanceStart;
attribute vec3 instanceEnd; attribute vec3 instanceColorStart;
attribute vec3 instanceColorEnd; varying vec2 vUv; varying float lineLength; #ifdef USE_DASH uniform float dashScale;
attribute float instanceDistanceStart;
attribute float instanceDistanceEnd;
varying float vLineDistance; #endif void trimSegment( const in vec4 start, inout vec4 end ) { // trim end segment so it terminates between the camera plane and the near plane // conservative estimate of the near plane
float a = projectionMatrix[ 2 ][ 2 ]; // 3nd entry in 3th column
float b = projectionMatrix[ 3 ][ 2 ]; // 3nd entry in 4th column
float nearEstimate = - 0.5 * b / a; float alpha = ( nearEstimate - start.z ) / ( end.z - start.z ); end.xyz = mix( start.xyz, end.xyz, alpha ); } void main() { #ifdef USE_COLOR vColor.xyz = ( position.y < 0.5 ) ? instanceColorStart : instanceColorEnd; #endif #ifdef USE_DASH vLineDistance = ( position.y < 0.5 ) ? dashScale * instanceDistanceStart : dashScale * instanceDistanceEnd; #endif float aspect = resolution.x / resolution.y; vUv = uv; // camera space
vec4 start = modelViewMatrix * vec4( instanceStart, 1.0 );
vec4 end = modelViewMatrix * vec4( instanceEnd, 1.0 ); // special case for perspective projection, and segments that terminate either in, or behind, the camera plane
// clearly the gpu firmware has a way of addressing this issue when projecting into ndc space
// but we need to perform ndc-space calculations in the shader, so we must address this issue directly
// perhaps there is a more elegant solution -- WestLangley bool perspective = ( projectionMatrix[ 2 ][ 3 ] == - 1.0 ); // 4th entry in the 3rd column if ( perspective ) { if ( start.z < 0.0 && end.z >= 0.0 ) { trimSegment( start, end ); } else if ( end.z < 0.0 && start.z >= 0.0 ) { trimSegment( end, start ); } } // clip space
vec4 clipStart = projectionMatrix * start;
vec4 clipEnd = projectionMatrix * end; // ndc space
vec2 ndcStart = clipStart.xy / clipStart.w;
vec2 ndcEnd = clipEnd.xy / clipEnd.w; // direction
vec2 dir = ndcEnd - ndcStart; // account for clip-space aspect ratio
dir.x *= aspect;
dir = normalize( dir ); // perpendicular to dir
vec2 offset = vec2( dir.y, - dir.x ); // undo aspect ratio adjustment
dir.x /= aspect;
offset.x /= aspect; // sign flip
if ( position.x < 0.0 ) offset *= - 1.0; // endcaps
if ( position.y < 0.0 ) { offset += - dir; } else if ( position.y > 1.0 ) { offset += dir; } // adjust for linewidth
offset *= linewidth; // adjust for clip-space to screen-space conversion // maybe resolution should be based on viewport ...
offset /= resolution.y; // select end
vec4 clip = ( position.y < 0.5 ) ? clipStart : clipEnd; // back to clip space
offset *= clip.w; clip.xy += offset; gl_Position = clip; vec4 mvPosition = ( position.y < 0.5 ) ? start : end; // this is an approximation //lineLength = distance(ndcStart, ndcEnd);
lineLength = distance(ndcStart, ndcEnd) * (1.57 + abs(atan(dir.x / dir.y))) / 2.0;
//lineLength = distance(clipStart.xyz, clipEnd.xyz);
//lineLength = distance(start.xyz, end.xyz); #include <logdepthbuf_vertex>
#include <clipping_planes_vertex>
#include <fog_vertex> }
`, fragmentShader:
`
uniform vec3 diffuse;
uniform float opacity;
uniform sampler2D map; varying float lineLength; #ifdef USE_DASH uniform float dashSize;
uniform float gapSize; #endif varying float vLineDistance; #include <common>
#include <color_pars_fragment>
#include <fog_pars_fragment>
#include <logdepthbuf_pars_fragment>
#include <clipping_planes_pars_fragment> varying vec2 vUv; void main() { #include <clipping_planes_fragment> #ifdef USE_DASH if ( vUv.y < - 1.0 || vUv.y > 1.0 ) discard; // discard endcaps if ( mod( vLineDistance, dashSize + gapSize ) > dashSize ) discard; // todo - FIX #endif if ( abs( vUv.y ) > 1.0 ) { float a = vUv.x;
float b = ( vUv.y > 0.0 ) ? vUv.y - 1.0 : vUv.y + 1.0;
float len2 = a * a + b * b; if ( len2 > 1.0 ) discard;
} vec4 diffuseColor = vec4( diffuse, opacity ); #include <logdepthbuf_fragment>
#include <color_fragment> vec4 c; if ( abs( vUv.y ) > 1.0 ) {
c = vec4(diffuseColor.rgb, diffuseColor.a);
} else {
vec2 rpt = vec2(0.5, 1.0); rpt.y *= lineLength * 5.0;
//rpt.y *= lineLength / 500.0; rpt.y = floor(rpt.y + 0.5);
if(rpt.y < 1.0) { rpt.y = 1.0; }
if(rpt.y > 5.0) { rpt.y = 5.0; }
c = vec4(1.0, 1.0, 1.0, 1.0);
c *= texture2D( map, vUv * rpt );
} gl_FragColor = c; //#include <premultiplied_alpha_fragment>
//#include <tonemapping_fragment>
//#include <encodings_fragment>
//#include <fog_fragment> }
`
}; var ArrowLineMaterial = function (parameters) { ShaderMaterial.call(this, { type: 'ArrowLineMaterial', uniforms: Object.assign({}, UniformsUtils.clone(ShaderLib['line'].uniforms), {
map: { value: null },
}), vertexShader: ShaderLib['line'].vertexShader,
fragmentShader: ShaderLib['line'].fragmentShader, clipping: true // required for clipping support }); this.dashed = false; Object.defineProperties(this, { map: { enumerable: true, get: function () { return this.uniforms.map.value; }, set: function (value) { this.uniforms.map.value = value; } }, color: { enumerable: true, get: function () { return this.uniforms.diffuse.value; }, set: function (value) { this.uniforms.diffuse.value = value; } }, linewidth: { enumerable: true, get: function () { return this.uniforms.linewidth.value; }, set: function (value) { this.uniforms.linewidth.value = value; } }, dashScale: { enumerable: true, get: function () { return this.uniforms.dashScale.value; }, set: function (value) { this.uniforms.dashScale.value = value; } }, dashSize: { enumerable: true, get: function () { return this.uniforms.dashSize.value; }, set: function (value) { this.uniforms.dashSize.value = value; } }, gapSize: { enumerable: true, get: function () { return this.uniforms.gapSize.value; }, set: function (value) { this.uniforms.gapSize.value = value; } }, resolution: { enumerable: true, get: function () { return this.uniforms.resolution.value; }, set: function (value) { this.uniforms.resolution.value.copy(value); } } }); this.setValues(parameters); }; ArrowLineMaterial.prototype = Object.create(ShaderMaterial.prototype);
ArrowLineMaterial.prototype.constructor = ArrowLineMaterial; ArrowLineMaterial.prototype.isLineMaterial = true; export { ArrowLineMaterial };
ArrowLineMaterial.js中主要修改部分:
在顶点着色器中定义变量:

varying float lineLength;
在顶点着色器中计算一下线的长度:

lineLength = distance(ndcStart, ndcEnd) * (1.57 + abs(atan(dir.x / dir.y))) / 2.0;
在片元着色器中定义变量:

uniform sampler2D map;
varying float lineLength;
在片元着色器中贴图:

vec4 c;
if ( abs( vUv.y ) > 1.0 ) {
c = vec4(diffuseColor.rgb, diffuseColor.a);
} else {
vec2 rpt = vec2(0.5, 1.0);
rpt.y *= lineLength * 5.0;
//rpt.y *= lineLength / 500.0;
rpt.y = floor(rpt.y + 0.5);
if(rpt.y < 1.0) { rpt.y = 1.0; }
if(rpt.y > 5.0) { rpt.y = 5.0; }
c = vec4(1.0, 1.0, 1.0, 1.0);
c *= texture2D( map, vUv * rpt );
}
gl_FragColor = c;
在片元着色器中注释掉下面几行,使线的颜色和canvas中设置的颜色一致:

//#include <premultiplied_alpha_fragment>
//#include <tonemapping_fragment>
//#include <encodings_fragment>
//#include <fog_fragment>
CanvasDraw.js代码:

/**
* canvas绘图
*/ let CanvasDraw = function () { /**
* 画文本和气泡
*/
this.drawText = function (THREE, renderer, text, width) {
let canvas = document.createElement("canvas");
let ctx = canvas.getContext('2d'); canvas.width = width * 2;
canvas.height = width * 2; this.drawBubble(ctx, width - 10, width - 65, width, 45, 6, "#00c864"); //设置文字
ctx.fillStyle = "#ffffff";
ctx.font = '32px 宋体';
ctx.fillText(text, width - 10 + 12, width - 65 + 34); let canvasTexture = new THREE.CanvasTexture(canvas);
canvasTexture.magFilter = THREE.NearestFilter;
canvasTexture.minFilter = THREE.NearestFilter; let maxAnisotropy = renderer.capabilities.getMaxAnisotropy();
canvasTexture.anisotropy = maxAnisotropy; return canvasTexture;
} /**
* 画箭头
*/
this.drawArrow = function (THREE, renderer, width, height) {
let canvas = document.createElement("canvas");
let ctx = canvas.getContext('2d'); canvas.width = width;
canvas.height = height; ctx.save(); ctx.translate(0, 0); //this.drawRoundRectPath(ctx, width, height, 0); //ctx.fillStyle = "#ffff00";
//ctx.fill(); this.drawArrowBorder(ctx, 2, 0, 0, 4, 100, 50, 0, 96, 2, 100, 300, 50);
ctx.fillStyle = "#ffffff";
ctx.fill(); ctx.restore(); let canvasTexture = new THREE.CanvasTexture(canvas);
canvasTexture.magFilter = THREE.NearestFilter;
canvasTexture.minFilter = THREE.NearestFilter; let maxAnisotropy = renderer.capabilities.getMaxAnisotropy();
canvasTexture.anisotropy = maxAnisotropy; return canvasTexture;
} /**
* 画线内箭头
*/
this.drawArrow3 = function (THREE, renderer, width, height, color) {
let canvas = document.createElement("canvas");
let ctx = canvas.getContext('2d'); canvas.width = width;
canvas.height = height; ctx.save(); ctx.translate(0, 0); this.drawRoundRectPath(ctx, width, height, 0); ctx.fillStyle = color;
ctx.fill(); this.drawArrowBorder(ctx, 0, 350, 0, 400, 50, 450, 100, 400, 100, 350, 50, 400);
ctx.fillStyle = "#ffffff";
ctx.fill(); ctx.restore(); let canvasTexture = new THREE.CanvasTexture(canvas);
canvasTexture.magFilter = THREE.NearestFilter;
canvasTexture.minFilter = THREE.NearestFilter;
canvasTexture.wrapS = THREE.RepeatWrapping;
canvasTexture.wrapT = THREE.RepeatWrapping; let maxAnisotropy = renderer.capabilities.getMaxAnisotropy();
canvasTexture.anisotropy = maxAnisotropy; return canvasTexture;
} /**
* 画气泡
*/
this.drawBubble = function (ctx, x, y, width, height, radius, fillColor) {
ctx.save(); ctx.translate(x, y); this.drawRoundRectPath(ctx, width, height, radius); ctx.fillStyle = fillColor || "#000";
ctx.fill(); this.drawTriangle(ctx, 20, height, 40, height, 10, 65);
ctx.fillStyle = fillColor || "#000";
ctx.fill(); ctx.restore();
} /**
* 画三角形
*/
this.drawTriangle = function (ctx, x1, y1, x2, y2, x3, y3) {
ctx.beginPath(); ctx.moveTo(x1, y1);
ctx.lineTo(x2, y2);
ctx.lineTo(x3, y3); ctx.closePath();
} /**
* 画箭头边框
*/
this.drawArrowBorder = function (ctx, x1, y1, x2, y2, x3, y3, x4, y4, x5, y5, x6, y6) {
ctx.beginPath(); ctx.moveTo(x1, y1);
ctx.lineTo(x2, y2);
ctx.lineTo(x3, y3);
ctx.lineTo(x4, y4);
ctx.lineTo(x5, y5);
ctx.lineTo(x6, y6); ctx.closePath();
} /**
* 画圆角矩形
*/
this.drawRoundRectPath = function (ctx, width, height, radius) {
ctx.beginPath(0); //从右下角顺时针绘制,弧度从0到1/2PI
ctx.arc(width - radius, height - radius, radius, 0, Math.PI / 2); //矩形下边线
ctx.lineTo(radius, height); //左下角圆弧,弧度从1/2PI到PI
ctx.arc(radius, height - radius, radius, Math.PI / 2, Math.PI); //矩形左边线
ctx.lineTo(0, radius); //左上角圆弧,弧度从PI到3/2PI
ctx.arc(radius, radius, radius, Math.PI, Math.PI * 3 / 2); //上边线
ctx.lineTo(width - radius, 0); //右上角圆弧
ctx.arc(width - radius, radius, radius, Math.PI * 3 / 2, Math.PI * 2); //右边线
ctx.lineTo(width, height - radius); ctx.closePath();
} /**
* 画圆
*/
this.drawCircle = function (THREE, renderer, width, height, radius, fillColor) {
let canvas = document.createElement("canvas");
let ctx = canvas.getContext('2d'); canvas.width = width;
canvas.height = height; ctx.save(); ctx.beginPath(0); ctx.arc(width / 2, height / 2, radius, 0, 2 * Math.PI); ctx.closePath(); ctx.fillStyle = fillColor || "#000";
ctx.fill(); ctx.restore(); let texture = new THREE.CanvasTexture(canvas);
texture.needsUpdate = true; texture.magFilter = THREE.NearestFilter;
texture.minFilter = THREE.NearestFilter; let maxAnisotropy = renderer.capabilities.getMaxAnisotropy();
texture.anisotropy = maxAnisotropy; return texture;
} } CanvasDraw.prototype.constructor = CanvasDraw; export { CanvasDraw }
DrawPath2.js代码:

/**
* 绘制路线
*/ import * as THREE from '../build/three.module.js'; import { Line2 } from '../js/lines/Line2.js';
import { LineGeometry } from '../js/lines/LineGeometry.js'; import { CanvasDraw } from '../js.my/CanvasDraw.js';
import { ArrowLineMaterial } from '../js.my/ArrowLineMaterial.js'; import { Utils } from '../js.my/Utils.js';
import { Msg } from '../js.my/Msg.js'; let DrawPath2 = function () { let _self = this; let _canvasDraw = new CanvasDraw();
let utils = new Utils();
let msg = new Msg(); this._isDrawing = false;
this._path = [];
this._lines = [];
this.color = '#00F300'; this._depthTest = true;
this._hide = false; let _side = 0; let viewerContainerId = '#threeCanvas';
let viewerContainer = $(viewerContainerId)[0]; let objects;
let camera;
let turn;
let scene; this.config = function (objects_, camera_, scene_, turn_) {
objects = objects_;
camera = camera_;
turn = turn_;
scene = scene_; this._oldDistance = 1;
this._oldCameraPos = { x: camera.position.x, y: camera.position.y, z: camera.position.z }
} this.start = function () {
if (!this._isDrawing) {
this._isDrawing = true;
viewerContainer.addEventListener('click', ray);
viewerContainer.addEventListener('mousedown', mousedown);
viewerContainer.addEventListener('mouseup', mouseup);
}
} this.stop = function () {
if (this._isDrawing) {
this._isDrawing = false;
viewerContainer.removeEventListener('click', ray);
viewerContainer.removeEventListener('mousedown', mousedown);
viewerContainer.removeEventListener('mouseup', mouseup);
}
} function mousedown(params) {
this._mousedownPosition = { x: camera.position.x, y: camera.position.y, z: camera.position.z }
} function mouseup(params) {
this._mouseupPosition = { x: camera.position.x, y: camera.position.y, z: camera.position.z }
} function ray(e) {
turn.unFocusButton(); let raycaster = createRaycaster(e.clientX, e.clientY);
let objs = [];
objects.all.map(object => {
if (object.material.visible) {
objs.push(object);
}
});
let intersects = raycaster.intersectObjects(objs);
if (intersects.length > 0) {
let point = intersects[0].point; let distance = utils.distance(this._mousedownPosition.x, this._mousedownPosition.y, this._mousedownPosition.z, this._mouseupPosition.x, this._mouseupPosition.y, this._mouseupPosition.z); if (distance < 5) {
_self._path.push({ x: point.x, y: point.y + 50, z: point.z }); if (_self._path.length > 1) {
let point1 = _self._path[_self._path.length - 2];
let point2 = _self._path[_self._path.length - 1]; drawLine(point1, point2);
}
}
}
} function createRaycaster(clientX, clientY) {
let x = (clientX / $(viewerContainerId).width()) * 2 - 1;
let y = -(clientY / $(viewerContainerId).height()) * 2 + 1; let standardVector = new THREE.Vector3(x, y, 0.5); let worldVector = standardVector.unproject(camera); let ray = worldVector.sub(camera.position).normalize(); let raycaster = new THREE.Raycaster(camera.position, ray); return raycaster;
} this.refresh = function () { } function drawLine(point1, point2) {
let n = Math.round(utils.distance(point1.x, point1.y, point1.z, point2.x, point2.y, point2.z) / 500);
if (n < 1) n = 1;
for (let i = 0; i < n; i++) {
let p1 = {};
p1.x = point1.x + (point2.x - point1.x) / n * i;
p1.y = point1.y + (point2.y - point1.y) / n * i;
p1.z = point1.z + (point2.z - point1.z) / n * i; let p2 = {};
p2.x = point1.x + (point2.x - point1.x) / n * (i + 1);
p2.y = point1.y + (point2.y - point1.y) / n * (i + 1);
p2.z = point1.z + (point2.z - point1.z) / n * (i + 1); drawLine2(p1, p2);
}
} function drawLine2(point1, point2) {
const positions = []; positions.push(point1.x / 50, point1.y / 50, point1.z / 50);
positions.push(point2.x / 50, point2.y / 50, point2.z / 50); let geometry = new LineGeometry();
geometry.setPositions(positions); geometry.setColors([
parseInt(_self.color.substr(1, 2), 16) / 256,
parseInt(_self.color.substr(3, 2), 16) / 256,
parseInt(_self.color.substr(5, 2), 16) / 256,
parseInt(_self.color.substr(1, 2), 16) / 256,
parseInt(_self.color.substr(3, 2), 16) / 256,
parseInt(_self.color.substr(5, 2), 16) / 256
]); let canvasTexture = _canvasDraw.drawArrow3(THREE, renderer, 100, 800, _self.color); //箭头 let matLine = new ArrowLineMaterial({
map: canvasTexture,
color: new THREE.Color(0xffffff),
linewidth: 0.005, // in world units with size attenuation, pixels otherwise
dashed: false,
depthTest: _self._depthTest,
side: _side,
vertexColors: THREE.VertexColors,
resolution: new THREE.Vector2(1, $(viewerContainerId).height() / $(viewerContainerId).width())
}); let line = new Line2(geometry, matLine);
line.computeLineDistances();
line.scale.set(50, 50, 50); scene.add(line);
_self._lines.push(line);
} this.setDepthTest = function (bl) {
if (bl) {
_self._depthTest = true;
this._lines.map(line => {
line.material.depthTest = true;
line.material.side = 0;
});
} else {
_self._depthTest = false;
this._lines.map(line => {
line.material.depthTest = false;
line.material.side = THREE.DoubleSide;
});
}
} this.getPath = function () {
return this._path;
} this.hide = function () {
this._lines.map(line => scene.remove(line));
this._hide = true;
} this.show = function () {
this._lines.map(line => scene.add(line));
this._hide = false;
} this.isShow = function () {
return !this._hide;
} this.create = function (path, color) {
_self.color = color;
_self._path = path; if (_self._path.length > 1) {
for (let i = 0; i < _self._path.length - 1; i++) {
let point1 = _self._path[i];
let point2 = _self._path[i + 1]; drawLine(point1, point2);
}
}
} this.getDepthTest = function () {
return _self._depthTest;
} this.undo = function () {
scene.remove(this._lines[this._lines.length - 1]);
_self._path.splice(this._path.length - 1, 1);
_self._lines.splice(this._lines.length - 1, 1);
} } DrawPath2.prototype.constructor = DrawPath2; export { DrawPath2 }
效果图:

缺陷:
2.5D视角观察,看着还行,但是把相机拉近观察,箭头就会变形。凑合着用。
箭头贴图变形或者箭头显示不全,原因我猜可能是因为在场景中,线的远离相机的一端,在标准设备坐标系中比较细,线的靠近相机的一端,在标准设备坐标系中比较粗,但为了使线的粗细一样,靠近相机的一端被裁剪了,所以箭头可能会显示不全。
不管是MeshLine还是three.js的Line2,这个带宽度的线,和三维场景中的三维模型是有区别的,无论场景拉近还是拉远,线的宽度不变,而三维模型场景拉远变小,拉近变大。
Drawing arrow lines is hard!

参考文章:
https://www.cnblogs.com/dojo-lzz/p/9219290.html
https://blog.csdn.net/Amesteur/article/details/95964526
用 three.js 绘制三维带箭头线 (线内箭头)的更多相关文章
- OpenLayer——绘制带箭头的线
绘制带箭头的线,计算相对复杂,多少是有点影响性能了.更简单的做法:初始.目标点用不同的点进行强调即可. <!DOCTYPE html> <html lang="en&quo ...
- 如何利用百度地图JSAPI画带箭头的线?
百度地图JSAPI提供两种绘制多折线的方式,一种是已知多折线经纬度坐标串通过AddOverlay接口进行添加:另一种是通过在地图上鼠标单击进行绘制(鼠标绘制工具条库).目前这两种方式只能绘制多折线,并 ...
- AE常用代码(标注要素、AE中画带箭头的线、如何获得投影坐标、参考坐标、投影方式、FeatureCount注意事项)
手上的电脑已经用了将近三年了,想入手一台Surface Pro,所以计划着把电脑上的资料整理下,部分资料打算发到博客上来,资料有同事.也有自己的.也有来自网络的,来源途径太多,也没法详细注明,请见谅! ...
- 使用原生JavaScript的Canvas实现拖拽式图形绘制,支持画笔、线条、箭头、三角形、矩形、平行四边形、梯形以及多边形和圆形,不依赖任何库和插件,有演示demo
前言 需要用到图形绘制,没有找到完整的图形绘制实现,所以自己实现了一个 - - 一.实现的功能 1.基于oop思想构建,支持坐标点.线条(由坐标点组成,包含方向).多边形(由多个坐标点组成).圆形(包 ...
- Matlab绘图基础——绘制三维表面
%绘制三维表面 ------------------------------------- %1.绘制线框图:mesh:每一条曲线称为mesh line %首先利用meshgrid函数产生平面区域内的 ...
- Matlab绘图基础——绘制三维曲线
%% 绘制三维曲线 %plot3函数,其中每一组x,y,z组成一组曲线的坐标参数,选项的定义和plot函数相同. %1.当x,y,z是同维向量时,则x,y,z 对应元素构成一条三维曲线. x0 = 0 ...
- three.js 3d三维网页代码加密的实现方法
http://www.jiamisoft.com/blog/17827-three-js-3dsanweiwangyejiami.html https://www.html5tricks.com/ta ...
- js 绘制数学函数
<!-- <!doctype html> --> <html lang="en"> <head> <meta charset= ...
- 使用Matlab绘制三维图的几种方法
以下六个函数都可以实现绘制三维图像: surf(xx,yy,zz); surfc(xx,yy,zz); mesh(xx,yy,zz); meshc(xx,yy,zz); meshz(xx,yy,zz) ...
- 【转】JS大总结(带实例)
JS大总结(带实例) JavaScript事务查询综合click() 对象.click() 使对象被点击.closed 对象.closed 对象窗口是否已封闭true/falseclearTimeou ...
随机推荐
- Mysql数据库查询之模糊查询
一.什么是模糊查询模糊查询是根据一定的模式匹配规则,查找与指定条件相似或相符的数据.二.模糊查询实操通配符查询1.% 表示任意0个或多个字符形式一: select 查询字段 from 表名 where ...
- Mysql报:error while loading shared libraries libtinfo.so.5的解决办法
版权声明:原创作品,谢绝转载!否则将追究法律责任. ----- 作者:kirin #.今天闲来无事,想在Anolis8的系统上装一个MySQL8.0玩.前期在安装和配置的过程中没有什么问题,但是在我想 ...
- HBuilderx 创建 、运行uniapp项目
uni-app官网介绍的 通过 HBuilderX 可视化界面 跟着小颖来创建一个自己的小程序 创建小程序 依次点击HBuilderx 左上方的按钮:文件->新建->项目 然后打开该界面, ...
- 09 - Shell流程控制语句
1. if-else语句 能够使用if条件语句进行条件判断 1.1 if 语法 if 条件 then 命令 fi if 条件; then 命令; fi 1.2 if-else 语法 if 条件 the ...
- 33. 干货系列从零用Rust编写正反向代理,关于HTTP客户端代理的源码实现
wmproxy wmproxy已用Rust实现http/https代理, socks5代理, 反向代理, 静态文件服务器,四层TCP/UDP转发,七层负载均衡,内网穿透,后续将实现websocket代 ...
- 吉特日化MES系统&生产工艺控制参数对照表
吉特日化MES生产工艺参数对照表 工艺编号 PROCE_BASE_TIMER 工艺名称 定时器 工艺说明 主要用于生产工艺步骤过程计时 参数编号 参数名称 参数描述 Prop_Timer_Enable ...
- 从零开始封装 vue 组件
对于学习 Vue 的同学来说,封装 vue 组件是实现代码复用的重要一环.在 Vue 官网中非常详细地介绍了 vue 组件的相关知识,我这里简单摘取使用最频繁的几个知识点,带大家快速入门 vue 组件 ...
- 如何开发一个ORM数据库框架
如何开发一个ORM框架 ORM(Object Relational Mapping)对象关系映射,ORM的数据库框架有hibernate,mybatis.我该如何开发一个类似这样的框架呢? 为什么会有 ...
- 5分钟就能实现的API监控,有什么理由不做呢?基调听云
API深度影响着你的应用 今天的数字应用世界其实是一个以API为中心的世界,我们只是没有意识到这些API的重要性.比如在电子商务交易.社交媒体等对交互高度依赖的领域,可以说API决定了应用的质量一点也 ...
- Programming Abstractions in C阅读笔记:p202-p234
<Programming Abstractions in C>学习第65天,p202-p234总结. 一.技术总结 完成第五章学习,第五章介绍递归在实际问题中的进一步应用,例如汉诺塔问题, ...