在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 绘制三维带箭头线 (线内箭头)的更多相关文章

  1. OpenLayer——绘制带箭头的线

    绘制带箭头的线,计算相对复杂,多少是有点影响性能了.更简单的做法:初始.目标点用不同的点进行强调即可. <!DOCTYPE html> <html lang="en&quo ...

  2. 如何利用百度地图JSAPI画带箭头的线?

    百度地图JSAPI提供两种绘制多折线的方式,一种是已知多折线经纬度坐标串通过AddOverlay接口进行添加:另一种是通过在地图上鼠标单击进行绘制(鼠标绘制工具条库).目前这两种方式只能绘制多折线,并 ...

  3. AE常用代码(标注要素、AE中画带箭头的线、如何获得投影坐标、参考坐标、投影方式、FeatureCount注意事项)

    手上的电脑已经用了将近三年了,想入手一台Surface Pro,所以计划着把电脑上的资料整理下,部分资料打算发到博客上来,资料有同事.也有自己的.也有来自网络的,来源途径太多,也没法详细注明,请见谅! ...

  4. 使用原生JavaScript的Canvas实现拖拽式图形绘制,支持画笔、线条、箭头、三角形、矩形、平行四边形、梯形以及多边形和圆形,不依赖任何库和插件,有演示demo

    前言 需要用到图形绘制,没有找到完整的图形绘制实现,所以自己实现了一个 - - 一.实现的功能 1.基于oop思想构建,支持坐标点.线条(由坐标点组成,包含方向).多边形(由多个坐标点组成).圆形(包 ...

  5. Matlab绘图基础——绘制三维表面

    %绘制三维表面 ------------------------------------- %1.绘制线框图:mesh:每一条曲线称为mesh line %首先利用meshgrid函数产生平面区域内的 ...

  6. Matlab绘图基础——绘制三维曲线

    %% 绘制三维曲线 %plot3函数,其中每一组x,y,z组成一组曲线的坐标参数,选项的定义和plot函数相同. %1.当x,y,z是同维向量时,则x,y,z 对应元素构成一条三维曲线. x0 = 0 ...

  7. three.js 3d三维网页代码加密的实现方法

    http://www.jiamisoft.com/blog/17827-three-js-3dsanweiwangyejiami.html https://www.html5tricks.com/ta ...

  8. js 绘制数学函数

    <!-- <!doctype html> --> <html lang="en"> <head> <meta charset= ...

  9. 使用Matlab绘制三维图的几种方法

    以下六个函数都可以实现绘制三维图像: surf(xx,yy,zz); surfc(xx,yy,zz); mesh(xx,yy,zz); meshc(xx,yy,zz); meshz(xx,yy,zz) ...

  10. 【转】JS大总结(带实例)

    JS大总结(带实例) JavaScript事务查询综合click() 对象.click() 使对象被点击.closed 对象.closed 对象窗口是否已封闭true/falseclearTimeou ...

随机推荐

  1. 字符串转换整数(atoi)(4.3leetcode每日打卡)

    一堆if不及python的一个正则表达式系列 请你来实现一个 atoi 函数,使其能将字符串转换成整数. 首先,该函数会根据需要丢弃无用的开头空格字符,直到寻找到第一个非空格的字符为止.接下来的转化规 ...

  2. H.264中的帧

    导言 高级视频编码 (AVC) 也称为 H.264,是使用最广泛的视频压缩标准.它与所有主要的流式传输协议和容器格式兼容. 当我们使用播放器播放一个视频时,通常会经过:解协议,解封装,音视频解码,音视 ...

  3. 用友U8+与百胜E3的数据对接:实现企业数字化业务的集成与协作

    用友U8+作为中国企业最佳经营管理平台之一,在企业经营管理中广泛应用.然而,由于每个企业的内部管理方式和流程各不相同,标准软件功能难以完全适应所有企业的管理需求.同时,随着互联网和移动应用的发展,对于 ...

  4. BI软件是什么?应用BI工具能给企业带来什么

    BI软件是指利用数据挖掘.分析和可视化等技术,将企业内部和外部数据转化为有价值的信息和洞察,以帮助企业支持业务决策和优化业务流程的工具和应用程序.常见的BI软件包括Datainside.QlikVie ...

  5. 基于DotNetty实现自动发布 - 自动检测代码变化

    前言 很抱歉没有实现上一篇的目标:一键发布,因为工作量超出了预期,本次只实现了 Git 代码变化检测 已完成的功能 解决方案的项目发现与配置 首次发布需要手动处理 自动检测代码变化并解析出待发布的文件 ...

  6. 基于Redis的简易延时队列

    基于Redis的简易延时队列 一.背景 在实际的业务场景中,经常会遇到需要延时处理的业务,比如订单超时未支付,需要取消订单,或者是用户注册后,需要在一段时间内激活账号,否则账号失效等等.这些业务场景都 ...

  7. smm整合

    配置整合 这个里面SpringConfig 就是书写Spring的配置类,其中加载了jdbc配置类和mybatis配置类,还加载了jdbc资源类. package com.itheima.config ...

  8. hszxoj 货车运输 [lca]

    题目链接: hszxoj 货车运输 题目描述与思路 简化题目: 求 \(x\)到 \(y\) 两点间路径的边权最小值的最大值 与之前的最短路最大的不同是这道题是多源最短路,那么 \(spfa\) 就废 ...

  9. u盘加密原理和实现步骤

    U盘加密原理:U盘加密的原理主要是通过对U盘存储的数据进行加密处理,确保只有经过授权的用户才能访问和解密数据.以下是一般的U盘加密原理: 加密算法: 使用强大的加密算法对U盘中的数据进行加密.常见的算 ...

  10. 如何通过port-forward命令在本地访问 k8s 集群服务

    公众号「架构成长指南」,专注于生产实践.云原生.分布式系统.大数据技术分享 概述 在我们访问k8s中的pod服务时,一般通过node port映射pod端口进行访问,还有一种是通过ingress或者i ...