Unity引擎绘制多边形属性图

  大家好,我是阿赵
  在制作游戏的时候,经常会遇到需要绘制多边形属性图的需求,比如这种效果:
可以根据需要的属性的数量变化多边形的边数,然后每一个顶点从中心点开始到多边形的顶点的长度代表了该属性的强度,然后多个属性的顶点连接起来形成一个多边形图形。
在这里插入图片描述

  这里介绍一下我自己的做法。

一、 需求拆分:

  需要做到上图的效果,可以拆分成几个部分

1、底板

在这里插入图片描述

  这一个图片,当然也可以用程序计算生成出来,但我个人觉得,这个底图除了会出现边数不一样以外,其他的样式差不多是固定的,而程序生成的图片可能没有美术做的底图好看,所以我是比较建议直接出图使用。如果需要换边数,可以直接换图

2、属性多边形

在这里插入图片描述

  这个形状是会根据属性的变化而变化的,所以是不能直接用美术出图的,必现要动态生成。既然是动态的绘制多边形,所以用到的知识点肯定是动态计算顶点和索引,构成Mesh网格来显示了。由于这个形状基本上都是用于UI的,所以不能直接用Mesh和MeshRenderer来渲染,我这里选择的是MaskableGraphic。
  MaskableGraphic可以直接在UI上通过顶点和索引绘制多边形。所以我们只需要固定一个中心点坐标,然后通过设置一些参数,比如:

  1. 边数
  2. 最大半径
  3. 颜色
  4. 属性的最大最小值
  5. 每一个边的当前值
  6. 等等
      然后根据参数计算几个顶点的坐标,再通过(中心点、当前顶点、下一个顶点)作为一个三角形的索引,就可以逐个三角形绘制出来了。最后指定颜色,半透明也是在颜色里面指定。

3、多边形描边

在这里插入图片描述

  这个的原理和上一步一样,都是使用MaskableGraphic来自定义顶点和索引绘制。
  可以设置的参数和上面绘制多边形基本一致,只需要加多:
1、 描边的厚度
2、 描边的颜色
  绘制描边的算法比绘制多边形本身复杂一些,我一开始想得简单,直接把多边形的半径扩大,然后往回减去描边厚度,来得到描边的一个角上的两个顶点。不过那样做是不行的,将会导致描边的线段不是均匀的厚度,到了尖角的地方会变得很厚。
  后来我还是老老实实的对多边形的每条边进行往内平移,并且求出每条平移后的线和下一条线的延伸线的交点,作为描边的第二层的顶点。然后如果有描边的情况下,多边形的顶点也是使用了描边的第二层的顶点,两者就完全接得上了。
  由于这个原因,所以需要求线段平移和交点的方法。

4、在编辑器调整效果

在这里插入图片描述

  最后,综合以上所述,在编辑器里面可以暴露这些参数,可以在做UI的时候就看到效果,并且用代码去设置。这里还有一个angle角度的变量,是用于旋转多边形的,因为有时候我们的需求多边形不一定是正上方有个顶点,可以是旋转一定角度。
  有一个isChange的变量,下面的代码里面会说到,只有在修改的情况下才会重新计算顶点。所以如果在编辑器的非运行状态下,可以手点一下激活,这样在调整参数的时候,画面就会立刻刷新变化。

二、 代码实现

1、 MaskableGraphic的基础代码

  使用MaskableGraphic之前介绍过,基础用法很简单,类继承MaskableGraphic,然后重写OnPopulateMesh方法,在里面输入顶点和索引列表。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;[RequireComponent(typeof(CanvasRenderer))][RequireComponent(typeof(RectTransform))]
public class UIPolyOutlineEx : MaskableGraphic
{private List<UIVertex> vertexList;private List<int> indexList;protected override void OnPopulateMesh(VertexHelper vh){vh.Clear();           if (vertexList != null && vertexList.Count > 0&&indexList!= null && indexList.Count > 0){vh.AddUIVertexStream(vertexList, indexList);}}
}

2、 设置变量

  根据刚才的分析,设置了变量

