Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Vector Graphics on Surfaces #8679

Draft
wants to merge 122 commits into
base: master
Choose a base branch
from
Draft
Changes from 1 commit
Commits
Show all changes
122 commits
Select commit Hold shift + click to select a range
fcf4c20
add initial structure for bsurf import into CGAL
sloriot Sep 25, 2023
1464142
first example
sloriot Sep 25, 2023
a0a2302
add dijkstra call on the dual graph + fill edges for unfolding
sloriot Sep 25, 2023
c756199
first running versione of shortest path (runs but bugged)
Claudiomancinelli90 Sep 25, 2023
d6204ca
fix order for the intersection since vertices should be CCW oriented
Claudiomancinelli90 Sep 26, 2023
9e3c1f4
WIP: straightening path
Claudiomancinelli90 Sep 26, 2023
11991e6
copy edit plugin/item as a base for editable shortest path
sloriot Sep 26, 2023
8fa860f
bug fixes, first working implementation
sloriot Sep 26, 2023
768f6b8
add missing entry
sloriot Sep 26, 2023
bd3b513
add code for recursive de Casteljau (compiles, runs but crashes)
sloriot Sep 27, 2023
176e4c7
WIP debug
sloriot Sep 27, 2023
0f5db6d
fix tracing bezier!
sloriot Sep 27, 2023
779eeeb
intrinsic dual_weights in graph for Dijkstra
Claudiomancinelli90 Sep 27, 2023
197627b
fix intersection point computation --> fixes weights
sloriot Sep 27, 2023
e7b3e9a
primal and dual graph for geodesic queries
Claudiomancinelli90 Sep 28, 2023
defa982
fix warnings
sloriot Sep 28, 2023
3a58185
bug fix
sloriot Sep 28, 2023
58adc66
bug fix strip on dual graph
Claudiomancinelli90 Sep 28, 2023
85e649b
fix macro
sloriot Sep 28, 2023
40f741b
add example for geodesic distance computation + fix compilation and
sloriot Sep 28, 2023
c5236db
bug fix (still bugged) Dijkstra
Claudiomancinelli90 Sep 29, 2023
2697e15
add early quit for Dijkstra
sloriot Sep 29, 2023
32704eb
add missing next + TODOs
sloriot Sep 29, 2023
ffa46ec
straightest geodesic (WIP)
Claudiomancinelli90 Sep 29, 2023
d79a0bd
straightest geodesic (compile)
Claudiomancinelli90 Sep 29, 2023
76e0f7a
raw import of file
sloriot Sep 29, 2023
1df3c82
walk along the intersection with a plane for now
sloriot Sep 29, 2023
5c41af0
add missing deps
sloriot Sep 29, 2023
ee4f229
fix compilation (does not run yet).
sloriot Sep 29, 2023
44fabf4
add missing class
sloriot Sep 29, 2023
e74b2ac
Revert "add missing entry"
sloriot Jan 5, 2024
bdffb60
Revert "copy edit plugin/item as a base for editable shortest path"
sloriot Jan 5, 2024
09891be
Merge remote-tracking branch 'cgal/master' into Bsur
sloriot Jan 5, 2024
3cf13af
update include to dijkstra
sloriot Jan 10, 2024
37ff2be
first version of locally shortest path plugin that starts to work
sloriot Jan 8, 2024
2ac824f
fix headers
sloriot Jan 10, 2024
9f0d60a
add tracing bezier
sloriot Jan 10, 2024
42538ca
clean up initial path if src/tgt are on vertex/edge
sloriot Jan 29, 2024
5cfaa04
move to a function
sloriot Jan 29, 2024
8d54b8e
add test for striping initial path + bug fixes
sloriot Jan 30, 2024
1a0cf35
add some debug
sloriot Jan 30, 2024
d61a500
handle already visible src and tgt
sloriot Jan 30, 2024
bd8c69f
fix edge update
sloriot Jan 31, 2024
6994bb9
update for length 1 path
sloriot Jan 31, 2024
b3fefe5
update test
sloriot Jan 31, 2024
3b55015
fix loop
sloriot Jan 31, 2024
88fe6cf
add test on grid
sloriot Jan 31, 2024
1515f8c
move Edge_location and add convinence function
sloriot Feb 1, 2024
5bff11f
add simplification function showing that we need exact predicates
sloriot Feb 1, 2024
d28866c
WIP Straightest path
Claudiomancinelli90 Feb 1, 2024
cca8324
clean up patch
sloriot Feb 1, 2024
f381652
dd trace geodesic polygon
Claudiomancinelli90 Feb 1, 2024
e50c2f9
accept external solver to avoid rebuilding it
sloriot Feb 1, 2024
831844a
print face locations in the infos
sloriot Feb 1, 2024
9f7711d
add missing point and trace several polygons
sloriot Feb 1, 2024
73e68ff
simplify the code by always stripping the path
sloriot Feb 2, 2024
26c6393
WIP straightest at vertex
Claudiomancinelli90 Feb 2, 2024
3da5af5
clean up patch
sloriot Feb 2, 2024
d1a5995
reusable solver
sloriot Feb 2, 2024
34ad600
WIP generic polygon tracing (to be debugged...)
sloriot Feb 2, 2024
3468a87
WIP testsuite
sloriot Feb 5, 2024
adb823a
fix invalid barycentric coordinate and add missing point
sloriot Feb 5, 2024
cba29df
clean up examples
sloriot Feb 5, 2024
3871e7d
clean up test
sloriot Feb 5, 2024
501b6a6
init angle should be in degrees
sloriot Feb 6, 2024
ed5cad1
add draft for drawing several polygons with different centers
sloriot Feb 7, 2024
f9cef82
add parallel transport
sloriot Feb 9, 2024
ea10d5a
another method for text, using parallel transport for now
sloriot Feb 9, 2024
645aa83
call the new method
sloriot Feb 9, 2024
c87b601
update angle wrt initial straightest
sloriot Feb 9, 2024
0376540
add an example tracing a svg
sloriot Feb 20, 2024
bed64dc
Refresh from master
sloriot Jun 24, 2024
7fca80b
change return type
sloriot Jun 26, 2024
ac5ed5a
add function to write along a curve given as input
sloriot Jun 26, 2024
90ed96f
more helper functions
sloriot Jun 28, 2024
9c55052
change return type to return location
sloriot Jun 28, 2024
019ef75
add basic code for extruding/carving
sloriot Jun 28, 2024
aec062d
accomodate API update
sloriot Jul 9, 2024
e0d66e9
API update
sloriot Jul 9, 2024
fa2143a
connect de Casteljau points with geodesic paths
sloriot Jul 9, 2024
e59b726
avoid duplicated points in the output of de Casteljau + remove unneed…
sloriot Jul 12, 2024
3f8506d
add functions to get vertex from location
sloriot Jul 12, 2024
dcf46c5
add function to get unique points from a path
sloriot Jul 12, 2024
514c87a
remove unused files
sloriot Jul 12, 2024
acd226d
new example to write on a polygon curve with location snapping
sloriot Jul 13, 2024
c0b87a0
WIP bug fix straightest geodesic starting on an edge but going in the…
sloriot Jul 13, 2024
ed33392
fix invalid index
sloriot Jul 15, 2024
a5553d8
handle case when starting at a vertex in straightest path
sloriot Jul 16, 2024
792e1de
missing update of location
sloriot Jul 17, 2024
ad23ae7
fix computation of angle in the triangle (need accumulation and not l…
sloriot Jul 17, 2024
8a84d01
remove debug
sloriot Jul 23, 2024
de4bb02
fix case of a path of length 0
sloriot Jul 24, 2024
6eaa1ab
add code for tracing a polyline of adjacent bezier curves
sloriot Jul 24, 2024
e91fc75
update example code to also trace svg with different center after reg…
sloriot Jul 24, 2024
c2d9c78
add extrude/carving for svg drawing
sloriot Jul 25, 2024
47683c5
regroup control polylines when overlapping
sloriot Jul 25, 2024
0045843
create skeleton of a new package for Bsurf
sloriot Aug 21, 2024
ecd5914
start handling border in straightest geodesic
sloriot Oct 9, 2024
6082359
bad break
sloriot Oct 9, 2024
79f0baa
first fixes for cases when reaching the boundary
sloriot Oct 16, 2024
9bcf6eb
add test for straightest geodesic
sloriot Oct 16, 2024
0576fb6
start fixing vertex case
sloriot Oct 18, 2024
54d72a9
fix ref landing page
sloriot Jan 3, 2025
40c7d25
tmp change to not forget to fix the code for the test
sloriot Jan 3, 2025
a372da3
start adding function doc
sloriot Jan 3, 2025
937003c
add more doc
sloriot Jan 6, 2025
e0572b9
fix license and copyright
sloriot Jan 7, 2025
b3d7ce4
move header + fix compilation issues
sloriot Jan 7, 2025
3cb40d0
change namespace
sloriot Jan 7, 2025
bf31250
classified reference manual
sloriot Jan 7, 2025
9e0ddba
move tests
sloriot Jan 7, 2025
e509999
please CI
sloriot Jan 7, 2025
ae0b792
add missing dependencies
sloriot Jan 8, 2025
d1eea2b
missing link with Eigen
sloriot Jan 8, 2025
adec4e5
fix compilation issue
sloriot Jan 8, 2025
f6eb9e6
one more missing eigen link
sloriot Jan 8, 2025
114fd88
doc fixes
afabri Jan 13, 2025
33a570e
uint -> unsigned int
afabri Jan 13, 2025
473d1d1
std::max
afabri Jan 13, 2025
27aaaa6
typo
afabri Jan 13, 2025
1bd12c7
typos
afabri Jan 14, 2025
f610f05
Change inclusion order in tests
afabri Jan 14, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
add an example tracing a svg
  • Loading branch information
sloriot committed Feb 20, 2024
commit 0376540a1c4daa33f769ec3b94bb015c7b67dc4b
27 changes: 27 additions & 0 deletions Data/data/polylines_2/nano.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions Installation/cmake/modules/CGAL_NanoSVG_support.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
if(NanoSVG_FOUND AND NOT TARGET CGAL::NanoSVG_support)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

During configuration I had to lib/cmake/NanoSVG inside the build directory for the Nanosvg_dir instead of just giving the build directory.

add_library(CGAL::NanoSVG_support INTERFACE IMPORTED)
set_target_properties(CGAL::NanoSVG_support PROPERTIES
INTERFACE_COMPILE_DEFINITIONS "CGAL_NANOSVG_ENABLED")
target_link_libraries(CGAL::NanoSVG_support INTERFACE NanoSVG::nanosvg)
endif()
Original file line number Diff line number Diff line change
@@ -56,6 +56,9 @@ create_single_source_cgal_program("isotropic_remeshing_with_custom_sizing_exampl
create_single_source_cgal_program("triangle_mesh_autorefinement.cpp")
create_single_source_cgal_program("soup_autorefinement.cpp")

find_package(NanoSVG)
include(CGAL_NanoSVG_support)

find_package(Eigen3 3.2.0 QUIET) #(requires 3.2.0 or greater)
include(CGAL_Eigen3_support)
if(TARGET CGAL::Eigen3_support)
@@ -81,6 +84,7 @@ if(TARGET CGAL::Eigen3_support)
target_link_libraries(remesh_almost_planar_patches PUBLIC CGAL::Eigen3_support)
create_single_source_cgal_program("locally_shortest_path_sm_example.cpp")
target_link_libraries(locally_shortest_path_sm_example PUBLIC CGAL::Eigen3_support)
#b/surf
create_single_source_cgal_program("trace_bezier_segment_sm_example.cpp")
target_link_libraries(trace_bezier_segment_sm_example PUBLIC CGAL::Eigen3_support)
create_single_source_cgal_program("geodesic_circles_sm_example.cpp")
@@ -93,6 +97,13 @@ if(TARGET CGAL::Eigen3_support)
target_link_libraries(trace_regular_polygons_example PUBLIC CGAL::Eigen3_support)
create_single_source_cgal_program("geodesic_isolevel_refinement.cpp")
target_link_libraries(geodesic_isolevel_refinement PUBLIC CGAL::Eigen3_support)
if (NanoSVG_FOUND)
create_single_source_cgal_program("trace_svg_example.cpp")
target_link_libraries(trace_svg_example PUBLIC CGAL::Eigen3_support CGAL::NanoSVG_support)
else()
message(STATUS "NOTICE: trace_svg_example requires NanoSVG and will not be compiled.")
endif()
##
create_single_source_cgal_program("interpolated_corrected_curvatures_SM.cpp")
target_link_libraries(interpolated_corrected_curvatures_SM PUBLIC CGAL::Eigen3_support)
create_single_source_cgal_program("interpolated_corrected_curvatures_PH.cpp")
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
#include <CGAL/Surface_mesh.h>
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Polygon_mesh_processing/Bsurf/locally_shortest_path.h>

#include <CGAL/boost/graph/IO/polygon_mesh_io.h>

#include <nanosvg.h>

namespace PMP = CGAL::Polygon_mesh_processing;

typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
typedef CGAL::Surface_mesh<K::Point_3> Mesh;
typedef PMP::Face_location<Mesh, double> Face_location;
typedef PMP::Edge_location<Mesh, double> Edge_location;


int main(int argc, char** argv)
{
std::string mesh_filename = (argc > 1) ? std::string(argv[1])
: CGAL::data_file_path("meshes/elephant.off");

std::string svg_filename = (argc > 2) ? std::string(argv[2])
: CGAL::data_file_path("polylines_2/nano.svg");

Mesh mesh;
if(!CGAL::IO::read_polygon_mesh(mesh_filename, mesh) || !CGAL::is_triangle_mesh(mesh))
{
std::cerr << "Invalid input mesh." << std::endl;
return 1;
}

NSVGimage* g_image = nsvgParseFromFile(svg_filename.c_str(), "px", 96.0f);
if (g_image == NULL) {
printf("Could not open SVG image.\n");
return 1;
}

// extract control points
std::vector< std::array<K::Point_2, 4> > bezier_curves;
CGAL::Bbox_2 bb2;

// in SVG's the y axis points downward, so we must take the opposite y coordinates
for (NSVGshape* shape = g_image->shapes; shape != NULL; shape = shape->next)
{
for (NSVGpath* path = shape->paths; path != NULL; path = path->next)
{
CGAL::Bbox_2 path_bbox(path->bounds[0], -path->bounds[1],
path->bounds[2], -path->bounds[3]);
bb2+=path_bbox;

float* pts=path->pts;
int npts=path->npts;

for (int i=0; i<npts-1; i += 3)
{
bezier_curves.emplace_back();
float* p = &pts[i*2];
bezier_curves.back()[0]=K::Point_2(p[0],-p[1]);
bezier_curves.back()[1]=K::Point_2(p[2],-p[3]);
bezier_curves.back()[2]=K::Point_2(p[4],-p[5]);
bezier_curves.back()[3]=K::Point_2(p[6],-p[7]);
}
}
}

nsvgDelete(g_image);

std::cout << "#Bezier curves read: " << bezier_curves.size() << "\n";

// convert control points to polar coordinates
typename K::Point_2 center_2((bb2.xmax()+bb2.xmin())/2., (bb2.ymax()+bb2.ymin())/2.);
double diag = std::sqrt( CGAL::square(bb2.xmin()-bb2.xmax()) + CGAL::square(bb2.xmin()-bb2.xmax()) );
const double expected_diag = 0.45; // user parameter for scaling
const double scaling = expected_diag/diag;

//TODO: do the scaling at read time!

std::vector<std::array<K::Vector_2, 4>> directions;
std::vector<std::array<K::FT, 4>> lengths;
directions.reserve(bezier_curves.size());
lengths.reserve(bezier_curves.size());

for (const std::array<K::Point_2, 4>& bezier : bezier_curves)
{
std::vector<std::pair<double, double>> polar_coords =
PMP::convert_polygon_to_polar_coordinates<K>(bezier, center_2);

directions.emplace_back();
lengths.emplace_back();

assert(polar_coords.size()==4);

for (int i=0;i<4; ++i)
{
lengths.back()[i] = scaling * polar_coords[i].first;
directions.back()[i]=K::Vector_2(std::cos(polar_coords[i].second), std::sin(polar_coords[i].second));
}
}

// trace bezier curves
std::size_t nb_faces = faces(mesh).size();
Mesh::Face_index f = *std::next(faces(mesh).begin(), (2154)%nb_faces);
Face_location center(f, CGAL::make_array(0.3,0.3,0.4));

PMP::Dual_geodesic_solver<double> solver;
PMP::init_geodesic_dual_solver(solver, mesh);

std::vector< std::vector<typename K::Point_3> > res =
PMP::trace_bezier_curves<K>(center, directions, lengths, 6, mesh, solver);

// write result
std::ofstream out("svg.polylines.txt");
out << std::setprecision(17);
for (const auto& b : res)
{
out << b.size();
for (const K::Point_3& pt : b)
out << " " << pt;
out << "\n";
}

return 0;
}
Original file line number Diff line number Diff line change
@@ -2955,9 +2955,10 @@ straightest_geodesic(const Face_location<TriangleMesh, typename K::FT> &src,
}

// we don't expect the last point to be duplicated here
template <class K>
// TODO: rename the function, it's not a polygon necessarily
template <class K, class PointRange_2>
std::vector<std::pair<typename K::FT, typename K::FT>>
convert_polygon_to_polar_coordinates(const std::vector <typename K::Point_2>& polygon,
convert_polygon_to_polar_coordinates(const PointRange_2& polygon,
std::optional<typename K::Point_2> center = std::nullopt)
{
std::vector<std::pair<typename K::FT, typename K::FT>> result;
@@ -3272,6 +3273,71 @@ trace_geodesic_label(const Face_location<TriangleMesh, typename K::FT> &center,
}


template <class K, class TriangleMesh>
std::vector< std::vector<typename K::Point_3> >
trace_bezier_curves(const Face_location<TriangleMesh, typename K::FT> &center,
const std::vector<std::array<typename K::Vector_2, 4>>& directions,
const std::vector<std::array<typename K::FT, 4>>& lengths,
const int num_subdiv,
const TriangleMesh &tmesh
#ifndef CGAL_BSURF_USE_DIJKSTRA_SP
, const Dual_geodesic_solver<typename K::FT>& solver = {}
#endif
)
{
using FT = typename K::FT;

std::size_t n=directions.size();
std::vector< std::vector<typename K::Point_3> > result(n);
std::vector<Face_location<TriangleMesh, typename K::FT>> vertices(n);

#ifndef CGAL_BSURF_USE_DIJKSTRA_SP
const Dual_geodesic_solver<typename K::FT>* solver_ptr=&solver;
Dual_geodesic_solver<typename K::FT> local_solver;
if (solver.graph.empty())
{
solver_ptr = &local_solver;
init_geodesic_dual_solver(local_solver, tmesh);
}
#endif

#ifdef CGAL_DEBUG_BSURF
std::ofstream debug_cp("/tmp/control_points.xyz");
std::ofstream debug_ep("/tmp/end_points.xyz");
debug_cp << std::setprecision(17);
debug_ep << std::setprecision(17);
#endif
for (std::size_t i=0; i<n; ++i)
{
Bezier_segment<TriangleMesh, FT> control_loc;
for (int k=0;k<4; ++k)
{
control_loc[k] = straightest_geodesic<K>(center,directions[i][k],lengths[i][k],tmesh).back();
}

#ifdef CGAL_DEBUG_BSURF
debug_ep << construct_point(control_loc[0], tmesh) << "\n";
debug_ep << construct_point(control_loc[3], tmesh) << "\n";
debug_cp << construct_point(control_loc[1], tmesh) << "\n";
debug_cp << construct_point(control_loc[2], tmesh) << "\n";
#endif

std::vector<Face_location<TriangleMesh, FT>> bezier =
recursive_de_Casteljau(tmesh, control_loc, num_subdiv
#ifndef CGAL_BSURF_USE_DIJKSTRA_SP
, *solver_ptr
#endif
);

result[i].reserve(bezier.size());
for(const Face_location<TriangleMesh, FT>& loc : bezier)
result[i].push_back(construct_point(loc,tmesh));
}

return result;
}


template <class K, class TriangleMesh>
typename K::FT path_length(const std::vector<Edge_location<TriangleMesh,typename K::FT>>& path,
const Face_location<TriangleMesh, typename K::FT>& src,