Skip to content

Commit a21a3c4

Browse files
committed
Make GL line rendering use a dash pattern instead of line style for dash support
1 parent 5039d6c commit a21a3c4

File tree

1 file changed

+23
-62
lines changed

1 file changed

+23
-62
lines changed

src/silx/gui/plot/backends/glutils/GLPlotCurve.py

Lines changed: 23 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -278,8 +278,6 @@ def isInitialized(self):
278278

279279
# line ########################################################################
280280

281-
SOLID, DASHED, DASHDOT, DOTTED = "-", "--", "-.", ":"
282-
283281

284282
class GLLines2D(object):
285283
"""Object rendering curve as a polyline
@@ -288,17 +286,16 @@ class GLLines2D(object):
288286
:param yVboData: Y coordinates VBO
289287
:param colorVboData: VBO of colors
290288
:param distVboData: VBO of distance along the polyline
291-
:param str style: Line style in: '-', '--', '-.', ':'
292289
:param List[float] color: RGBA color as 4 float in [0, 1]
293290
:param float width: Line width
294-
:param List[float] dashPattern: "Unscaled" dash pattern in points
291+
:param List[float] dashPattern:
292+
"unscaled" dash pattern as 4 lengths in points (dash1, gap1, dash2, gap2).
293+
This pattern is scaled with the line width.
294+
Set to () to draw solid lines (default), and to None to disable rendering.
295295
:param drawMode: OpenGL drawing mode
296296
:param List[float] offset: Translation of coordinates (ox, oy)
297297
"""
298298

299-
STYLES = SOLID, DASHED, DASHDOT, DOTTED
300-
"""Supported line styles"""
301-
302299
_SOLID_PROGRAM = Program(
303300
vertexShader="""
304301
#version 120
@@ -383,11 +380,10 @@ def __init__(
383380
yVboData=None,
384381
colorVboData=None,
385382
distVboData=None,
386-
style=SOLID,
387383
color=(0.0, 0.0, 0.0, 1.0),
388384
gapColor=None,
389385
width=1,
390-
dashPeriod=20.0,
386+
dashPattern=(),
391387
drawMode=None,
392388
offset=(0.0, 0.0),
393389
):
@@ -419,26 +415,11 @@ def __init__(
419415
self.color = color
420416
self.gapColor = gapColor
421417
self.width = width
422-
self._style = None
423-
self.style = style
424-
self.dashPeriod = dashPeriod
418+
self.dashPattern = dashPattern
425419
self.offset = offset
426420

427421
self._drawMode = drawMode if drawMode is not None else gl.GL_LINE_STRIP
428422

429-
@property
430-
def style(self):
431-
"""Line style (Union[str,None])"""
432-
return self._style
433-
434-
@style.setter
435-
def style(self, style):
436-
if style in _MPL_NONES:
437-
self._style = None
438-
else:
439-
assert style in self.STYLES
440-
self._style = style
441-
442423
@classmethod
443424
def init(cls):
444425
"""OpenGL context initialization"""
@@ -449,39 +430,23 @@ def render(self, context):
449430
450431
:param RenderContext context:
451432
"""
452-
width = self.width / 72.0 * context.dpi
453-
454-
style = self.style
455-
if style is None:
433+
if self.dashPattern is None: # Nothing to display
456434
return
457435

458-
elif style == SOLID:
436+
if self.dashPattern == (): # No dash: solid line
459437
program = self._SOLID_PROGRAM
460438
program.use()
461439

462-
else: # DASHED, DASHDOT, DOTTED
440+
else: # Dashed line defined by 4 control points
463441
program = self._DASH_PROGRAM
464442
program.use()
465443

466-
dashPeriod = self.dashPeriod * width
467-
if self.style == DOTTED:
468-
dash = (
469-
0.2 * dashPeriod,
470-
0.5 * dashPeriod,
471-
0.7 * dashPeriod,
472-
dashPeriod,
473-
)
474-
elif self.style == DASHDOT:
475-
dash = (
476-
0.3 * dashPeriod,
477-
0.5 * dashPeriod,
478-
0.6 * dashPeriod,
479-
dashPeriod,
480-
)
481-
else:
482-
dash = (0.5 * dashPeriod, dashPeriod, dashPeriod, dashPeriod)
483-
484-
gl.glUniform4f(program.uniforms["dash"], *dash)
444+
# Scale pattern by width, convert from lengths in points to offsets in pixels
445+
scale = self.width / 72.0 * context.dpi
446+
dashOffsets = tuple(
447+
offset * scale for offset in numpy.cumsum(self.dashPattern)
448+
)
449+
gl.glUniform4f(program.uniforms["dash"], *dashOffsets)
485450

486451
if self.gapColor is None:
487452
# Use fully transparent color which gets discarded in shader
@@ -540,7 +505,7 @@ def render(self, context):
540505
yPosAttrib, 1, gl.GL_FLOAT, False, 0, self.yVboData
541506
)
542507