public int sideCount = 0;
public float radius = 100;
public float minVal = 0.1f;
public float maxVal = 1;
public float edgeLen = 10;
public float[] sideValueArr;
public float angle = 0;
public Color insideColor = Color.green;
public Color edgeColor = Color.black;public bool isChange = false;
private List<UIVertex> outlinePoints;
private List<UIVertex> insidePoints;
private List<UIVertex> vertexList;
private List<int> indexList;

3、 计算顶点

  需要根据参数,求出内部多边形和外部描边的顶点,中间还有一个平移线段的顶点信息,所以需要三个数组来计算。计算完之后,就把他们保存起来。这里我是直接保存成UIVertex的,由于描边和内部颜色不一样,所以UIVertex里面也记录了颜色,所以描边的顶点列表和内部的顶点列表是完全分开的,就算看着是同一个点,其实也是两边都保存。

    private void CreatePoints(){List<Vector2> outsidePoints = new List<Vector2>();List<Vector2> outsidePoints2 = new List<Vector2>();List<Vector2> moveLinePoints = new List<Vector2>();outlinePoints = new List<UIVertex>();insidePoints = new List<UIVertex>();if (sideCount < 3){return;}float offsetRate = edgeLen / radius;Rect rect = gameObject.GetComponent<RectTransform>().rect;UIVertex vex0 = UIVertex.simpleVert;vex0.position = new Vector3(rect.center.x, rect.center.y, 0);Vector3 uv0 = new Vector2(0.5f, 0.5f);vex0.uv0 = uv0;vex0.color = insideColor;insidePoints.Add(vex0);for (int i = 0; i < sideCount; i++){float val = 0;if (sideValueArr != null && i < sideValueArr.Length){val = sideValueArr[i];}else{val = 0;}float ang = 360f / sideCount * i + angle;ang = ang * Mathf.Deg2Rad;val = Mathf.Clamp(val, minVal, maxVal);float x = val * Mathf.Sin(ang);float y = val * Mathf.Cos(ang);outsidePoints.Add(new Vector2(x, y));}if (edgeLen <= 0){for (int i = 0; i < outsidePoints.Count; i++){UIVertex vex = UIVertex.simpleVert;vex.position = new Vector3(rect.center.x + outsidePoints[i].x * radius, rect.center.y + outsidePoints[i].y * radius, 0);Vector2 uv = new Vector2(outsidePoints[i].x, outsidePoints[i].y);uv *= 0.5f;uv += new Vector2(0.5f, 0.5f);vex.uv0 = uv;vex.color = insideColor;insidePoints.Add(vex);}}else{for (int i = 0; i < outsidePoints.Count; i++){Vector2 p0 = Vector2.zero;Vector2 p1 = outsidePoints[i];Vector2 p2;if (i < outsidePoints.Count - 1){p2 = outsidePoints[i + 1];}else{p2 = outsidePoints[0];}Vector2 foot = GetPointToLine(p0, p1, p2);Vector2 dir = p0 - foot;dir.Normalize();Vector2 p3 = p1 + dir * offsetRate;Vector2 p4 = p2 + dir * offsetRate;moveLinePoints.Add(p3);moveLinePoints.Add(p4);}for (int i = 0; i < outsidePoints.Count; i++){int ind1 = i * 2;int ind2 = i * 2 + 1;int ind3 = i * 2 - 2;int ind4 = i * 2 - 1;if (i == 0){ind3 = moveLinePoints.Count - 2;ind4 = moveLinePoints.Count - 1;}Vector2 crossPoint = GetLineCrossPoint(moveLinePoints[ind1], moveLinePoints[ind2], moveLinePoints[ind3], moveLinePoints[ind4]);print(moveLinePoints[ind1] * radius + "," + moveLinePoints[ind2] * radius + "|" + moveLinePoints[ind3] * radius + "," + moveLinePoints[ind4] * radius + "||" + crossPoint * radius);outsidePoints2.Add(crossPoint);}for (int i = 0; i < outsidePoints.Count; i++){UIVertex vex = UIVertex.simpleVert;vex.position = new Vector3(rect.center.x + outsidePoints2[i].x * radius, rect.center.y + outsidePoints2[i].y * radius, 0);Vector2 uv = new Vector2(outsidePoints2[i].x, outsidePoints2[i].y);uv *= 0.5f;uv += new Vector2(0.5f, 0.5f);vex.uv0 = uv;vex.color = insideColor;insidePoints.Add(vex);vex = UIVertex.simpleVert;vex.position = new Vector3(rect.center.x + outsidePoints[i].x * radius, rect.center.y + outsidePoints[i].y * radius, 0);uv = new Vector2(outsidePoints[i].x, outsidePoints[i].y);uv *= 0.5f;uv += new Vector2(0.5f, 0.5f);vex.uv0 = uv;vex.color = edgeColor;outlinePoints.Add(vex);vex = UIVertex.simpleVert;vex.position = new Vector3(rect.center.x + outsidePoints2[i].x * radius, rect.center.y + outsidePoints2[i].y * radius, 0);uv = new Vector2(outsidePoints2[i].x, outsidePoints2[i].y);uv *= 0.5f;uv += new Vector2(0.5f, 0.5f);vex.uv0 = uv;vex.color = edgeColor;outlinePoints.Add(vex);}}}private Vector2 GetPointToLine(Vector2 p0, Vector2 p1, Vector2 p2){Vector2 lineDir = p1 - p2;lineDir.Normalize();float x0 = p0.x;float y0 = p0.y;float x1 = p1.x;// -lineDir.x*10;float y1 = p1.y;// - lineDir.y * 10;float x2 = p2.x;// + lineDir.x * 10;float y2 = p2.y;// + lineDir.x * 10;if ((x1 == x0 && y1 == y0) || (x2 == x0 && y2 == y0)){return new Vector2(x0, y0);//点和线段一边重合}float k = 1;if (x1 != x2){k = (y2 - y1) / (x2 - x1);}float a = k;float b = -1;float c = y1 - k * x1;float d = Mathf.Abs(a * x0 + b * y0 + c) / Mathf.Sqrt(a * a + b * b);float px = (b * b * x0 - a * b * y0 - a * c) / (a * a + b * b);float py = (a * a * y0 - a * b * x0 - b * c) / (a * a + b * b);return new Vector2(px, py);}private Vector2 GetLineCrossPoint(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4){Vector2 dir1 = (p1 - p2).normalized;p1 += dir1;p2 -= dir1;Vector2 dir2 = (p3 - p4).normalized;p3 += dir2;p4 -= dir2;Vector2 bx = p4 - p3;float d1 = Mathf.Abs(CrossMulVec(bx, p1 - p3));float d2 = Mathf.Abs(CrossMulVec(bx, p2 - p3));float dx = d1 + d2;if (dx == 0){return p1;}float t = d1 / dx;Vector2 temp = (p2 - p1) * t;return p1 + temp;}private float CrossMulVec(Vector2 p1, Vector2 p2){return p1.x * p2.y - p2.x * p1.y;
}

