Läsa in SVG till koordinater eller liknande i C.

Permalänk
Medlem

Läsa in SVG till koordinater eller liknande i C.

Jag använder librsvg och cairo för att läsa in och rendera en svg-fil, men jag vill även kolla om en punkt befinner sig inuti en "svg path". Jag använder mig av rsvg_handle_render_cairo() för att rendera svg-dokumentet till cairo, men jag vill använda mig av funktionen cairo_in_fill() för att testa om punkten befinner sig innanför eller inte, men rsvg_handle_render_cairo() tömmer cairo-contexten så det inte finns några paths kvar att köra cairo_in_fill på.

Kan man på något vis läsa in svg-dokumentet till punkter eller liknande för att sedan rita ut dokumentet med t.ex. cairo_line_to() så man har mer kontroll? Jag skulle kunna göra någon egen parser antar jag, men det känns dumt att uppfinna hjulet igen. Är libxml2 nåt att titta på kanske? Antar att det inte kan parsa svg, men man kan ju iallafall få ut svg-informationen på ett stabilt sätt för att sedan parsa det själv, isåfall.

Permalänk
Medlem

Jag har gjort precis det du beskriver. Jag använder libxml2 för att parsa xml-delen, men har skrivit egen kod för att parsa koordinater, paths och annat som går utanför xml. Det var inte särskilt svårt.

Visa signatur

Alla män är dödliga. Sokrates var dödlig. Alltså är alla män Sokrates.

Permalänk
Medlem
Citat:

Ursprungligen inskrivet av selotodo
Jag har gjort precis det du beskriver. Jag använder libxml2 för att parsa xml-delen, men har skrivit egen kod för att parsa koordinater, paths och annat som går utanför xml. Det var inte särskilt svårt.

Det låter bra. Jag har dock väldigt lite kunskaper om text-parsning i C, ska man använda sig av reguljära uttryck eller hur ska man gå till väga?

Jag vill få detta:

M 523.51839,4.7573983 L 522.40814,8.4040792 L 517.54293,5.0913781 L 515.77373,8.8463689 L 516.88398,12.059773 L 523.51839,11.391819 L 519.98,13.052684 L 517.20891,14.487884 L 520.86463,15.923084 L 524.069,14.713543 L 524.95359,17.033333 L 528.26631,14.713543 L 529.59318,15.155838

till nåt i stil med:

[M, 524, 5] [L, 522, 8] etc

där M och L är variabler som representerar dom olika SVG-koderna (M=move to, L=line to). Det skulle vara lätt att genomföra i python, men i C?

Permalänk
Medlem

Reguljära uttryck är knöliga att använda i C och är overkill för uppgiften tycker jag.

Börja med att skriva en funktion för att läsa in reella tal, till exempel med hjälp av strtod(). Använd den till att skriva en funktion som läser in och returnerar ett Point-objekt från nuvarande filposition. Använd i sin tur den till att skriva en funktion som läser in och returnerar ett Path-objekt, och så vidare.

Här är en förklarande skiss i C++:

Point* SvgParser::readPoint() { double x = readDouble(); skipWhiteSpace(); skipComma(); double y = readDouble(); return new Point(x, y); }

Gör motsvarande med structar och malloc/stackallokering istället om du kör med C.

Visa signatur

Alla män är dödliga. Sokrates var dödlig. Alltså är alla män Sokrates.

Permalänk
Medlem
Citat:

Ursprungligen inskrivet av selotodo
Reguljära uttryck är knöliga att använda i C och är overkill för uppgiften tycker jag.

Börja med att skriva en funktion för att läsa in reella tal, till exempel med hjälp av strtod(). Använd den till att skriva en funktion som läser in och returnerar ett Point-objekt från nuvarande filposition. Använd i sin tur den till att skriva en funktion som läser in och returnerar ett Path-objekt, och så vidare.

Här är en förklarande skiss:
[code]
Point* SvgParser::readPoint() {
double x = readDouble();
skipWhiteSpace();
skipComma();
double y = readDouble();

return new Point(x, y);
}
[code]

Mm, jag anade att det skulle vara knöligt. Förstår inte exakt hur du menar, men jag hade tänkt att kanske loopa igenom hela strängen, och först dela upp den i strängar i stil med:

"M 523.51839,4.7573983" "L 522.40814,8.4040792" "L 517.54293,5.0913781"

För att sedan få det till en struct som har t.ex. x.type = MOVE_TO eller LINE_TO och x = 524, y = 5.

När cairo sedan kör igenom det kan man köra nåt i stil med:

if(x.type == MOVE_TO) cairo_move_to(cr, x.x, x.y); if(x.type == LINE_TO) cairo_line_to(cr, x.x, x.y); if(x.type == CLOSE_PATH) cairo_close_path(cr);

Kan det vara nåt tro?

Permalänk
Medlem

struct point { char c; float x, y; }; void svg_parse(FILE * file, std::vector<point> & points) { while(!feof(file)) { point p; fscanf(file, "%c %f,%f", &p.c, &p.x, &p.y); points.push_back(p); } }

Vill du ha det i ren C så får du byta ut vectorn till t.ex. en array.

Visa signatur

Intel Core i7-3770K | NVIDIA Geforce GTX 980 | 16 GB DDR3 | DELL P2415Q | DELL U2711 | DELL U2410

Permalänk
Medlem
Citat:

Ursprungligen inskrivet av MagnusL

struct point { char c; float x, y; }; void svg_parse(FILE * file, std::vector<point> & points) { while(!feof(file)) { point p; fscanf(file, "%c %f,%f", &p.c, &p.x, &p.y); points.push_back(p); } }

Vill du ha det i ren C så får du byta ut vectorn till t.ex. en array.

Ah, sscanf verkar kunna hjälpa mig, men om jag har en variabel innehållandes all data, på detta vis:

M 523.51839,4.7573983 L 522.40814,8.4040792 L 517.54293,5.0913781 L 515.77373,8.8463689 L 516.88398,12.059773 L 523.51839,11.391819 L 519.98,13.052684 L 517.20891,14.487884 z

och kör sscanf(variabel, "%c %f,%f", &type, &x_, &y_); på den så får jag enbart ut M 523.51839 och 4.7573983 av naturliga skäl, hur får man funktionen att matcha alla såna förekommande mönster i variabeln?

EDIT: variabeln innehåller inga radslut, lade till dom för att det skulle vara enklare att läsa.

Permalänk
Medlem

om man läser ur en ström, tex fil eller annat så kan man läsa tecken för tecken till man kommer till nått intressant, tex L eller M, efter typen man hittar läser man in resten, dock kanske det bara funkar i c++

//hitta en typ i strömmen while (1){ if(ström.read()!=L || M){ //läs in två tal med tex: ström >> x >> y; } }

Permalänk
Medlem

En path består av en serie kommandon: moveTo, lineTo, curveTo osv. Varje kommando består i sin tur av en uppsättning koordinater. Spegla detta förhållande i dina structar så att din Path-struct innehåller kommando-structar, som innehåller point-structar osv. I min lösning speglar även själva parserns struktur språkets struktur på detta sätt. Jag gjorde så för att recursive descent parsers känns naturliga för mig, men du behöver naturligtvis inte göra likadant. Googla på recursive descent om du undrar vad det är.

Angående hur du får in alla kommandon så är det bara att loopa tills du upptäcker CLOSE_PATH..

Visa signatur

Alla män är dödliga. Sokrates var dödlig. Alltså är alla män Sokrates.