543-
gl.glLineWidth(width)
508+
gl.glLineWidth(self.width / 72.0 * context.dpi)
544509
gl.glDrawArrays(self._drawMode, 0, self.xVboData.size)
545510

546511
gl.glDisable(gl.GL_LINE_SMOOTH)
@@ -1220,11 +1185,10 @@ def __init__(
12201185
colorData=None,
12211186
xError=None,
12221187
yError=None,
1223-
lineStyle=SOLID,
12241188
lineColor=(0.0, 0.0, 0.0, 1.0),
12251189
lineGapColor=None,
12261190
lineWidth=1,
1227-
lineDashPeriod=20,
1191+
lineDashPattern=(),
12281192
marker=SQUARE,
12291193
markerColor=(0.0, 0.0, 0.0, 1.0),
12301194
markerSize=7,
@@ -1311,11 +1275,10 @@ def deduce_baseline(baseline):
13111275
)
13121276

13131277
self.lines = GLLines2D()
1314-
self.lines.style = lineStyle
13151278
self.lines.color = lineColor
13161279
self.lines.gapColor = lineGapColor
13171280
self.lines.width = lineWidth
1318-
self.lines.dashPeriod = lineDashPeriod
1281+
self.lines.dashPattern = lineDashPattern
13191282
self.lines.offset = self.offset
13201283

13211284
self.points = Points2D()
@@ -1336,15 +1299,13 @@ def deduce_baseline(baseline):
13361299

13371300
distVboData = _proxyProperty(("lines", "distVboData"))
13381301

1339-
lineStyle = _proxyProperty(("lines", "style"))
1340-
13411302
lineColor = _proxyProperty(("lines", "color"))
13421303

13431304
lineGapColor = _proxyProperty(("lines", "gapColor"))
13441305

13451306
lineWidth = _proxyProperty(("lines", "width"))
13461307

1347-
lineDashPeriod = _proxyProperty(("lines", "dashPeriod"))
1308+
lineDashPattern = _proxyProperty(("lines", "dashPattern"))
13481309

13491310
marker = _proxyProperty(("points", "marker"))
13501311

@@ -1362,7 +1323,7 @@ def prepare(self):
13621323
"""Rendering preparation: build indices and bounding box vertices"""
13631324
if self.xVboData is None:
13641325
xAttrib, yAttrib, cAttrib, dAttrib = None, None, None, None
1365-
if self.lineStyle in (DASHED, DASHDOT, DOTTED):
1326+
if self.lineDashPattern:
13661327
dists = distancesFromArrays(self.xData, self.yData, self._ratio)
13671328
if self.colorData is None:
13681329
xAttrib, yAttrib, dAttrib = vertexBuffer(
@@ -1393,7 +1354,7 @@ def render(self, context):
13931354
13941355
:param RenderContext context: Rendering information
13951356
"""
1396-
if self.lineStyle in (DASHED, DASHDOT, DOTTED):
1357+
if self.lineDashPattern:
13971358
visibleRanges = context.plotFrame.transformedDataRanges
13981359
xLimits = visibleRanges.x
13991360
yLimits = visibleRanges.y if self.yaxis == "left" else visibleRanges.y2
@@ -1450,7 +1411,7 @@ def pick(self, xPickMin, yPickMin, xPickMax, yPickMax):
14501411
:rtype: Union[List[int],None]
14511412
"""
14521413
if (
1453-
(self.marker is None and self.lineStyle is None)
1414+
(self.marker is None and self.lineDashPattern is None)
14541415
or self.xMin > xPickMax
14551416
or xPickMin > self.xMax
14561417
or self.yMin > yPickMax
@@ -1464,7 +1425,7 @@ def pick(self, xPickMin, yPickMin, xPickMax, yPickMax):
14641425
yPickMin = yPickMin - self.offset[1]
14651426
yPickMax = yPickMax - self.offset[1]
14661427

1467-
if self.lineStyle is not None:
1428+
if self.lineDashPattern is not None:
14681429
# Using Cohen-Sutherland algorithm for line clipping
14691430
with numpy.errstate(invalid="ignore"): # Ignore NaN comparison warnings
14701431
codes = (

0 commit comments

Comments
 (0)