4、 求构成多边形的点和索引

  由于绘制的时候,需要把描边和内部的所有顶点和索引合并在一起,所以这里需要再计算一次,把两个列表合并。

        private void CreateMeshParam(){vertexList = new List<UIVertex>();indexList = new List<int>();int insidePointCount = 0;if (insidePoints != null && insidePoints.Count > 0){insidePointCount = insidePoints.Count;for (int i = 0; i < insidePoints.Count; i++){vertexList.Add(insidePoints[i]);}List<int> tempList = new List<int>();if (sideCount > 2){int ind3 = 0;for (int i = 0; i < sideCount; i++){tempList.Add(0);tempList.Add(i + 1);ind3 = i + 2;if (ind3 > sideCount){ind3 = 1;}tempList.Add(ind3);}}indexList = tempList;}if (outlinePoints != null && outlinePoints.Count > 0){for (int i = 0; i < outlinePoints.Count; i++){vertexList.Add(outlinePoints[i]);}for (int i = 0; i < sideCount; i++){int ind1 = i * 2;int ind2 = i * 2 + 2;int ind3 = i * 2 + 1;int ind4 = i * 2 + 3;if (i == sideCount - 1){ind2 = 0;ind4 = 1;}indexList.Add(ind1 + insidePointCount);indexList.Add(ind2 + insidePointCount);indexList.Add(ind3 + insidePointCount);indexList.Add(ind3 + insidePointCount);indexList.Add(ind2 + insidePointCount);indexList.Add(ind4 + insidePointCount);}}}

