Skip to content

Commit

Permalink
Merge pull request #10 from sisl/version2
Browse files Browse the repository at this point in the history
Version2
  • Loading branch information
zsunberg committed Mar 9, 2018
2 parents f04a667 + a01700e commit cf8c6c3
Show file tree
Hide file tree
Showing 12 changed files with 427 additions and 19 deletions.
76 changes: 71 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,77 @@
# AutoViz

This package provides visualization tools for [AutomotiveDrivingModels](https://github.com/sisl/AutomotiveDrivingModels.jl).
Built off of PGFPlots and Cairo.

You can find the [documentation here](http://nbviewer.ipython.org/github/sisl/AutoViz.jl/blob/master/doc/AutoViz.ipynb).

[![Build Status](https://travis-ci.org/sisl/AutoViz.jl.svg?branch=master)](https://travis-ci.org/sisl/AutoViz.jl)
[![Coverage Status](https://coveralls.io/repos/sisl/AutoViz.jl/badge.svg)](https://coveralls.io/r/sisl/AutoViz.jl)

A package for rendering simple scenes primarily consisting of cars on roadways using Cairo.

AutoViz is undergoing significant changes. If you are looking for the version before these changes that is designed around AutomotiveDrivingModels.jl, please checkout the v0.6.0 tag.

![AutoViz](readmeimage.png)

## Usage

The main function is

```julia
render(scene)
```

where scene is an iterable of renderable objects including cars and roadways.

Example:
```julia
roadway = gen_straight_roadway(3, 100.0)
car = ArrowCar([0.0, 0.0], 0.0, color=colorant"blue") # [north, east], angle
render([roadway, car, "some text"])
```

### Renderable

*What does it mean to be "renderable"?*

An object is *directly renderable* if the function `render!(rm::RenderModel, object)` is implemented for it.

An object is *renderable by conversion* if `convert(Renderable, object)` returns a directly renderable object.

When `render()` is invoked, direct renderability is checked with `isrenderable(object)`, which defaults to `method_exists(render!, Tuple{RenderModel, typeof(object)})`. If this check fails, a conversion attempt is made with `convert(Renderable, object)`.

### Roadways and ArrowCars

The primary basic directly renderable types are `Roadway` (now from `AutomotiveDrivingModels`; soon from `Roadways.jl`) and `ArrowCar`.

`ArrowCar`s are the pink cars with arrows that are in everyone's videos. You can construct one like this:

```julia
using Colors
using AutoViz

# x, y, angle and velocity are from your simulation

ArrowCar(x, y, angle; color=colorant"green", text="v: $velocity")
```

### How to make types renderable

There are two ways to make renderable types.

1. You can make your existing types renderable by conversion by defining `convert(::Type{Renderable}, ::MyType)` which should return a directly renderable object, e.g. an `ArrowCar`.
2. You can make types directly renderable by defining `render!(::RenderModel, ::MyType)`. To make things easier for the compiler, you can also define `isrenderable(::Type{MyType}) = true`. If you want to allow others to convert to this type to make their types renderable by conversion, make your type a subtype of `Renderable`.

## Overlays

Overlays will function as in the previous version of AutoViz. They will be rendered last with `render!(rendermodel, overlay, scene)`.

## Additional keyword arguments for `render()`

The following additional keyword arguments will accepted by `render()`:

- `canvas_width`
- `canvas_height`
- `rendermodel`
- `overlays`
- `cam` - a camera controlling the field of view as in the previous version of AutoViz

## `RenderModel`s

The mid-level interface for this package (which is what you will use when you write `render!()` for your types or when you write an overlay) revolves around adding instructions to a `RenderModel`. Each instruction consists of a function and a tuple of arguments for the function. This is not documented in this readme, but it is fairly easy to figure out by reading `rendermodels.jl`, `overlays.jl`, and `arrowcar.jl`.
3 changes: 2 additions & 1 deletion REQUIRE
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ Cairo
Reel
Interact
NBInclude
Parameters
Parameters
StaticArrays
16 changes: 13 additions & 3 deletions doc/AutoViz.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,17 @@
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"\u001b[1m\u001b[36mINFO: \u001b[39m\u001b[22m\u001b[36mPrecompiling module AutoViz.\n",
"\u001b[39mWARNING: Method definition (::Type{AutoViz.CarFollowCamera{I} where I})(I, Float64) in module AutoViz at C:\\Users\\ekhla\\AppData\\Local\\JuliaPro-0.6.1.1\\pkgs-0.6.1.1\\v0.6\\AutoViz\\src\\cameras.jl:43 overwritten at C:\\Users\\ekhla\\AppData\\Local\\JuliaPro-0.6.1.1\\pkgs-0.6.1.1\\v0.6\\AutoViz\\src\\cameras.jl:46.\n",
"WARNING: Method definition (::Type{AutoViz.CarFollowCamera{I} where I})(I, Float64) in module AutoViz at C:\\Users\\ekhla\\AppData\\Local\\JuliaPro-0.6.1.1\\pkgs-0.6.1.1\\v0.6\\AutoViz\\src\\cameras.jl:43 overwritten at C:\\Users\\ekhla\\AppData\\Local\\JuliaPro-0.6.1.1\\pkgs-0.6.1.1\\v0.6\\AutoViz\\src\\cameras.jl:46.\n"
]
}
],
"source": [
"using AutomotiveDrivingModels\n",
"using AutoViz"
Expand Down Expand Up @@ -545,15 +555,15 @@
"metadata": {
"anaconda-cloud": {},
"kernelspec": {
"display_name": "Julia 0.6.0",
"display_name": "Julia 0.6.1",
"language": "julia",
"name": "julia-0.6"
},
"language_info": {
"file_extension": ".jl",
"mimetype": "application/julia",
"name": "julia",
"version": "0.6.0"
"version": "0.6.1"
}
},
"nbformat": 4,
Expand Down
182 changes: 182 additions & 0 deletions notebooks/tutorial.ipynb

Large diffs are not rendered by default.

15 changes: 13 additions & 2 deletions src/AutoViz.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ module AutoViz

using Reexport
using Parameters
using StaticArrays
using AutomotiveDrivingModels

@reexport using Colors
Expand All @@ -16,7 +17,13 @@ export
DEFAULT_CANVAS_WIDTH,
DEFAULT_CANVAS_HEIGHT,
render!,
get_pastel_car_colors
get_pastel_car_colors,

render,
isrenderable,

ArrowCar


const DEFAULT_CANVAS_WIDTH = 1000
const DEFAULT_CANVAS_HEIGHT = 600
Expand All @@ -25,6 +32,11 @@ include("colorscheme.jl")
include("rendermodels.jl")

include("cameras.jl")

include("renderable.jl")
include("arrowcar.jl")
include("text.jl")

include("interface.jl")
include("overlays.jl")
include("reel_drive.jl")
Expand All @@ -33,5 +45,4 @@ include("1d/main.jl")
include("2d/main.jl")



end # module
24 changes: 24 additions & 0 deletions src/arrowcar.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#TODO: Add doc string
@with_kw struct ArrowCar{A<:AbstractArray{Float64}, C<:Colorant} <: Renderable
pos::A = SVector(0.0, 0.0)
angle::Float64 = 0.0
length::Float64 = 4.8
width::Float64 = 1.8
color::C = COLOR_CAR_OTHER
text::String = "" # some debugging text to print by the car
id::Int = 0
end

ArrowCar(pos::AbstractArray, angle::Float64=0.0; length = 4.8, width = 1.8, color=COLOR_CAR_OTHER, text="", id=0) = ArrowCar(pos, angle, length, width, color, text, id)
ArrowCar(x::Real, y::Real, angle::Float64=0.0; length = 4.8, width = 1.8, color=COLOR_CAR_OTHER, text="", id=0) = ArrowCar(SVector(x, y), angle, length, width, color, text, id)

function render!(rm::RenderModel, c::ArrowCar)
x = c.pos[1]
y = c.pos[2]
add_instruction!(rm, render_vehicle, (x, y, c.angle, c.length, c.width, c.color))
add_instruction!(rm, render_text, (c.text, x, y-c.width/2 - 2.0, 10, colorant"white"))
return rm
end

id(ac::ArrowCar) = ac.id
pos(ac::ArrowCar) = ac.pos
27 changes: 23 additions & 4 deletions src/cameras.jl
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ function camera_set!(rendermodel::RenderModel, cam::StaticCamera, canvas_width::
end
camera_set!{S,D,I,R}(rendermodel::RenderModel, cam::StaticCamera, scene::EntityFrame{S,D,I}, roadway::R, canvas_width::Int, canvas_height::Int) = camera_set!(rendermodel, cam, canvas_width, canvas_height)

# method for new interface
camera_set!(rm::RenderModel, cam::StaticCamera, scene, canvas_width::Int, canvas_height::Int) = camera_set!(rm, cam, canvas_width, canvas_height)

mutable struct FitToContentCamera <: Camera
percent_border::Float64
FitToContentCamera(percent_border::Float64=0.1) = new(percent_border)
Expand All @@ -33,12 +36,14 @@ function camera_set!(rendermodel::RenderModel, cam::FitToContentCamera, canvas_w
end
camera_set!{S,D,I,R}(rendermodel::RenderModel, cam::FitToContentCamera, scene::EntityFrame{S,D,I}, roadway::R, canvas_width::Int, canvas_height::Int) = camera_set!(rendermodel, cam, canvas_width, canvas_height)

# method for new interface
camera_set!(rendermodel::RenderModel, cam::FitToContentCamera, scene, canvas_width::Int, canvas_height::Int) = camera_set!(rendermodel, cam, canvas_width, canvas_height)

mutable struct CarFollowCamera{I} <: Camera
targetid::I
zoom::Float64 # [pix/meter]

CarFollowCamera{I}(targetid::I, zoom::Float64=3.0) where {I} = new(targetid, zoom)
end
CarFollowCamera(targetid::I) where {I} = CarFollowCamera{I}(targetid, 3.0)

function camera_set!{S<:State1D,D,I,R}(rendermodel::RenderModel, cam::CarFollowCamera{I}, scene::EntityFrame{S,D,I}, roadway::R, canvas_width::Int, canvas_height::Int)

Expand Down Expand Up @@ -67,6 +72,22 @@ function camera_set!{S<:VehicleState,D,I,R}(rendermodel::RenderModel, cam::CarFo
rendermodel
end

# method for new interface
function camera_set!(rendermodel::RenderModel, cam::CarFollowCamera, scene, canvas_width::Int, canvas_height::Int)

inds = find(x -> x isa ArrowCar && id(x) == cam.targetid, scene)
if isempty(inds)
add_instruction!( rendermodel, render_text, (@sprintf("CarFollowCamera did not find an ArrowCar with id %d", cam.targetid), 10, 15, 15, colorant"white"), incameraframe=false)
camera_fit_to_content!(rendermodel, canvas_width, canvas_height)
else
veh_index = first(inds)
camera_set_pos!(rendermodel, pos(scene[veh_index])...)
camera_setzoom!(rendermodel, cam.zoom)
end

rendermodel
end

mutable struct SceneFollowCamera <: Camera
zoom::Float64 # [pix/meter]
SceneFollowCamera(zoom::Float64=3.0) = new(zoom)
Expand Down Expand Up @@ -113,5 +134,3 @@ function camera_set!{S<:VehicleState,D,I,R}(rendermodel::RenderModel, cam::Scene

rendermodel
end


4 changes: 2 additions & 2 deletions src/interface.jl
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ function render!{S,D,I}(
rendermodel
end

function render{R}(roadway::R;
function render{R<:Roadway}(roadway::R;
canvas_width::Int=DEFAULT_CANVAS_WIDTH,
canvas_height::Int=DEFAULT_CANVAS_HEIGHT,
rendermodel = RenderModel(),
Expand Down Expand Up @@ -69,4 +69,4 @@ function get_pastel_car_colors{S,D,I}(scene::EntityFrame{S,D,I}; saturation::Flo
retval[veh.id] = convert(RGB, HSV(180*(i-1)/max(n-1,1), saturation, value))
end
return retval
end
end
14 changes: 13 additions & 1 deletion src/overlays.jl
Original file line number Diff line number Diff line change
Expand Up @@ -87,11 +87,23 @@ function render!{S,D,I,R}(rendermodel::RenderModel, overlay::TextOverlay, scene:
rendermodel
end

# method for new interface
function render!(rendermodel::RenderModel, overlay::TextOverlay, scene)
x = overlay.pos.x
y = overlay.pos.y
y_jump = overlay.line_spacing*overlay.font_size
for line in overlay.text
add_instruction!(rendermodel, render_text, (line, x, y, overlay.font_size, overlay.color), incameraframe=overlay.incameraframe)
y += y_jump
end
rendermodel
end


mutable struct Overwash <: SceneOverlay
color::Colorant
end
function render!{S,D,I,R}(rendermodel::RenderModel, overlay::Overwash, scene::EntityFrame{S,D,I}, roadway::R)
add_instruction!(rendermodel, render_paint, (overlay.color,))
rendermodel
end

59 changes: 59 additions & 0 deletions src/renderable.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#TODO: Renderable type
abstract type Renderable end

"""
Return true if an object or type is *directly renderable*, false otherwise.
New types should implement the `isrenderable(t::Type{NewType})` method.
"""
function isrenderable end

isrenderable(object) = isrenderable(typeof(object))
isrenderable(::Type{R}) where R <: Renderable = true
isrenderable(t::Type) = method_exists(render!, Tuple{RenderModel, t})
isrenderable(t::Type{Roadway}) = true


function render(scene; # iterable of renderable objects
overlays=[],
rendermodel::RenderModel=RenderModel(),
cam::Camera=FitToContentCamera(),
canvas_height::Int=DEFAULT_CANVAS_HEIGHT,
canvas_width::Int=DEFAULT_CANVAS_WIDTH
)

s = CairoRGBSurface(canvas_width, canvas_height)
ctx = creategc(s)
clear_setup!(rendermodel)

for x in scene
if isrenderable(x)
render!(rendermodel, x)
else
render!(rendermodel, convert(Renderable, x))
end
end

for o in overlays
render!(rendermodel, o, scene)
end

camera_set!(rendermodel, cam, scene, canvas_width, canvas_height)

render(rendermodel, ctx, canvas_width, canvas_height)
return s
end

function Base.convert(::Type{Renderable}, x::AbstractVector{R}) where R <: Real
@assert length(x) >= 2
if length(x) == 2
ac = ArrowCar(SVector(x[1],x[2]))
else
ac = ArrowCar(SVector(x[1],x[2]), x[3])
end
ac
end
#TODO: Tutorial notebook -> roadways, arrow cars, how to convert: Ekhlas

#TODO: test -> run tutorial notebook, default conversions, isrenderable(), etc.: Ekhlas
#TODO: Hints for figuring out rendermodels: Zach
13 changes: 13 additions & 0 deletions src/text.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
isrenderable(::Type{String}) = true

function render!(rm::RenderModel, t::String)
font_size = 10
x = 10
y = font_size
y_jump = 1.5 * font_size
for line in split(t, '\n')
add_instruction!(rm, render_text, (line, x, y, font_size, colorant"white"), incameraframe=true)
y += y_jump
end
return rm
end
13 changes: 12 additions & 1 deletion test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,17 @@ using Base.Test
using AutomotiveDrivingModels
using AutoViz
using NBInclude
using Colors

nbinclude(Pkg.dir("AutoViz", "doc", "AutoViz.ipynb"))
nbinclude(Pkg.dir("AutoViz", "notebooks", "tutorial.ipynb"))

nbinclude(Pkg.dir("AutoViz", "doc", "AutoViz.ipynb"))
rw = gen_straight_roadway(3, 100.0)
car = ArrowCar(0.0, 0.0, 0.0, id=1)
car2 = ArrowCar(1.0, 1.0, 1.0, color=colorant"green", text="text")

render([rw, car, "some text"])

render([rw, car, car2, "some text"], cam=CarFollowCamera(0))

render([rw, car, car2], overlays=[TextOverlay(text=["overlay"], color=colorant"blue")])

0 comments on commit cf8c6c3

Please sign in to comment.