CSharpGL(21)用鼠标拾取、拖拽VBO图元内的点、线或本身

效果图

以最常见的三角形网格(用GL_TRIANGLES方式进行渲染)为例。

在拾取模式为GeometryType.Point时,你可以拾取单个的顶点。

在拾取模式为GeometryType.Line时,你可以拾取任意一个三角形里的任意一条线。即同时拾取此线段的两个顶点。

在拾取模式为GeometryType.Triangle时,你可以拾取任意一个三角形。即同时拾取此三角形的三个顶点。

实际上,CSharpGL实现了在所有渲染模式下拾取Point、Line、Triangle、Quad和Polygon的功能。(当然,你可以想象,如果想在一个GL_TRIANGLES渲染方式下拾取一个Quad,那是什么都拾取不到的)下面是描述这一功能的图示。由于我的白板小,就没有列出GL_TRIANGLES_ADJACENCY、GL_TRIANGLE_STRIP_ADJACENCY、GL_LINES_ADJACENCY、GL_LINE_STRIP_ADJCANCEY这几个情况。

下载

CSharpGL已在GitHub开源,欢迎对OpenGL有兴趣的同学加入(https://github.com/bitzhuwei/CSharpGL

规定

为了简便描述,我用GL_LINE*代表GL_LINES、GL_LINE_STRIP、GL_LINES_ADJACENCY、GL_LINE_STRIP_ADJACENCY,用GL_TRIANGLE*代表GL_TRIANGLES、GL_TRIANGLE_STRIP、GL_TRIANGLE_FAN、GL_TRIANGLES_ADJACENCY、GL_TRIANGLE_STRIP_ADJACENCY,用GL_QUAD*代表GL_QUADS、GL_QUAD_STRIP。

如何使用

使用方式十分简单,只需给RenderEventArgs传入如下的参数:

  1. GeometryType PickingGeometryType = Geometry.Point;
  2. var arg = new RenderEventArgs(
  3. // 为了拾取而进行的渲染
  4. RenderModes.ColorCodedPicking,
  5. this.glCanvas1.ClientRectangle,
  6. this.camera,
  7. // 我想拾取的类型(Geometry)
  8. this.PickingGeometryType);
  9. // 要拾取的位置(鼠标位置)
  10. Point mousePostion = GetMousePosition();
  11. // 支持Picking的Renderer列表
  12. PickableRenderer[] pickableElements = GetRenderersInScene();
  13. // 执行拾取操作
  14. PickedGeometry pickedGeometry = ColorCodedPicking.Pick(arg, mousePostion, pickableElements);

具体用法详见(CSharpGL(20)用unProject和Project实现鼠标拖拽图元

如何实现

在GL_POINTS时拾取Point,在GL_LINE*时拾取Line,在GL_TRIANGL*时拾取Triangle,在GL_QUAD*时拾取Quad,在GL_POLYGON时拾取Polygon,这都是已经实现了的(CSharpGL(18)分别处理glDrawArrays()和glDrawElements()两种方式下的拾取(ColorCodedPicking))。这些不再详述。

拾取Point

ZeroIndexRenderer

在除了GL_POINTS时,想拾取一个Point,只能用 glDrawArrays(GL_POINTS, ..); 来代替原有的 glDrawArrays(OriginalMode, ..); 。但这会渲染所有的顶点。而在OriginalMode下,未必渲染所有的顶点。所以在拾取到一个Point后要判断一下是否真的应该拾取到它。

  1. /// <summary>
  2. /// 现在,已经判定了鼠标在某个点上。
  3. /// 我需要判定此点是否出现在图元上。
  4. /// now that I know the mouse is picking on some point,
  5. /// I need to make sure that point should appear.
  6. /// </summary>
  7. /// <param name="lastVertexId"></param>
  8. /// <param name="mode"></param>
  9. /// <returns></returns>
  10. private bool OnPrimitiveTest(uint lastVertexId, DrawMode mode)
  11. {
  12. bool result = false;
  13. int first = this.zeroIndexBufferPtr.FirstVertex;
  14. if (first < ) { return false; }
  15. int vertexCount = this.zeroIndexBufferPtr.VertexCount;
  16. if (vertexCount <= ) { return false; }
  17. int last = first + vertexCount - ;
  18. switch (mode)
  19. {
  20. case DrawMode.Points:
  21. result = true;
  22. break;
  23. case DrawMode.LineStrip:
  24. result = vertexCount > ;
  25. break;
  26. case DrawMode.LineLoop:
  27. result = vertexCount > ;
  28. break;
  29. case DrawMode.Lines:
  30. if (vertexCount > )
  31. {
  32. if (vertexCount % == )
  33. {
  34. result = (first <= lastVertexId && lastVertexId <= last);
  35. }
  36. else
  37. {
  38. result = (first <= lastVertexId && lastVertexId <= last - );
  39. }
  40. }
  41. break;
  42. case DrawMode.LineStripAdjacency:
  43. if (vertexCount > )
  44. {
  45. result = (first < lastVertexId && lastVertexId < last);
  46. }
  47. break;
  48. case DrawMode.LinesAdjacency:
  49. if (vertexCount > )
  50. {
  51. var lastPart = last - (last + - first) % ;
  52. if (first <= lastVertexId && lastVertexId <= lastPart)
  53. {
  54. var m = (lastVertexId - first) % ;
  55. result = (m == || m == );
  56. }
  57. }
  58. break;
  59. case DrawMode.TriangleStrip:
  60. if (vertexCount > )
  61. {
  62. result = vertexCount > ;
  63. }
  64. break;
  65. case DrawMode.TriangleFan:
  66. if (vertexCount > )
  67. {
  68. result = vertexCount > ;
  69. }
  70. break;
  71. case DrawMode.Triangles:
  72. if (vertexCount > )
  73. {
  74. if (first <= lastVertexId)
  75. {
  76. result = ((vertexCount % == ) && (lastVertexId <= last))
  77. || ((vertexCount % == ) && (lastVertexId < last))
  78. || ((vertexCount % == ) && (lastVertexId + < last));
  79. }
  80. }
  81. break;
  82. case DrawMode.TriangleStripAdjacency:
  83. if (vertexCount > )
  84. {
  85. var lastPart = last - (last + - first) % ;
  86. if (first <= lastVertexId && lastVertexId <= lastPart)
  87. {
  88. result = (lastVertexId - first) % == ;
  89. }
  90. }
  91. break;
  92. case DrawMode.TrianglesAdjacency:
  93. if (vertexCount > )
  94. {
  95. var lastPart = last - (last + - first) % ;
  96. if (first <= lastVertexId && lastVertexId <= lastPart)
  97. {
  98. result = (lastVertexId - first) % == ;
  99. }
  100. }
  101. break;
  102. case DrawMode.Patches:
  103. // not know what to do for now
  104. break;
  105. case DrawMode.QuadStrip:
  106. if (vertexCount > )
  107. {
  108. if (first <= lastVertexId && lastVertexId <= last)
  109. {
  110. result = (vertexCount % == )
  111. || (lastVertexId < last);
  112. }
  113. }
  114. break;
  115. case DrawMode.Quads:
  116. if (vertexCount > )
  117. {
  118. if (first <= lastVertexId && lastVertexId <= last)
  119. {
  120. var m = vertexCount % ;
  121. if (m == ) { result = true; }
  122. else if (m == ) { result = lastVertexId + < last; }
  123. else if (m == ) { result = lastVertexId + < last; }
  124. else if (m == ) { result = lastVertexId + < last; }
  125. else { throw new Exception("This should never happen!"); }
  126. }
  127. }
  128. break;
  129. case DrawMode.Polygon:
  130. if (vertexCount > )
  131. {
  132. result = (first <= lastVertexId && lastVertexId <= last);
  133. }
  134. break;
  135. default:
  136. throw new NotImplementedException();
  137. }
  138.  
  139. return result;
  140. }

bool OnPrimitiveTest(uint lastVertexId, DrawMode mode)

OneIndexBuffer

如果是用glDrawElements(OriginalMode, ..);渲染,此时想拾取一个Point,那么我就不做类似的OnPrimitiveTest了。因为情况太复杂,且必须用MapBufferRange来检测大量的顶点情况。而这仅仅是因为导入的IBufferable模型本身没有使用某些顶点。没用你就删了它啊!这我就不管了。

  1. /// <summary>
  2. /// I don't know how to implement this method in a high effitiency way.
  3. /// So keep it like this.
  4. /// Also, why would someone use glDrawElements() when rendering GL_POINTS?
  5. /// </summary>
  6. /// <param name="lastVertexId"></param>
  7. /// <param name="mode"></param>
  8. /// <returns></returns>
  9. private bool OnPrimitiveTest(uint lastVertexId, DrawMode mode)
  10. {
  11. return true;
  12. }

拾取Line

ZeroIndexRenderer

如果是在GL_LINE*下拾取线,那么这是上一篇文章已经实现了的情况。如果是想在GL_TRIANGLE*、GL_QUAD*、GL_POLYGON模式下拾取其某个图元的某条Line,那么就分两部走:第一,像上一篇一样拾取图元;第二,设计一个新的小小的索引,即用GL_LINES模式渲染此图元(三角形、四边形、多边形)的所有边的索引。用此索引重新执行渲染、拾取,那么就可以找到鼠标所在位置的Line了。

例如,下面是在一个三角形图元中找到那个你想要的Line的过程。

  1. class ZeroIndexLineInTriangleSearcher : ZeroIndexLineSearcher
  2. {
  3. /// <summary>
  4. /// 在三角形图元中拾取指定位置的Line
  5. /// </summary>
  6. /// <param name="arg">渲染参数</param>
  7. /// <param name="x">指定位置</param>
  8. /// <param name="y">指定位置</param>
  9. /// <param name="lastVertexId">三角形图元的最后一个顶点</param>
  10. /// <param name="modernRenderer">目标Renderer</param>
  11. /// <returns></returns>
  12. internal override uint[] Search(RenderEventArgs arg,
  13. int x, int y,
  14. uint lastVertexId, ZeroIndexRenderer modernRenderer)
  15. {
  16. // 创建临时索引
  17. OneIndexBufferPtr indexBufferPtr = null;
  18. using (var buffer = new OneIndexBuffer<uint>(DrawMode.Lines, BufferUsage.StaticDraw))
  19. {
  20. buffer.Alloc();
  21. unsafe
  22. {
  23. var array = (uint*)buffer.FirstElement();
  24. array[] = lastVertexId - ; array[] = lastVertexId - ;
  25. array[] = lastVertexId - ; array[] = lastVertexId - ;
  26. array[] = lastVertexId - ; array[] = lastVertexId - ;
  27. }
  28.  
  29. indexBufferPtr = buffer.GetBufferPtr() as OneIndexBufferPtr;
  30. }
  31.  
  32. // 用临时索引渲染此三角形图元(仅渲染此三角形图元)
  33. modernRenderer.Render4InnerPicking(arg, indexBufferPtr);
  34. // id是拾取到的Line的Last Vertex Id
  35. uint id = ColorCodedPicking.ReadPixel(x, y, arg.CanvasRect.Height);
  36.  
  37. indexBufferPtr.Dispose();
  38.  
  39. // 对比临时索引,找到那个Line
  40. if (id + == lastVertexId)
  41. { return new uint[] { id + , id, }; }
  42. else
  43. { return new uint[] { id - , id, }; }
  44. }
  45. }

OneIndexBuffer

用glDrawElements()时,实现思路与上面一样,只不过Index参数变化一下而已。

在(CSharpGL(18)分别处理glDrawArrays()和glDrawElements()两种方式下的拾取(ColorCodedPicking)),已经能够找到目标图元的所有顶点,所以就简单了。

继续用"在一个三角形图元中找到那个你想要的Line的过程"来举例。

  1. class OneIndexLineInTrianglesSearcher : OneIndexLineSearcher
  2. {
  3. internal override uint[] Search(RenderEventArgs arg,
  4. int x, int y,
  5. RecognizedPrimitiveIndex lastIndexId,
  6. OneIndexRenderer modernRenderer)
  7. {
  8. if (lastIndexId.IndexIdList.Count != ) { throw new ArgumentException(); }
  9. List<uint> indexList = lastIndexId.IndexIdList;
  10. if (indexList[] == indexList[]) { return new uint[] { indexList[], indexList[], }; }
  11. else if (indexList[] == indexList[]) { return new uint[] { indexList[], indexList[], }; }
  12. else if (indexList[] == indexList[]) { return new uint[] { indexList[], indexList[], }; }
  13.  
  14. OneIndexBufferPtr indexBufferPtr = null;
  15. using (var buffer = new OneIndexBuffer<uint>(DrawMode.Lines, BufferUsage.StaticDraw))
  16. {
  17. buffer.Alloc();
  18. unsafe
  19. {
  20. var array = (uint*)buffer.FirstElement();
  21. array[] = indexList[]; array[] = indexList[];
  22. array[] = indexList[]; array[] = indexList[];
  23. array[] = indexList[]; array[] = indexList[];
  24. }
  25.  
  26. indexBufferPtr = buffer.GetBufferPtr() as OneIndexBufferPtr;
  27. }
  28.  
  29. modernRenderer.Render4InnerPicking(arg, indexBufferPtr);
  30. uint id = ColorCodedPicking.ReadPixel(x, y, arg.CanvasRect.Height);
  31.  
  32. indexBufferPtr.Dispose();
  33.  
  34. if (id == indexList[])
  35. { return new uint[] { indexList[], indexList[], }; }
  36. else if (id == indexList[])
  37. { return new uint[] { indexList[], indexList[], }; }
  38. else if (id == indexList[])
  39. { return new uint[] { indexList[], indexList[], }; }
  40. else
  41. { throw new Exception("This should not happen!"); }
  42. }
  43. }

Polygon

这里顺便提一下GL_POLYGON,这是个特别的图元,因为它的顶点数是不确定的。它产生的临时小索引就可能不再小。但神奇的是,它不再需要OneIndexBufferPtr类型的临时索引,而只需一个几乎不占空间的ZeroIndexBufferPtr。

  1. class ZeroIndexLineInPolygonSearcher : ZeroIndexLineSearcher
  2. {
  3. internal override uint[] Search(RenderEventArgs arg,
  4. int x, int y,
  5. uint lastVertexId, ZeroIndexRenderer modernRenderer)
  6. {
  7. var zeroIndexBufferPtr = modernRenderer.GetIndexBufferPtr() as ZeroIndexBufferPtr;
  8. ZeroIndexBufferPtr indexBufferPtr = null;
  9. // when the temp index buffer could be long, it's no longer needed.
  10. // what a great OpenGL API design!
  11. using (var buffer = new ZeroIndexBuffer(DrawMode.LineLoop,
  12. zeroIndexBufferPtr.FirstVertex, zeroIndexBufferPtr.VertexCount))
  13. {
  14. indexBufferPtr = buffer.GetBufferPtr() as ZeroIndexBufferPtr;
  15. }
  16. modernRenderer.Render4InnerPicking(arg, indexBufferPtr);
  17. uint id = ColorCodedPicking.ReadPixel(x, y, arg.CanvasRect.Height);
  18.  
  19. indexBufferPtr.Dispose();
  20.  
  21. if (id == zeroIndexBufferPtr.FirstVertex)
  22. { return new uint[] { (uint)(zeroIndexBufferPtr.FirstVertex + zeroIndexBufferPtr.VertexCount - ), id, }; }
  23. else
  24. { return new uint[] { id - , id, }; }
  25. }
  26. }

拾取本身

所谓拾取本身,就是:如果用GL_TRIANGLE*进行渲染,就拾取一个Triangle;如果用GL_QUAD*进行渲染,就拾取一个Quad;如果用GL_POLYGON进行渲染,就拾取一个Polygon。这都是在(CSharpGL(18)分别处理glDrawArrays()和glDrawElements()两种方式下的拾取(ColorCodedPicking))中已经实现了的功能。

整合

三种情况都解决了,下面整合进来就行了。

ZeroIndexRenderer

这是对ZeroIndexRenderer的Pick。

  1. public override PickedGeometry Pick(RenderEventArgs arg, uint stageVertexId,
  2. int x, int y)
  3. {
  4. uint lastVertexId;
  5. if (!this.GetLastVertexIdOfPickedGeometry(stageVertexId, out lastVertexId))
  6. { return null; }
  7.  
  8. GeometryType geometryType = arg.PickingGeometryType;
  9.  
  10. if (geometryType == GeometryType.Point)
  11. {
  12. DrawMode mode = this.GetIndexBufferPtr().Mode;
  13. if (this.OnPrimitiveTest(lastVertexId, mode))
  14. { return PickPoint(stageVertexId, lastVertexId); }
  15. else
  16. { return null; }
  17. }
  18. else if (geometryType == GeometryType.Line)
  19. {
  20. DrawMode mode = this.GetIndexBufferPtr().Mode;
  21. GeometryType typeOfMode = mode.ToGeometryType();
  22. if (geometryType == typeOfMode)
  23. { return PickWhateverItIs(stageVertexId, lastVertexId, mode, typeOfMode); }
  24. else
  25. {
  26. ZeroIndexLineSearcher searcher = GetLineSearcher(mode);
  27. if (searcher != null)// line is from triangle, quad or polygon
  28. { return SearchLine(arg, stageVertexId, x, y, lastVertexId, searcher); }
  29. else if (mode == DrawMode.Points)// want a line when rendering GL_POINTS
  30. { return null; }
  31. else
  32. { throw new Exception(string.Format("Lack of searcher for [{0}]", mode)); }
  33. }
  34. }
  35. else
  36. {
  37. DrawMode mode = this.GetIndexBufferPtr().Mode;
  38. GeometryType typeOfMode = mode.ToGeometryType();
  39. if (typeOfMode == geometryType)// I want what it is
  40. { return PickWhateverItIs(stageVertexId, lastVertexId, mode, typeOfMode); }
  41. else
  42. { return null; }
  43. //{ throw new Exception(string.Format("Lack of searcher for [{0}]", mode)); }
  44. }
  45. }

public override PickedGeometry Pick(RenderEventArgs arg, uint stageVertexId, int x, int y)

OneIndexRenderer

这是对OneIndexRenderer的Pick。

  1. public override PickedGeometry Pick(RenderEventArgs arg, uint stageVertexId,
  2. int x, int y)
  3. {
  4. uint lastVertexId;
  5. if (!this.GetLastVertexIdOfPickedGeometry(stageVertexId, out lastVertexId))
  6. { return null; }
  7.  
  8. GeometryType geometryType = arg.PickingGeometryType;
  9.  
  10. if (geometryType == GeometryType.Point)
  11. {
  12. DrawMode mode = this.GetIndexBufferPtr().Mode;
  13. if (this.OnPrimitiveTest(lastVertexId, mode))
  14. { return PickPoint(stageVertexId, lastVertexId); }
  15. else
  16. { return null; }
  17. }
  18. else if (geometryType == GeometryType.Line)
  19. {
  20. // 找到 lastIndexId
  21. RecognizedPrimitiveIndex lastIndexId = this.GetLastIndexIdOfPickedGeometry(
  22. arg, lastVertexId, x, y);
  23. if (lastIndexId == null)
  24. {
  25. Debug.WriteLine(
  26. "Got lastVertexId[{0}] but no lastIndexId! Params are [{1}] [{2}] [{3}] [{4}]",
  27. lastVertexId, arg, stageVertexId, x, y);
  28. { return null; }
  29. }
  30. else
  31. {
  32. // 获取pickedGeometry
  33. DrawMode mode = this.GetIndexBufferPtr().Mode;
  34. GeometryType typeOfMode = mode.ToGeometryType();
  35. if (geometryType == typeOfMode)
  36. { return PickWhateverItIs(stageVertexId, lastIndexId, typeOfMode); }
  37. else
  38. {
  39. OneIndexLineSearcher searcher = GetLineSearcher(mode);
  40. if (searcher != null)// line is from triangle, quad or polygon
  41. { return SearchLine(arg, stageVertexId, x, y, lastVertexId, lastIndexId, searcher); }
  42. else if (mode == DrawMode.Points)// want a line when rendering GL_POINTS
  43. { return null; }
  44. else
  45. { throw new Exception(string.Format("Lack of searcher for [{0}]", mode)); }
  46. }
  47. }
  48. }
  49. else
  50. {
  51. // 找到 lastIndexId
  52. RecognizedPrimitiveIndex lastIndexId = this.GetLastIndexIdOfPickedGeometry(
  53. arg, lastVertexId, x, y);
  54. if (lastIndexId == null)
  55. {
  56. Debug.WriteLine(
  57. "Got lastVertexId[{0}] but no lastIndexId! Params are [{1}] [{2}] [{3}] [{4}]",
  58. lastVertexId, arg, stageVertexId, x, y);
  59. { return null; }
  60. }
  61. else
  62. {
  63. DrawMode mode = this.GetIndexBufferPtr().Mode;
  64. GeometryType typeOfMode = mode.ToGeometryType();
  65. if (typeOfMode == geometryType)// I want what it is
  66. { return PickWhateverItIs(stageVertexId, lastIndexId, typeOfMode); }
  67. else
  68. { return null; }
  69. //{ throw new Exception(string.Format("Lack of searcher for [{0}]", mode)); }
  70. }
  71. }
  72. }

public override PickedGeometry Pick(RenderEventArgs arg, uint stageVertexId, int x, int y)

总结

在完成后,我以为彻底解决了拾取问题。等完成本文后,我不再这么想了。还是谦虚点好。

原CSharpGL的其他功能(3ds解析器、TTF2Bmp、CSSL等),我将逐步加入新CSharpGL。

欢迎对OpenGL有兴趣的同学关注(https://github.com/bitzhuwei/CSharpGL

CSharpGL(21)用鼠标拾取、拖拽VBO图元内的点、线或本身的更多相关文章

  1. Qt窗口添加鼠标移动拖拽事件

    1. .h文件中添加 private:    QPoint dragPosition; 2. 在cpp文件中重写鼠标点击和拖拽函数 void ShapeWidget::mousePressEvent( ...

  2. JS鼠标的拖拽原理

    拖拽功能主要是用在让用户做一些自定义的动作,比如拖动排序,弹出框拖动移动等等,效果还是蛮不错的.下面讲解一下拖拽的原理,希望可以帮助到有需要的朋友! 一.拖拽的流程动作①鼠标按下②鼠标移动③鼠标松开 ...

  3. 鼠标事件-拖拽2(不能拖出指定对象的div)

    <!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>& ...

  4. 鼠标事件-拖拽(不能拖出窗口的div)

    <!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>& ...

  5. CSharpGL(20)用unProject和Project实现鼠标拖拽图元

    CSharpGL(20)用unProject和Project实现鼠标拖拽图元 效果图 例如,你可以把Big Dipper这个模型拽成下面这个样子. 配合旋转,还可以继续拖拽成这样. 当然,能拖拽的不只 ...

  6. Arcgis for qml - 鼠标拖拽移动

    以实现鼠标拖拽文本图层为例 GitHub:ArcGIS拖拽文本 作者:狐狸家的鱼 目的是利用鼠标进行拖拽. 实现两种模式,一种是屏幕上的拖拽,第二种是地图上图层的挪动. 屏幕上的拖拽其实跟ArcGIS ...

  7. 鼠标拖拽移动Java界面组件

    默认的,Frame或者JFrame自身已经实现了鼠标拖拽标题栏移动窗口的功能. 只是,当你不满意java的JFrame样式,隐藏了标题栏和边框,又或者干脆直接使用JWindow,那你又该怎么实现鼠标拖 ...

  8. 完美实现鼠标拖拽事件,解决各种小bug,基于jquery

    鼠标拖拽事件是web中使用频率极高的事件,之前写过的代码包括网上的代码,总存在各种各样的问题,包括拖拽体验差,松开鼠标后拖拽效果仍存在以及代码冗余过大等 本次我才用jQuery实现一个尽可能高效的拖拽 ...

  9. Javascript之盒子拖拽(跟随鼠标、边界限定、轨迹回放)

    本文通过拖拽案例,实现"跟随鼠标.边界限定.轨迹回放"三大效果: 完整代码中有详尽注释,故不再进行细致讲解: 对于案例中需要注意的重点或易错点问题,会总结在最后. 效果图(仅演示左 ...

随机推荐

  1. 一步步开发自己的博客 .NET版(11、Web.config文件的读取和修改)

    Web.config的读取 对于Web.config的读取大家都很属性了.平时我们用得比较多的就是appSettings节点下配置.如: 我们对应的代码是: = ConfigurationManage ...

  2. JS里面Data日期格式转换

    var format = function(time, format){     var t = new Date(time);     var tf = function(i){return (i  ...

  3. [原] KVM 环境下MySQL性能对比

    KVM 环境下MySQL性能对比 标签(空格分隔): Cloud2.0 [TOC] 测试目的 对比MySQL在物理机和KVM环境下性能情况 压测标准 压测遵循单一变量原则,所有的对比都是只改变一个变量 ...

  4. [笔记]kubernetes 无法启动问题

    在启动kubernetes的时候报错误. ERROR: timed out for http://localhost:4001/v2/keys/ 原因是无法启动etcd, etcd 监听4001本地端 ...

  5. Kooboo CMS技术文档之四:Kooboo CMS的站点组成部分

    Kooboo CMS本着功能独立分离的原则,将站点分为三部分组成:用户管理,站点管理和内容数据库管理.各个功能之间既可独立使用,也可以容易组成在一起形成一个完整的系统. 用户管理 管理整个系统内的用户 ...

  6. angluarjs2项目生成内容合并到asp.net mvc4项目中一起发布

    应用场景 angular2(下文中标注位NG2)项目和.net mvc项目分别开发,前期采用跨域访问进行并行开发,后期只需要将NG2项目的生产版本合并到.net项目. NG2项目概述 ng2项目采用的 ...

  7. if __name__== "__main__" 的意思(作用)python代码复用

    if __name__== "__main__" 的意思(作用)python代码复用 转自:大步's Blog  http://www.dabu.info/if-__-name__ ...

  8. golang sync.WaitGroup bug

    注意,这个结构体,要是想在函数之间传来传去的话,必须要使用指针....... 这个结构体里没有 指针,这个类型可以说没有“引用特性”. 被坑了一晚上.特此记录.

  9. arcgis api for js入门开发系列六地图分屏对比(含源代码)

    上一篇实现了demo的地图标绘模块,本篇新增地图地图分屏对比模块,截图如下(源代码见文章底部): 对效果图的简单介绍一下,在demo只采用了两分屏对比,感兴趣的话,可以在两分屏的基础上拓展,修改css ...

  10. maven的pom.xml关系依赖书写顺序

    今天遇到了一个情况,以前代码编译没有问题,升级了hbase客户端phoenix驱动,又调整了thrift的关系依赖的位置,放到了这个驱动后面. 如下: 导致了一个thrift接口类编译报错: 检查这个 ...