5、 各种属性的GetSet

  在运行的时候,我们不会希望每一帧都需要重复去计算多边形的顶点和索引,希望只有参数变化的时候才重新计算。所以那些可以改变的参数,应该都做成GetSet方法,然后在Set方法的时候,把一个isChange的标记设置为true。那么当isChange为true的时候,才重新计算。

public void InitData(int sideCount,float r,float edge)
{SetSideCount(sideCount);radius = r;edgeLen = edge;isChange = true;
}
public void SetIsChange()
{isChange = true;
}
public void SetSideCount(int val)
{sideCount = val;float[] newArr = new float[val];if(sideValueArr!=null&&sideValueArr.Length>0){for(int i = 0;i<val;i++){if(sideValueArr.Length>val){newArr[i] = sideValueArr[i];}}}sideValueArr = newArr;isChange = true;
}public void SetValArr(float[] vals)
{if (sideValueArr == null){return;}for (int i = 0; i < sideValueArr.Length; i++){if (i < vals.Length){sideValueArr[i] = vals[i];}}isChange = true;
}public void SetOneVal(int index,float val)
{if(index<0){return;}if(sideValueArr != null&&sideValueArr.Length> index){sideValueArr[index] = val;}isChange = true;
}public void SetOneValByLua(double index, double val)
{int ind = Mathf.FloorToInt((float)index);float value = (float)val;SetOneVal(ind - 1, value);
}public void SetAngle(float ang)
{angle = ang;isChange = true;
}public void SetRange(float min,float max)
{minVal = min;maxVal = max;isChange = true;
}public void SetInsideColor(Color col)
{insideColor = col;isChange = true;
}public void SetOutlineColor(Color col)
{edgeColor = col;isChange = true;
}public void SetRadius(float val)
{radius = val;isChange = true;
}

  这是一个重新计算顶点和索引的方法,只有在isChange为true的时候,才会调用。

private void UpdatePoly()
{if (sideCount == 0){vertexList = null;return;}CreatePoints();CreateMeshParam();
}

