@@ -27,7 +27,8 @@ function draw_atomic(scene::Scene, screen::CairoScreen, primitive::Union{Lines,
2727 end
2828 end
2929
30- projected_positions = project_position .(Ref (scene), positions, Ref (model))
30+ space = to_value (get (primitive, :space , :data ))
31+ projected_positions = project_position .(Ref (scene), Ref (space), positions, Ref (model))
3132
3233 if color isa AbstractArray{<: Number }
3334 color = numbers_to_colors (color, primitive)
@@ -194,22 +195,12 @@ function draw_atomic(scene::Scene, screen::CairoScreen, primitive::Scatter)
194195 strokewidth, marker, marker_offset, remove_billboard (rotations)) do point, col,
195196 markersize, strokecolor, strokewidth, marker, mo, rotation
196197
197- # if we give size in pixels, the size is always equal to that value
198- is_pixelspace = haskey (primitive, :markerspace ) && primitive. markerspace[] == Makie. Pixel
199- scale = if is_pixelspace
200- Makie. to_2d_scale (markersize)
201- else
202- # otherwise calculate a scaled size
203- project_scale (scene, markersize, size_model)
204- end
205- offset = if is_pixelspace
206- Makie. to_2d_scale (mo)
207- else
208- project_scale (scene, mo, size_model)
209- end
210-
211- pos = project_position (scene, point, model)
198+ markerspace = to_value (get (primitive, :markerspace , :pixel ))
199+ scale = project_scale (scene, markerspace, markersize, size_model)
200+ offset = project_scale (scene, markerspace, mo, size_model)
212201
202+ space = to_value (get (primitive, :space , :data ))
203+ pos = project_position (scene, space, point, model)
213204 isnan (pos) && return
214205
215206 Cairo. set_source_rgba (ctx, rgbatuple (col)... )
@@ -276,17 +267,27 @@ function draw_marker(ctx, marker::Char, font, pos, scale, strokecolor, strokewid
276267end
277268
278269function draw_marker (ctx, marker:: Circle , pos, scale, strokecolor, strokewidth, marker_offset, rotation)
279-
280270 marker_offset = marker_offset + scale ./ 2
281271 pos += Point2f (marker_offset[1 ], - marker_offset[2 ])
282- Cairo. arc (ctx, pos[1 ], pos[2 ], scale[1 ]/ 2 , 0 , 2 * pi )
272+
273+ if scale[1 ] != scale[2 ]
274+ old_matrix = Cairo. get_matrix (ctx)
275+ Cairo. scale (ctx, scale[1 ], scale[2 ])
276+ Cairo. translate (ctx, pos[1 ]/ scale[1 ], pos[2 ]/ scale[2 ])
277+ Cairo. arc (ctx, 0 , 0 , 0.5 , 0 , 2 * pi )
278+ else
279+ Cairo. arc (ctx, pos[1 ], pos[2 ], scale[1 ]/ 2 , 0 , 2 * pi )
280+ end
281+
283282 Cairo. fill_preserve (ctx)
284283
285284 Cairo. set_line_width (ctx, Float64 (strokewidth))
286285
287286 sc = to_color (strokecolor)
288287 Cairo. set_source_rgba (ctx, rgbatuple (sc)... )
289288 Cairo. stroke (ctx)
289+ scale[1 ] != scale[2 ] && Cairo. set_matrix (ctx, old_matrix)
290+ nothing
290291end
291292
292293function draw_marker (ctx, marker:: Rect , pos, scale, strokecolor, strokewidth, marker_offset, rotation)
@@ -316,31 +317,37 @@ end
316317
317318function draw_atomic (scene:: Scene , screen:: CairoScreen , primitive:: Text{<:Tuple{<:G}} ) where G <: Union{AbstractArray{<:Makie.GlyphCollection}, Makie.GlyphCollection}
318319 ctx = screen. context
319- @get_attribute (primitive, (rotation, model, space, offset))
320+ @get_attribute (primitive, (rotation, model, space, markerspace, offset))
320321 position = primitive. position[]
321322 # use cached glyph info
322323 glyph_collection = to_value (primitive[1 ])
323324
324- draw_glyph_collection (scene, ctx, position, glyph_collection, remove_billboard (rotation), model, space, offset)
325+ draw_glyph_collection (
326+ scene, ctx, position, glyph_collection, remove_billboard (rotation),
327+ model, space, markerspace, offset
328+ )
325329
326330 nothing
327331end
328332
329333
330- function draw_glyph_collection (scene, ctx, positions, glyph_collections:: AbstractArray , rotation, model:: SMatrix , space, offset)
334+ function draw_glyph_collection (
335+ scene, ctx, positions, glyph_collections:: AbstractArray , rotation,
336+ model:: SMatrix , space, markerspace, offset
337+ )
331338
332339 # TODO : why is the Ref around model necessary? doesn't broadcast_foreach handle staticarrays matrices?
333- broadcast_foreach (positions, glyph_collections, rotation,
334- Ref (model), space, offset) do pos, glayout, ro, mo, sp, off
340+ broadcast_foreach (positions, glyph_collections, rotation, Ref (model), space,
341+ markerspace, offset) do pos, glayout, ro, mo, sp, msp , off
335342
336- draw_glyph_collection (scene, ctx, pos, glayout, ro, mo, sp, off)
343+ draw_glyph_collection (scene, ctx, pos, glayout, ro, mo, sp, msp, off)
337344 end
338345end
339346
340347_deref (x) = x
341348_deref (x:: Ref ) = x[]
342349
343- function draw_glyph_collection (scene, ctx, position, glyph_collection, rotation, model, space, offsets)
350+ function draw_glyph_collection (scene, ctx, position, glyph_collection, rotation, model, space, markerspace, offsets)
344351
345352 glyphs = glyph_collection. glyphs
346353 glyphoffsets = glyph_collection. origins
@@ -351,6 +358,8 @@ function draw_glyph_collection(scene, ctx, position, glyph_collection, rotation,
351358 strokewidths = glyph_collection. strokewidths
352359 strokecolors = glyph_collection. strokecolors
353360
361+ s2ms = Makie. clip_to_space (scene. camera, markerspace) * Makie. space_to_clip (scene. camera, space)
362+
354363 Cairo. save (ctx)
355364
356365 broadcast_foreach (glyphs, glyphoffsets, fonts, rotations, scales, colors, strokewidths, strokecolors, offsets) do glyph,
@@ -366,83 +375,43 @@ function draw_glyph_collection(scene, ctx, position, glyph_collection, rotation,
366375 Cairo. save (ctx)
367376 Cairo. set_source_rgba (ctx, rgbatuple (color)... )
368377
369- if space == :data
370- # in data space, the glyph offsets are just added to the string positions
371- # and then projected
372-
373- # glyph position in data coordinates (offset has rotation applied already)
374- gpos_data = to_ndim (Point3f, position, 0 ) .+ glyphoffset .+ p3_offset
375-
376- scale3 = scale isa Number ? Point3f (scale, scale, 0 ) : to_ndim (Point3f, scale, 0 )
377-
378- # this could be done better but it works at least
379-
380- # the CairoMatrix is found by transforming the right and up vector
381- # of the character into screen space and then subtracting the projected
382- # origin. The resulting vectors give the directions in which the character
383- # needs to be stretched in order to match the 3D projection
384-
385- xvec = rotation * (scale3[1 ] * Point3f (1 , 0 , 0 ))
386- yvec = rotation * (scale3[2 ] * Point3f (0 , - 1 , 0 ))
387-
388- glyphpos = project_position (scene, gpos_data, _deref (model))
389- xproj = project_position (scene, gpos_data + xvec, _deref (model))
390- yproj = project_position (scene, gpos_data + yvec, _deref (model))
391-
392- xdiff = xproj - glyphpos
393- ydiff = yproj - glyphpos
394-
395- mat = Cairo. CairoMatrix (
396- xdiff[1 ], xdiff[2 ],
397- ydiff[1 ], ydiff[2 ],
398- 0 , 0 ,
399- )
400-
401- elseif space == :screen
402- # in screen space, the glyph offsets are added after projecting
403- # the string position into screen space
404- glyphpos = let
405- # project without yflip - we need to apply model before that
406- p = project_position (scene, position, Mat4f (I), false )
407-
408- # flip for Cairo
409- p += (p3_to_p2 (glyphoffset .+ p3_offset))
410- p = (_deref (model) * Vec4f (p[1 ], p[2 ], 0 , 1 ))[Vec (1 , 2 )]
411- p = (0 , 1 ) .* scene. camera. resolution[] .+ p .* (1 , - 1 )
412- p
413- end
414- # and the scale is just taken as is
415- scale = length (scale) == 2 ? scale : SVector (scale, scale)
416-
417- mat = let
418- scale_mat = if length (scale) == 2
419- Mat2f (scale[1 ], 0 , 0 , scale[2 ])
420- else
421- Mat2f (scale, 0 , 0 , scale)
422- end
423- T = _deref (model)[Vec (1 , 2 ), Vec (1 , 2 )] * scale_mat
424- Cairo. CairoMatrix (T[1 , 1 ], T[1 , 2 ], T[2 , 1 ], T[2 , 2 ], 0 , 0 )
425- end
426- else
427- error ()
428- end
378+ # offsets and scale apply in markerspace
379+ glyph_pos = s2ms * to_ndim (Point4f, to_ndim (Point3f, position, 0 ), 1 )
380+ gp3 = glyph_pos[SOneTo (3 )] ./ glyph_pos[4 ] .+ glyphoffset .+ p3_offset
381+
382+ scale3 = scale isa Number ? Point3f (scale, scale, 0 ) : to_ndim (Point3f, scale, 0 )
383+
384+ # the CairoMatrix is found by transforming the right and up vector
385+ # of the character into screen space and then subtracting the projected
386+ # origin. The resulting vectors give the directions in which the character
387+ # needs to be stretched in order to match the 3D projection
388+
389+ xvec = rotation * (scale3[1 ] * Point3f (1 , 0 , 0 ))
390+ yvec = rotation * (scale3[2 ] * Point3f (0 , - 1 , 0 ))
391+
392+ glyphpos = project_position (scene, markerspace, gp3, _deref (model))
393+ xproj = project_position (scene, markerspace, gp3 + xvec, _deref (model))
394+ yproj = project_position (scene, markerspace, gp3 + yvec, _deref (model))
395+
396+ xdiff = xproj - glyphpos
397+ ydiff = yproj - glyphpos
398+
399+ mat = Cairo. CairoMatrix (
400+ xdiff[1 ], xdiff[2 ],
401+ ydiff[1 ], ydiff[2 ],
402+ 0 , 0 ,
403+ )
429404
430405 Cairo. save (ctx)
431406 Cairo. move_to (ctx, glyphpos... )
432407 set_font_matrix (ctx, mat)
433- if space == :screen
434- Cairo. rotate (ctx, to_2d_rotation (rotation))
435- end
436408 Cairo. show_text (ctx, string (glyph))
437409 Cairo. restore (ctx)
438410
439411 if strokewidth > 0 && strokecolor != RGBAf (0 , 0 , 0 , 0 )
440412 Cairo. save (ctx)
441413 Cairo. move_to (ctx, glyphpos... )
442414 set_font_matrix (ctx, mat)
443- if space == :screen
444- Cairo. rotate (ctx, to_2d_rotation (rotation))
445- end
446415 Cairo. text_path (ctx, string (glyph))
447416 Cairo. set_source_rgba (ctx, rgbatuple (strokecolor)... )
448417 Cairo. set_line_width (ctx, strokewidth)
@@ -548,8 +517,9 @@ function draw_atomic(scene::Scene, screen::CairoScreen, primitive::Union{Heatmap
548517
549518 # find projected image corners
550519 # this already takes care of flipping the image to correct cairo orientation
551- xy = project_position (scene, Point2f (first .(imsize)), model)
552- xymax = project_position (scene, Point2f (last .(imsize)), model)
520+ space = to_value (get (primitive, :space , :data ))
521+ xy = project_position (scene, space, Point2f (first .(imsize)), model)
522+ xymax = project_position (scene, space, Point2f (last .(imsize)), model)
553523 w, h = xymax .- xy
554524
555525 s = to_cairo_image (image, primitive)
@@ -580,7 +550,8 @@ function draw_atomic(scene::Scene, screen::CairoScreen, primitive::Union{Heatmap
580550 end
581551 # find projected image corners
582552 # this already takes care of flipping the image to correct cairo orientation
583- xys = [project_position (scene, Point2f (x, y), model) for x in xs, y in ys]
553+ space = to_value (get (primitive, :space , :data ))
554+ xys = [project_position (scene, space, Point2f (x, y), model) for x in xs, y in ys]
584555 colors = to_rgba_image (image, primitive)
585556
586557 # Note: xs and ys should have size ni+1, nj+1
@@ -597,11 +568,11 @@ function draw_atomic(scene::Scene, screen::CairoScreen, primitive::Union{Heatmap
597568
598569 # Rectangles and polygons that are directly adjacent usually show
599570 # white lines between them due to anti aliasing. To avoid this we
600- # increase their size slightly.
571+ # increase their size slightly.
601572
602573 if alpha (colors[i, j]) == 1
603- # sign.(p - center) gives the direction in which we need to
604- # extend the polygon. (Which may change due to rotations in the
574+ # sign.(p - center) gives the direction in which we need to
575+ # extend the polygon. (Which may change due to rotations in the
605576 # model matrix.) (i!=1) etc is used to avoid increasing the
606577 # outer extent of the heatmap.
607578 center = 0.25 * (p1 + p2 + p3 + p4)
@@ -657,8 +628,9 @@ function draw_mesh2D(scene, screen, primitive)
657628 pattern = Cairo. CairoPatternMesh ()
658629
659630 cols = per_face_colors (color, colormap, colorrange, nothing , vs, fs, nothing , uv)
631+ space = to_value (get (primitive, :space , :data ))
660632 for (f, (c1, c2, c3)) in zip (fs, cols)
661- t1, t2, t3 = project_position .(scene, vs[f], (model,)) # triangle points
633+ t1, t2, t3 = project_position .(scene, space, vs[f], (model,)) # triangle points
662634 Cairo. mesh_pattern_begin_patch (pattern)
663635
664636 Cairo. mesh_pattern_move_to (pattern, t1... )
@@ -700,9 +672,10 @@ function draw_mesh3D(
700672 ctx = screen. context
701673
702674 model = primitive. model[]
703- view = scene. camera. view[]
704- projection = scene. camera. projection[]
705- i = SOneTo (3 )
675+ space = to_value (get (primitive, :space , :data ))
676+ view = ifelse (is_data_space (space), scene. camera. view[], Mat4f (I))
677+ projection = Makie. space_to_clip (scene. camera, space, false )
678+ i = Vec (1 , 2 , 3 )
706679 normalmatrix = transpose (inv (view[i, i] * model[i, i]))
707680
708681 # Mesh data
0 commit comments