diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 33d975ae..28869a4c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -48,12 +48,18 @@ jobs: - uses: actions/checkout@v2 - uses: julia-actions/setup-julia@v1 with: - version: '1.5' + version: '1.6' - run: | julia --project=docs -e ' using Pkg Pkg.develop(PackageSpec(path=pwd())) Pkg.instantiate()' + - run: | + julia --project=docs -e ' + using Documenter: doctest, DocMeta + using GeometryBasics + DocMeta.setdocmeta!(GeometryBasics, :DocTestSetup, :(using GeometryBasics); recursive=true) + doctest(GeometryBasics)' - run: julia --project=docs docs/make.jl env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore index cd69cdbd..8e582249 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ .DS_Store /Manifest.toml docs/build/ +*~ diff --git a/README.md b/README.md index 2aaad55b..a0b6738c 100644 --- a/README.md +++ b/README.md @@ -2,101 +2,36 @@ [![Build Status](https://api.travis-ci.org/JuliaGeometry/GeometryBasics.jl.svg?branch=master)](https://travis-ci.com/JuliaGeometry/GeometryBasics.jl) [![Codecov](https://codecov.io/gh/JuliaGeometry/GeometryBasics.jl/branch/master/graph/badge.svg)](https://codecov.io/gh/JuliaGeometry/GeometryBasics.jl) -**Documentation**: [![Docs - stable](https://img.shields.io/badge/docs-stable-lightgrey.svg)](http://juliageometry.github.io/GeometryBasics.jl/stable/) -[![Docs - dev](https://img.shields.io/badge/docs-dev-blue.svg)](http://juliageometry.github.io/GeometryBasics.jl/dev) +[![Docs - dev](https://img.shields.io/badge/docs-dev-blue.svg)](http://juliageometry.github.io/GeometryBasics.jl/dev/) # GeometryBasics.jl -Basic Geometry Types. -This package aims to offer a standard set of Geometry types, which easily work with metadata, query frameworks on geometries and different memory layouts. -The aim is to create a solid basis for Graphics/Plotting, finite elements analysis, Geo applications, and general geometry manipulations - while offering a julian API, that still allows performant C-interop. +Basic geometry types. -This package is a replacement for the discontinued [GeometryTypes](https://github.com/JuliaGeometry/GeometryTypes.jl/). - -## Quick start - -```julia -using GeometryBasics - -# create some points -julia> p1 = Point(3, 1) -2-element Point{2,Int64} with indices SOneTo(2): - 3 - 1 - -julia> p2 = Point(1, 3); - -julia> p3 = Point(4, 4); - -# geometries can carry metadata -julia> poi = meta(p1, city="Abuja", rainfall=1221.2) -2-element PointMeta{2,Int64,Point{2,Int64},(:city, :rainfall),Tuple{String,Float64}} with indices SOneTo(2): - 3 - 1 - -# metadata is stored in a NamedTuple and can be retrieved as such -julia> meta(poi) -(city = "Abuja", rainfall = 1221.2) - -# specific metadata attributes can be directly retrieved -julia> poi.rainfall -1221.2 +This package aims to offer a standard set of geometry types that easily work +with metadata, query frameworks on geometries and different memory layouts. The +aim is to create a solid basis for graphics/plotting, finite element analysis, +geo applications, and general geometry manipulations - while offering a Julian +API that still allows performant C-interop. -# to remove the metadata and keep only the geometry, use metafree -julia> metafree(poi) -2-element Point{2,Int64} with indices SOneTo(2): - 3 - 1 - -# for other geometries metatypes are predefined -julia> multipoi = MultiPointMeta([p1], city="Abuja", rainfall=1221.2) -1-element MultiPointMeta{Point{2,Int64},MultiPoint{2,Int64,Point{2,Int64},Array{Point{2,Int64},1}},(:city, :rainfall),Tuple{String,Float64}}: -[3, 1] - -# connect the points with lines -julia> l1 = Line(p1, p2) -Line([3, 1] => [1, 3]) - -julia> l2 = Line(p2, p3); - -# connect the lines in a linestring -julia> LineString([l1, l2]) -2-element LineString{2,Int64,Point{2,Int64},Array{GeometryBasics.Ngon{2,Int64,2,Point{2,Int64}},1}}: - Line([3, 1] => [1, 3]) - Line([1, 3] => [4, 4]) - -# linestrings can also be constructed directly from points -julia> LineString([p1, p2, p3]) -2-element LineString{2,Int64,Point{2,Int64},Base.ReinterpretArray{GeometryBasics.Ngon{2,Int64,2,Point{2,Int64}},1,Tuple{Point{2,Int64},Point{2,Int64}},TupleView{Tuple{Point{2,Int64},Point{2,Int64}}, 1}}}: - Line([3, 1] => [1, 3]) - Line([1, 3] => [4, 4]) +This package is a replacement for the discontinued [GeometryTypes](https://github.com/JuliaGeometry/GeometryTypes.jl/). -# the same goes for polygons -julia> Polygon(Point{2, Int}[(3, 1), (4, 4), (2, 4), (1, 2), (3, 1)]) -Polygon{2,Int64,Point{2,Int64},LineString{2,Int64,Point{2,Int64},Base.ReinterpretArray{GeometryBasics.Ngon{2,Int64,2,Point{2,Int64}},1,Tuple{Point{2,Int64},Point{2,Int64}},TupleView{Tuple{Point{2,Int64},Point{2,Int64}}, 1}}},Array{LineString{2,Int64,Point{2,Int64},Base.ReinterpretArray{GeometryBasics.Ngon{2,Int64,2,Point{2,Int64}},1,Tuple{Point{2,Int64},Point{2,Int64}},TupleView{Tuple{Point{2,Int64},Point{2,Int64}}, 1}}},1}}(GeometryBasics.Ngon{2,Int64,2,Point{2,Int64}}[Line([3, 1] => [4, 4]), Line([4, 4] => [2, 4]), Line([2, 4] => [1, 2]), Line([1, 2] => [3, 1])], LineString{2,Int64,Point{2,Int64},Base.ReinterpretArray{GeometryBasics.Ngon{2,Int64,2,Point{2,Int64}},1,Tuple{Point{2,Int64},Point{2,Int64}},TupleView{Tuple{Point{2,Int64},Point{2,Int64}}, 1}}}[]) +**Documentation:** http://juliageometry.github.io/GeometryBasics.jl/stable/ -# create a rectangle placed at the origin with unit widths -julia> rect = Rect(Vec(0.0, 0.0), Vec(1.0, 1.0)) -GeometryBasics.HyperRectangle{2,Float64}([0.0, 0.0], [1.0, 1.0]) +## Contributing -# decompose the rectangle into two triangular faces -julia> rect_faces = decompose(TriangleFace{Int}, rect) -2-element Array{NgonFace{3,Int64},1}: - TriangleFace(1, 2, 4) - TriangleFace(1, 4, 3) +Make sure your changes don't break the documentation. -# decompose the rectangle into four vertices -julia> rect_vertices = decompose(Point{2, Float64}, rect) -4-element Array{Point{2,Float64},1}: - [0.0, 0.0] - [1.0, 0.0] - [0.0, 1.0] - [1.0, 1.0] +To build the documentation locally, you first need to instantiate the `docs/` project: -# combine the vertices and faces into a triangle mesh -julia> mesh = Mesh(rect_vertices, rect_faces) -Mesh{2, Float64, Triangle}: - Triangle([0.0, 0.0], [1.0, 0.0], [1.0, 1.0]) - Triangle([0.0, 0.0], [1.0, 1.0], [0.0, 1.0]) ``` +julia --project=docs/ +pkg> instantiate +pkg> dev . +``` + +Then use `julia --project=docs/ docs/make.jl` to build the documentation. This +will also run the doctests defined in Markdown files. The doctests should be +written for the Julia version configured in [ci.yml](.github/workflows/ci.yml) +(`:docs` section). diff --git a/docs/make.jl b/docs/make.jl index a9a3a351..f3e3b90c 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -6,12 +6,18 @@ using GeometryBasics DocMeta.setdocmeta!(GeometryBasics, :DocTestSetup, :(using GeometryBasics); recursive=true) -# Copy the README to serve as the homepage -cp(joinpath(@__DIR__, "..", "README.md"), joinpath(@__DIR__, "src", "index.md")) - -makedocs(format=Documenter.HTML(), sitename="GeometryBasics.jl", - pages=["index.md", "primitives.md", "rectangles.md", "polygons.md", "meshes.md", - "decomposition.md", "distancefields.md", "metadata.md", "api.md"], +makedocs(format=Documenter.HTML(prettyurls=get(ENV, "CI", "false") == "true"), + sitename="GeometryBasics.jl", + pages=[ + "index.md", + "primitives.md", + "rectangles.md", + "polygons.md", + "meshes.md", + "decomposition.md", + "metadata.md", + "api.md" + ], modules=[GeometryBasics]) deploydocs(repo="github.com/JuliaGeometry/GeometryBasics.jl.git", push_preview=true) diff --git a/docs/src/decomposition.md b/docs/src/decomposition.md index 698c07bc..65c3d75a 100644 --- a/docs/src/decomposition.md +++ b/docs/src/decomposition.md @@ -1,9 +1,9 @@ # Decomposition -## GeometryBasic Mesh interface +## GeometryBasics Mesh interface -GeometryBasic defines an interface, to decompose abstract geometries into +GeometryBasics defines an interface to decompose abstract geometries into points and triangle meshes. This can be done for any arbitrary primitive, by overloading the following interface: @@ -39,7 +39,7 @@ m = GeometryBasics.mesh(Tesselation(rect, (50, 50))) length(coordinates(m)) == 50^2 ``` -As you can see, `coordinates` and `faces` is also defined on a mesh +As you can see, `coordinates` and `faces` are also defined on a mesh ```julia coordinates(m) faces(m) diff --git a/docs/src/distancefields.md b/docs/src/distancefields.md deleted file mode 100644 index 5d9009ee..00000000 --- a/docs/src/distancefields.md +++ /dev/null @@ -1 +0,0 @@ -# Distance Fields diff --git a/docs/src/index.md b/docs/src/index.md new file mode 100644 index 00000000..a50427af --- /dev/null +++ b/docs/src/index.md @@ -0,0 +1,108 @@ +# GeometryBasics.jl + +Basic geometry types. + +This package aims to offer a standard set of geometry types that easily work +with metadata, query frameworks on geometries and different memory layouts. The +aim is to create a solid basis for graphics/plotting, finite element analysis, +geo applications, and general geometry manipulations - while offering a Julian +API that still allows performant C-interop. + +This package is a replacement for the discontinued [GeometryTypes](https://github.com/JuliaGeometry/GeometryTypes.jl/). + +## Quick start + +Create some points: + +```@repl quickstart +using GeometryBasics + +p1 = Point(3, 1) +p2 = Point(1, 3); +p3 = Point(4, 4); +``` + +Geometries can carry metadata: + +```@repl quickstart +poi = meta(p1, city="Abuja", rainfall=1221.2) +``` + +Metadata is stored in a NamedTuple and can be retrieved as such: + +```@repl quickstart +meta(poi) +``` + +Specific metadata attributes can be directly retrieved: + +```@repl quickstart +poi.rainfall +``` + +To remove the metadata and keep only the geometry, use `metafree`: + +```@repl quickstart +metafree(poi) +``` + +Geometries have predefined metatypes: + +```@repl quickstart +multipoi = MultiPointMeta([p1], city="Abuja", rainfall=1221.2) +``` + +Connect the points with lines: + +```@repl quickstart +l1 = Line(p1, p2) +l2 = Line(p2, p3); +``` + +Connect the lines in a linestring: + +```@repl quickstart +LineString([l1, l2]) +``` + +Linestrings can also be constructed directly from points: + +```@repl quickstart +LineString([p1, p2, p3]) +``` + +The same goes for polygons: + +```@repl quickstart +Polygon(Point{2, Int}[(3, 1), (4, 4), (2, 4), (1, 2), (3, 1)]) +``` + +Create a rectangle placed at the origin with unit width and height: + +```@repl quickstart +rect = Rect(Vec(0.0, 0.0), Vec(1.0, 1.0)) +``` + +Decompose the rectangle into two triangular faces: + +```@repl quickstart +rect_faces = decompose(TriangleFace{Int}, rect) +``` + +Decompose the rectangle into four vertices: + +```@repl quickstart +rect_vertices = decompose(Point{2, Float64}, rect) +``` + +Combine the vertices and faces into a triangle mesh: + +```@repl quickstart +mesh = Mesh(rect_vertices, rect_faces) +``` + +Use `GeometryBasics.mesh` to get a mesh directly from a geometry: + +```@repl quickstart +mesh = GeometryBasics.mesh(rect) +``` diff --git a/docs/src/meshes.md b/docs/src/meshes.md index a28a65cb..7468388e 100644 --- a/docs/src/meshes.md +++ b/docs/src/meshes.md @@ -2,10 +2,8 @@ ## Types -```@docs -AbstractMesh -Mesh -``` +* [`AbstractMesh`](@ref) +* [`Mesh`](@ref) ## How to create a mesh diff --git a/docs/src/metadata.md b/docs/src/metadata.md index 7d491f9e..d7bebcaf 100644 --- a/docs/src/metadata.md +++ b/docs/src/metadata.md @@ -18,69 +18,48 @@ meta(meta-geometry) ### Examples -```jldoctest meta -julia> using GeometryBasics - -julia> p1 = Point(2.2, 3.6) -2-element Point{2,Float64} with indices SOneTo(2): - 2.2 - 3.6 - -julia> poi = meta(p1, city="Abuja", rainfall=1221.2) -2-element PointMeta{2,Float64,Point{2,Float64},(:city, :rainfall),Tuple{String,Float64}} with indices SOneTo(2): - 2.2 - 3.6 +```@repl meta +using GeometryBasics +p1 = Point(2.2, 3.6) +poi = meta(p1, city="Abuja", rainfall=1221.2) ``` -Metadata is stored in a NamedTuple and can be retrieved as such +Metadata is stored in a NamedTuple and can be retrieved as such: -```jldoctest meta -julia> meta(poi) -(city = "Abuja", rainfall = 1221.2) +```@repl meta +meta(poi) ``` -Specific metadata attributes can be directly retrieved - -```jldoctest meta -julia> poi.rainfall -1221.2 +Specific metadata attributes can be directly retrieved: -julia> metafree(poi) -2-element Point{2,Float64} with indices SOneTo(2): - 2.2 - 3.6 +```@repl meta +poi.rainfall +metafree(poi) ``` -For other geometries metatypes are predefined +Metatypes are predefined for geometries: -```jldoctest meta -julia> multipoi = MultiPointMeta([p1], city="Abuja", rainfall=1221.2) -1-element MultiPointMeta{Point{2,Float64},MultiPoint{2,Float64,Point{2,Float64},Array{Point{2,Float64},1}},(:city, :rainfall),Tuple{String,Float64}}: - [2.2, 3.6] +```@repl meta +multipoi = MultiPointMeta([p1], city="Abuja", rainfall=1221.2) ``` -In the above example we have also used geometry specific meta methods. +(In the above example we have also used a geometry-specific meta method.) -```jldoctest meta -julia> GeometryBasics.MetaType(Polygon) -PolygonMeta - -julia> GeometryBasics.MetaType(Mesh) -MeshMeta +```@repl meta +GeometryBasics.MetaType(Polygon) +GeometryBasics.MetaType(Mesh) ``` -The metageometry objects are infact composed of the original geometry types. -```jldoctest meta -julia> GeometryBasics.MetaFree(PolygonMeta) -Polygon +The metageometry objects are infact composed of the original geometry types. -julia> GeometryBasics.MetaFree(MeshMeta) -Mesh +```@repl meta +GeometryBasics.MetaFree(PolygonMeta) +GeometryBasics.MetaFree(MeshMeta) ``` ## MetaT -In GeometryBasics we can a have tabular layout for a collection of meta-geometries +In GeometryBasics we can have tabular layout for a collection of meta-geometries by putting them into a StructArray that extends the [Tables.jl](https://github.com/JuliaData/Tables.jl) API. In practice it's not necessary for the geometry or metadata types to be consistent. @@ -102,12 +81,11 @@ For example, while a Point MetaGeometry is a `PointMeta`, the MetaT representati ### Examples -```jldoctest meta -julia> MetaT(Point(1, 2), city = "Mumbai") -MetaT{Point{2,Int64},(:city,),Tuple{String}}([1, 2], (city = "Mumbai",)) +```@repl meta +MetaT(Point(1, 2), city = "Mumbai") ``` -For a tabular representation, an iterable of `MetaT` types can be passed on to a `metatable` method. +For a tabular representation, an iterable of `MetaT` types can be passed on to a `meta_table` method. ### Syntax @@ -119,62 +97,50 @@ meta_table(iter) Create an array of 2 linestrings: -```jldoctest meta -julia> ls = [LineString([Point(i, i+1), Point(i-1,i+5)]) for i in 1:2]; - -julia> coordinates.(ls) -2-element Array{Array{Point{2,Int64},1},1}: - [[1, 2], [0, 6]] - [[2, 3], [1, 7]] +```@repl meta +ls = [LineString([Point(i, i+1), Point(i-1,i+5)]) for i in 1:2]; +coordinates.(ls) ``` Create a multi-linestring: -```jldoctest meta -julia> mls = MultiLineString(ls); - -julia> coordinates.(mls) -2-element Array{Array{Point{2,Int64},1},1}: - [[1, 2], [0, 6]] - [[2, 3], [1, 7]] +```@repl meta +mls = MultiLineString(ls); +coordinates.(mls) ``` Create a polygon: -```jldoctest meta -julia> poly = Polygon(Point{2, Int}[(40, 40), (20, 45), (45, 30), (40, 40)]); - -julia> coordinates(poly) -4-element Array{Point{2,Int64},1}: - [40, 40] - [20, 45] - [45, 30] - [40, 40] +```@repl meta +poly = Polygon(Point{2, Int}[(40, 40), (20, 45), (45, 30), (40, 40)]); +coordinates(poly) ``` Put all geometries into an array: -```jldoctest meta -julia> geom = [ls..., mls, poly]; +```@repl meta +geom = [ls..., mls, poly]; ``` -:Generate some random metadata: +Generate some random metadata: + +```@repl meta +prop = [(country_states = "India$(i)", rainfall = (i*9)/2) for i in 1:4] +feat = [MetaT(i, j) for (i,j) = zip(geom, prop)]; # create an array of MetaT +``` -```jldoctest meta -julia> prop = [(country_states = "India$(i)", rainfall = (i*9)/2) for i in 1:4] -4-element Array{NamedTuple{(:country_states, :rainfall),Tuple{String,Float64}},1}: - (country_states = "India1", rainfall = 4.5) - (country_states = "India2", rainfall = 9.0) - (country_states = "India3", rainfall = 13.5) - (country_states = "India4", rainfall = 18.0) +We can now generate a `StructArray` / `Table` with `meta_table`: -julia> feat = [MetaT(i, j) for (i,j) = zip(geom, prop)]; # create an array of MetaT +```@repl meta +sa = meta_table(feat); ``` -We can now generate a `StructArray` / `Table` with `meta_table`. Fields are accessed with `sa.main`, `sa.country_states`, `sa.rainfall`. +The data can be accessed through `sa.main` and the metadata through +`sa.country_states` and `sa.rainfall`. Here we print only the type names of the +data items for brevity: -```jldoctest meta -julia> sa = meta_table(feat); +```@repl meta +[nameof.(typeof.(sa.main)) sa.country_states sa.rainfall] ``` ### Disadvantages diff --git a/docs/src/primitives.md b/docs/src/primitives.md index 5ae95175..2f28a12c 100644 --- a/docs/src/primitives.md +++ b/docs/src/primitives.md @@ -6,17 +6,12 @@ ## Shapes -```@docs -Circle -Sphere -Cylinder -``` +* [`Circle`](@ref) +* [`Sphere`](@ref) +* [`Cylinder`](@ref) ## Abstract types -```@docs -GeometryPrimitive -AbstractSimplex -AbstractMesh -AbstractDistanceField -``` +* `GeometryPrimitive` +* `AbstractSimplex` +* [`AbstractMesh`](@ref) diff --git a/src/meshes.jl b/src/meshes.jl index 1037e381..7d1e7ca1 100644 --- a/src/meshes.jl +++ b/src/meshes.jl @@ -103,6 +103,7 @@ end uvtype=nothing, normaltype=nothing) Creates a mesh from `primitive`. + Uses the element types from the keyword arguments to create the attributes. The attributes that have their type set to nothing are not added to the mesh. Note, that this can be an `Int` or `Tuple{Int, Int}``, when the primitive is grid based. @@ -144,7 +145,8 @@ end """ mesh(polygon::AbstractVector{P}; pointtype=P, facetype=GLTriangleFace, normaltype=nothing) -Polygon triangluation! + +Create a mesh from a polygon given as a vector of points, using triangulation. """ function mesh(polygon::AbstractVector{P}; pointtype=P, facetype=GLTriangleFace, normaltype=nothing) where {P<:AbstractPoint{2}} diff --git a/src/primitives/spheres.jl b/src/primitives/spheres.jl index 5c9298ac..73d8083e 100644 --- a/src/primitives/spheres.jl +++ b/src/primitives/spheres.jl @@ -8,6 +8,7 @@ struct HyperSphere{N,T} <: GeometryPrimitive{N,T} center::Point{N,T} r::T end + """ Circle{T} diff --git a/src/triangulation.jl b/src/triangulation.jl index 352860cc..770cabe6 100644 --- a/src/triangulation.jl +++ b/src/triangulation.jl @@ -105,10 +105,11 @@ function snip(contour::AbstractVector{<:AbstractPoint{N,T}}, u, v, w, n, V) wher end """ - faces(contour::AbstractArray{Point}, [facetype = GLTriangleFace]) + decompose(facetype, contour::AbstractArray{AbstractPoint}) -Triangulates a Polygon given as an `AbstractArray{Point}` without holes. -It will return a Vector{`facetype`}, defining indexes into `contour` +Triangulate a Polygon without hole. + +Returns a Vector{`facetype`} defining indexes into `contour`. """ function decompose(::Type{FaceType}, points::AbstractArray{P}) where {P<:AbstractPoint,FaceType<:AbstractFace} diff --git a/src/viewtypes.jl b/src/viewtypes.jl index 73db1f70..3711fc93 100644 --- a/src/viewtypes.jl +++ b/src/viewtypes.jl @@ -62,7 +62,7 @@ end end """ - connect(points::AbstractVector{<: AbstractPoint}, P::Type{<: Polytype{N}}, skip::Int = N) + connect(points::AbstractVector{<: AbstractPoint}, P::Type{<: Polytope{N}}, skip::Int = N) Creates a view that connects a number of points to a Polytope `P`. Between each polytope, `skip` elements are skipped untill the next starts.