6、 修改OnPopulateMesh方法

  在OnPopulateMesh里面判断isChange,然后调用UpdatePoly方法。

   protected override void OnPopulateMesh(VertexHelper vh){//base.OnPopulateMesh(vh);vh.Clear();if(isChange){UpdatePoly();if(Application.isPlaying)isChange = false;}if (vertexList != null && vertexList.Count > 0){vh.AddUIVertexStream(vertexList, indexList);}}

三、完整代码:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
namespace azhao
{[RequireComponent(typeof(CanvasRenderer))][RequireComponent(typeof(RectTransform))]public class UIPolyOutlineEx : MaskableGraphic{public int sideCount = 0;public float radius = 100;public float minVal = 0.1f;public float maxVal = 1;public float edgeLen = 10;public float[] sideValueArr;public float angle = 0;public Color insideColor = Color.green;public Color edgeColor = Color.black;public bool isChange = false;private List<UIVertex> outlinePoints;private List<UIVertex> insidePoints;private List<UIVertex> vertexList;private List<int> indexList;// Start is called before the first frame updateprivate new IEnumerator Start(){UpdatePoly();yield return null;}public void InitData(int sideCount,float r,float edge){SetSideCount(sideCount);radius = r;edgeLen = edge;isChange = true;}public void SetIsChange(){isChange = true;}public void SetSideCount(int val){sideCount = val;float[] newArr = new float[val];if(sideValueArr!=null&&sideValueArr.Length>0){for(int i = 0;i<val;i++){if(sideValueArr.Length>val){newArr[i] = sideValueArr[i];}}}sideValueArr = newArr;isChange = true;}public void SetValArr(float[] vals){if (sideValueArr == null){return;}for (int i = 0; i < sideValueArr.Length; i++){if (i < vals.Length){sideValueArr[i] = vals[i];}}isChange = true;}public void SetOneVal(int index,float val){if(index<0){return;}if(sideValueArr != null&&sideValueArr.Length> index){sideValueArr[index] = val;}isChange = true;}public void SetOneValByLua(double index, double val){int ind = Mathf.FloorToInt((float)index);float value = (float)val;SetOneVal(ind - 1, value);}public void SetAngle(float ang){angle = ang;isChange = true;}public void SetRange(float min,float max){minVal = min;maxVal = max;isChange = true;}public void SetInsideColor(Color col){insideColor = col;isChange = true;}public void SetOutlineColor(Color col){edgeColor = col;isChange = true;}public void SetRadius(float val){radius = val;isChange = true;}private void UpdatePoly(){if (sideCount == 0){vertexList = null;return;}CreatePoints();CreateMeshParam();}private void CreatePoints(){List<Vector2> outsidePoints = new List<Vector2>();List<Vector2> outsidePoints2 = new List<Vector2>();List<Vector2> moveLinePoints = new List<Vector2>();outlinePoints = new List<UIVertex>();insidePoints = new List<UIVertex>();if (sideCount < 3){return;}float offsetRate = edgeLen / radius;Rect rect = gameObject.GetComponent<RectTransform>().rect;UIVertex vex0 = UIVertex.simpleVert;vex0.position = new Vector3(rect.center.x, rect.center.y, 0);Vector3 uv0 = new Vector2(0.5f, 0.5f);vex0.uv0 = uv0;vex0.color = insideColor;insidePoints.Add(vex0);for (int i = 0; i < sideCount; i++){float val = 0;if (sideValueArr != null && i < sideValueArr.Length){val = sideValueArr[i];}else{val = 0;}float ang = 360f / sideCount * i + angle;ang = ang * Mathf.Deg2Rad;val = Mathf.Clamp(val, minVal, maxVal);float x = val * Mathf.Sin(ang);float y = val * Mathf.Cos(ang);outsidePoints.Add(new Vector2(x, y));}if (edgeLen <= 0){for (int i = 0; i < outsidePoints.Count; i++){UIVertex vex = UIVertex.simpleVert;vex.position = new Vector3(rect.center.x + outsidePoints[i].x * radius, rect.center.y + outsidePoints[i].y * radius, 0);Vector2 uv = new Vector2(outsidePoints[i].x, outsidePoints[i].y);uv *= 0.5f;uv += new Vector2(0.5f, 0.5f);vex.uv0 = uv;vex.color = insideColor;insidePoints.Add(vex);}}else{for (int i = 0; i < outsidePoints.Count; i++){Vector2 p0 = Vector2.zero;Vector2 p1 = outsidePoints[i];Vector2 p2;if (i < outsidePoints.Count - 1){p2 = outsidePoints[i + 1];}else{p2 = outsidePoints[0];}Vector2 foot = GetPointToLine(p0, p1, p2);Vector2 dir = p0 - foot;dir.Normalize();Vector2 p3 = p1 + dir * offsetRate;Vector2 p4 = p2 + dir * offsetRate;moveLinePoints.Add(p3);moveLinePoints.Add(p4);}for (int i = 0; i < outsidePoints.Count; i++){int ind1 = i * 2;int ind2 = i * 2 + 1;int ind3 = i * 2 - 2;int ind4 = i * 2 - 1;if (i == 0){ind3 = moveLinePoints.Count - 2;ind4 = moveLinePoints.Count - 1;}Vector2 crossPoint = GetLineCrossPoint(moveLinePoints[ind1], moveLinePoints[ind2], moveLinePoints[ind3], moveLinePoints[ind4]);print(moveLinePoints[ind1] * radius + "," + moveLinePoints[ind2] * radius + "|" + moveLinePoints[ind3] * radius + "," + moveLinePoints[ind4] * radius + "||" + crossPoint * radius);outsidePoints2.Add(crossPoint);}for (int i = 0; i < outsidePoints.Count; i++){UIVertex vex = UIVertex.simpleVert;vex.position = new Vector3(rect.center.x + outsidePoints2[i].x * radius, rect.center.y + outsidePoints2[i].y * radius, 0);Vector2 uv = new Vector2(outsidePoints2[i].x, outsidePoints2[i].y);uv *= 0.5f;uv += new Vector2(0.5f, 0.5f);vex.uv0 = uv;vex.color = insideColor;insidePoints.Add(vex);vex = UIVertex.simpleVert;vex.position = new Vector3(rect.center.x + outsidePoints[i].x * radius, rect.center.y + outsidePoints[i].y * radius, 0);uv = new Vector2(outsidePoints[i].x, outsidePoints[i].y);uv *= 0.5f;uv += new Vector2(0.5f, 0.5f);vex.uv0 = uv;vex.color = edgeColor;outlinePoints.Add(vex);vex = UIVertex.simpleVert;vex.position = new Vector3(rect.center.x + outsidePoints2[i].x * radius, rect.center.y + outsidePoints2[i].y * radius, 0);uv = new Vector2(outsidePoints2[i].x, outsidePoints2[i].y);uv *= 0.5f;uv += new Vector2(0.5f, 0.5f);vex.uv0 = uv;vex.color = edgeColor;outlinePoints.Add(vex);}}}private Vector2 GetPointToLine(Vector2 p0, Vector2 p1, Vector2 p2){Vector2 lineDir = p1 - p2;lineDir.Normalize();float x0 = p0.x;float y0 = p0.y;float x1 = p1.x;// -lineDir.x*10;float y1 = p1.y;// - lineDir.y * 10;float x2 = p2.x;// + lineDir.x * 10;float y2 = p2.y;// + lineDir.x * 10;if ((x1 == x0 && y1 == y0) || (x2 == x0 && y2 == y0)){return new Vector2(x0, y0);//点和线段一边重合}float k = 1;if (x1 != x2){k = (y2 - y1) / (x2 - x1);}float a = k;float b = -1;float c = y1 - k * x1;float d = Mathf.Abs(a * x0 + b * y0 + c) / Mathf.Sqrt(a * a + b * b);float px = (b * b * x0 - a * b * y0 - a * c) / (a * a + b * b);float py = (a * a * y0 - a * b * x0 - b * c) / (a * a + b * b);return new Vector2(px, py);}private Vector2 GetLineCrossPoint(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4){Vector2 dir1 = (p1 - p2).normalized;p1 += dir1;p2 -= dir1;Vector2 dir2 = (p3 - p4).normalized;p3 += dir2;p4 -= dir2;Vector2 bx = p4 - p3;float d1 = Mathf.Abs(CrossMulVec(bx, p1 - p3));float d2 = Mathf.Abs(CrossMulVec(bx, p2 - p3));float dx = d1 + d2;if (dx == 0){return p1;}float t = d1 / dx;Vector2 temp = (p2 - p1) * t;return p1 + temp;}private float CrossMulVec(Vector2 p1, Vector2 p2){return p1.x * p2.y - p2.x * p1.y;}private void CreateMeshParam(){vertexList = new List<UIVertex>();indexList = new List<int>();int insidePointCount = 0;if (insidePoints != null && insidePoints.Count > 0){insidePointCount = insidePoints.Count;for (int i = 0; i < insidePoints.Count; i++){vertexList.Add(insidePoints[i]);}List<int> tempList = new List<int>();if (sideCount > 2){int ind3 = 0;for (int i = 0; i < sideCount; i++){tempList.Add(0);tempList.Add(i + 1);ind3 = i + 2;if (ind3 > sideCount){ind3 = 1;}tempList.Add(ind3);}}indexList = tempList;}if (outlinePoints != null && outlinePoints.Count > 0){for (int i = 0; i < outlinePoints.Count; i++){vertexList.Add(outlinePoints[i]);}for (int i = 0; i < sideCount; i++){int ind1 = i * 2;int ind2 = i * 2 + 2;int ind3 = i * 2 + 1;int ind4 = i * 2 + 3;if (i == sideCount - 1){ind2 = 0;ind4 = 1;}indexList.Add(ind1 + insidePointCount);indexList.Add(ind2 + insidePointCount);indexList.Add(ind3 + insidePointCount);indexList.Add(ind3 + insidePointCount);indexList.Add(ind2 + insidePointCount);indexList.Add(ind4 + insidePointCount);}}}// Update is called once per framevoid Update(){}protected override void OnPopulateMesh(VertexHelper vh){//base.OnPopulateMesh(vh);vh.Clear();if(isChange){UpdatePoly();if(Application.isPlaying)isChange = false;}if (vertexList != null && vertexList.Count > 0){vh.AddUIVertexStream(vertexList, indexList);}}}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/145708.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

谈对象第二弹: C++类和对象(中)

文章目录 一、类的默认成员函数二、构造函数三、析构函数四、拷贝构造函数五、运算符重载5.1运算符重载5.2赋值运算符重载5.3实现日期类<<、>>重载检查、获取天数关系运算符重载算数、赋值运算符重载Date.hDate.cpp 六、取地址运算符重载6.1const成员函数6.2取地址…

docker部署excalidraw画图工具

0&#xff09;效果 0.1&#xff09;实时协作 0.2&#xff09;导出格式 1&#xff09;docker安装 docker脚本 bash <(curl -sSL https://cdn.jsdelivr.net/gh/SuperManito/LinuxMirrorsmain/DockerInstallation.sh)docker-compose脚本 curl -L "https://github.com/…

Dynaform 5.9.4简体中文版百度云下载(含教程)

如大家所了解的&#xff0c;Dynaform是一种基于有限元分析&#xff08;FEA&#xff09;技术的计算机辅助工程&#xff08;CAE&#xff09;软件&#xff0c;常常用于模拟和优化各种工业应用中的结构和流体问题。 目前常用的版本为Dynaform 5.9.4&#xff0c;可以模拟机械结构、…

第314题|参考!如何做到【一题多解】|武忠祥老师每日一题

解析&#xff1a; 画出图像&#xff1a; 观察选项可知&#xff1a;选项A和选项B是相反选项&#xff0c;因此答案只能在AB当中。 因此本题我们只需要算出和的大小即可。 方法一&#xff1a;直接相减然后判断结果的正负。 分析题目给的条件&#xff1a;f(x)单调减少&#xff0…

肥胖成因:饮食之外,消耗吸收慢是关键因素

肥胖问题一直被现代社会所关注&#xff0c;不可否认&#xff0c;饮食是影响胖瘦的重要因素之一。高热量、高油脂的食物摄入过多&#xff0c;也确实会导致热量油脂过剩&#xff0c;堆积储存进身体内进而养肥身体。可在正常情况中&#xff0c;就算是消耗吸收率一般的人&#xff0…

828华为云征文 | 在Huawei Cloud EulerOS系统中安装Docker的详细步骤与常见问题解决

前言 Docker是一种轻量级的容器技术&#xff0c;广泛用于应用程序的开发、部署和运维。在华为云的欧拉&#xff08;Huawei Cloud EulerOS&#xff09;系统上安装和运行Docker&#xff0c;虽然与CentOS有相似之处&#xff0c;但在具体实现过程中&#xff0c;可能会遇到一些系统…

进程状态的优先级

1.进程的状态&#xff08;所有系统&#xff09; 因为是对于所有系统的&#xff0c;所以描述会很抽象。 补充知识&#xff1a; 并行和并发 并行&#xff1a;多个进程再多个cpu下分别同时运行并发&#xff1a;多个进程在一个cpu下采取进程切换的方式&#xff0c;在一段时间内&…

echarts实现地图下钻并解决海南群岛显示缩略图

一、准备工作 1、echarts版本&#xff1a; ^5.5.1 2、去掉海南数据的json文件 二、获取删除过后的json文件 1、DataV.GeoAtlas地理小工具系列 (aliyun.com) 在网站输入这个复制的&#xff0c;新建一个json文件粘贴进去。 接下来需要删除两个地方&#xff0c;不要删错&…

左手研发,右手销量,比亚迪舍弃了什么?

早买早享受&#xff0c;晚买享折扣&#xff0c;是近一年来汽车消费市场的真实写照。 A级家轿价格下探至6、7万元&#xff1b;曾经20万起步的主流B级车&#xff0c;如今只要12万元就能入手&#xff1b;即使是BBA等豪华品牌&#xff0c;也开始降价促销换销量。买车更便宜了&…

【最优化】一维最优化方法:华罗庚黄金分割优选法

一、意义 华先生提倡用数学实际服务国民经济发展&#xff0c;受限于当时计算能力有限&#xff0c;华先生总结经验&#xff0c;提出黄金分割优选法&#xff0c;能够用最少的试验次数找出最优解。 二、主要内容 ①应用范围&#xff1a;一维单峰函数 ②算法步骤&#xff1a; ③详…

Qt/C++ TCP调试助手V1.1 新增图像传输与接收功能(附发布版下载链接)

发布版本链接 通过百度网盘分享的文件&#xff1a;TCP调试助手V1.zip&#xff08;含客户端与服务器&#xff09; 链接&#xff1a;https://pan.baidu.com/s/14LTRPChPhYdwp_s6KeyBiA?pwdcedu 提取码&#xff1a;cedu 基于Qt/C实现了一款功能丰富的TCP服务器与客户端调试助手…

【已解决】华为AR100-S路由器 恢复出厂后,找不到5G wifi的设置

前两帖讨论了华为AR100-S路由器&#xff1a; 一是用电脑浏览器访问web管理界面报错的解决&#xff0c;详情点这里&#xff01; https://blog.csdn.net/weixin_62598385/article/details/142215136 再就是如何回复出厂&#xff0c;也即如何复位&#xff0c; 详情点这里&#xff…

微服务保护详细笔记(一):雪崩问题--Sentinel

目录 1.雪崩问题 1.1.雪崩问题产生原因&#xff1a; 1.2.雪崩问题解决方案 1.2.1.请求限流 1.1.2.线程隔离 1.1.3.服务熔断 1.3.微服务保护技术对比 1.4.Sentinel 1.4.1.介绍与安装 1.4.2.微服务整合 1.雪崩问题 1.1.雪崩问题产生原因&#xff1a; 比如查询购物车的…

SEO之页面优化(二—描述标签)

初创企业搭建网站的朋友看1号文章&#xff1b;想学习云计算&#xff0c;怎么入门看2号文章谢谢支持&#xff1a; 1、我给不会敲代码又想搭建网站的人建议 2、“新手上云”能够为你开启探索云世界的第一步 博客&#xff1a;阿幸SEO~探索搜索排名之道 2、描述标签 描述标签是H…

Tomcat CVE-2017-12615漏洞复现

1.开启环境 cd /vulhub/tomcat/CVE-2017-12615 docker-compose up -d 一键启动环境 2.在首页进行抓包 修改为put方式提交 Tomcat允许适用put方法上传任意文件类型&#xff0c;但不允许jsp后缀文件上传&#xff0c;因此我们需要配合 windows的解析漏洞. 使用put /shell.jsp…

LocalDateTime,OffsetDateTime和ZonedDateTime(上)

图片来源&#xff1a;https://www.cnblogs.com/yourbatman/p/14324575.html 一. LocalDate和LocalTime LocalDate&#xff1a;代表不含时区信息的日期&#xff0c;它只能表示年、月、日。它适用于记录一个日子&#xff0c;比如生日、纪念日、或者任何只需要日期而不需要具体时…

前端框架大比拼:React、Angular、Vue、Svelte、Ember,哪个才是你的终极选择!

前端开发框架在现代Web开发中扮演着至关重要的角色。它们不仅提高了开发效率&#xff0c;还改善了代码的可维护性和扩展性。以下是一些流行的前端框架及其对比&#xff0c;帮助你选择最适合你项目需求的框架。 1. React 优点: 生态系统丰富&#xff1a; React 拥有庞大的社区…

【SpringCloud】注册中心的其他实现 - Nacos

目录 注册中心的其他实现-NacosNacos简介Nacos安装下载安装包Windows解压修改单机模式启动Nacos常见问题 Linux准备安装包单机模式启动常见问题 Nacos快速上手服务注册/服务发现引入Spring Cloud Alibaba依赖引入Nacos 依赖引入Load Balance依赖 配置Nacos地址远程调用启动服务…

SpringCloud微服务实现服务熔断的实践指南

Spring Cloud是一套分布式系统的微服务框架&#xff0c;它提供了一系列的组件和工具&#xff0c;能够使我们更容易地构建和管理微服务架构。在实际开发中&#xff0c;由于各个服务之间的通信依赖&#xff0c;一旦某个服务出现故障或负载过高&#xff0c;可能会导致整个系统的性…

百度飞浆Paddle OCR检测和识别【OCR数据收集、标注、数据集划分、检测识别模型训练、导出模型】

文章目录 前言一、OCR数据集采集二、OCR数据标注三、划分数据集四、数据训练五、导出模型 前言 1、我的电脑没有GPU&#xff0c;如果不使用AI Studio训练的话&#xff0c;第一遍我是按照CPU进行环境配置和训练的&#xff0c;可以参考这篇文章&#xff0c;我按着弄了一遍&#…