From 482bec3712e49e3a0a9e629cfed4290253301ba7 Mon Sep 17 00:00:00 2001 From: Vladimir Georgiev Date: Wed, 6 Apr 2016 14:25:27 +0300 Subject: [PATCH] xtherion: Added line simplification menu in Edit line --- xtherion/global.tcl | 2 ++ xtherion/lang/xtexts.txt | 12 +++++++ xtherion/me.tcl | 3 ++ xtherion/me_cmds2.tcl | 87 ++++++++++++++++++++++++++++++++++++++++++++++++ xtherion/msgxth.tcl | 9 +++++ xtherion/xtherion.ini | 3 ++ 6 files changed, 116 insertions(+) diff --git a/xtherion/global.tcl b/xtherion/global.tcl index 735234d..0fcf5d7 100644 --- a/xtherion/global.tcl +++ b/xtherion/global.tcl @@ -194,6 +194,8 @@ set xth(gui,me,line,clwidth) 2 set xth(gui,me,line,ticksize) 15 # width of start line tick set xth(gui,me,line,tickwidth) 3 +# simplification limit for lines. Larger simp_limit = less points; smaller simp_limit = more points and smoother line +set xth(gui,me,line,simp_limit) 10 # for color names, see http://wiki.tcl.tk/37701 set xth(gui,me,activefill) red diff --git a/xtherion/lang/xtexts.txt b/xtherion/lang/xtexts.txt index 0e94f12..cd1c4bf 100644 --- a/xtherion/lang/xtexts.txt +++ b/xtherion/lang/xtexts.txt @@ -3420,6 +3420,18 @@ ru: Разделить линию sk: Rozdeliť krivku sq: ndaje rjeshtin-vijen +therion: Trace line +bg: Проследяване от картината +en: Trace line + +therion: Convert to curve +bg: Конвертиране в Безие +en: Convert to curve + +therion: Simplify line +bg: Опростяване на линия +en: Simplify line + therion: deleting line point bg: Изтрий точка от линията cz: mazaní bodu na křivce diff --git a/xtherion/me.tcl b/xtherion/me.tcl index 4c473b1..7129b43 100644 --- a/xtherion/me.tcl +++ b/xtherion/me.tcl @@ -2095,6 +2095,8 @@ Button $lnc.trace -text [mc "Continue tracing"] -anchor center -font $xth(gui,lf -state disabled -command {xth_me_cmds_line_trace} -width 10 Button $lnc.vector -text [mc "Convert to curve"] -anchor center -font $xth(gui,lfont) \ -state disabled -command {xth_me_cmds_line_poly2bezier} -width 10 +Button $lnc.simpl -text [mc "Simplify line"] -anchor center -font $xth(gui,lfont) \ + -state disabled -command {xth_me_cmds_line_simplify} -width 10 xth_status_bar me $lnc.upd [mc "Click this button to apply line changes."] menu $lnc.lpa.m -tearoff 0 -font $xth(gui,lfont) @@ -2103,6 +2105,7 @@ $lnc.lpa.m add command -label [mc "Delete point"] -command {xth_me_cmds_delete_l $lnc.lpa.m add command -label [mc "Split line"] -command {xth_me_cmds_line_split} -state disabled $lnc.lpa.m add command -label [mc "Trace line"] -command {xth_me_cmds_line_trace_start} $lnc.lpa.m add command -label [mc "Convert to curve"] -command {xth_me_cmds_line_poly2bezier} +$lnc.lpa.m add command -label [mc "Simplify line"] -command {xth_me_cmds_line_simplify} #Button $lnc.insp -text "Insert" -anchor center -font $xth(gui,lfont) \ # -state disabled -width 10 -command {xth_me_cmds_start_linept_insert} diff --git a/xtherion/me_cmds2.tcl b/xtherion/me_cmds2.tcl index f7cc018..12eab69 100644 --- a/xtherion/me_cmds2.tcl +++ b/xtherion/me_cmds2.tcl @@ -3690,6 +3690,93 @@ proc xth_me_cmds_line_trace_point {dist tcol} { } +# Line simplification using the Ramer-Douglas-Peucker algorithm +# P is a list of points. Epsilon controls the point removal accuracy. Larger E means less points remaining +proc simplify_line_RDP {P epsilon} { + set P0 [lindex $P 0] + set P1 [lindex $P end] + set dmax 0 + set idx 0 + for {set i 1} {$i < [llength $P]-1} {incr i} { + set d [DistanceToLine [lindex $P $i] $P0 $P1] + if {$d > $dmax} { + set dmax $d + set idx $i + } + } + + if {$dmax >= $epsilon} { + set leg1 [simplify_line_RDP [lrange $P 0 $idx] $epsilon] + set leg2 [simplify_line_RDP [lrange $P $idx end] $epsilon] + set leg [concat [lrange $leg1 0 end-1] $leg2] + } else { + return [list $P0 $P1] + } +} + +# Given a point and a line segment, return distance between the point and the segment +# Perpendicular or euclidean distance +# can probably be replaced with ::math::geometry::findClosestPointOnLine, but not tested +proc DistanceToLine {P P0 P1} { + lassign $P PX PY + lassign $P0 x0 y0 + lassign $P1 x1 y1 + + set lx [expr {$x1 - $x0}] + set ly [expr {$y1 - $y0}] + set d [expr {hypot($lx, $ly)}] ;# To normalize line vector + if {$d == 0} { return 99999 } ;# Degenerate line + + set px [expr {$PX - $x0}] ;# Vector to our point + set py [expr {$PY - $y0}] + set hdist [expr {($px*$lx + $py*$ly) / $d}] ;# Distance along line vector + set vdist [expr {($py*$lx - $px*$ly) / $d}] ;# Distance along perpendicular + + if {$hdist < 0} { ;# Point behind line segment + set rdist [expr {hypot($px, $py)}] + } elseif {$hdist <= $d} { ;# Point within line segment + set rdist [expr {abs($vdist)}] + } else { ;# Point beyond line segment + set px [expr {$PX - $x1}] + set py [expr {$PY - $y1}] + set rdist [expr {hypot($px, $py)}] + } + return $rdist +} + +# Replace the selected line with one with less points +proc xth_me_cmds_line_simplify {} { + global xth + set id $xth(me,cmds,selid) + if {$xth(me,cmds,$id,ct) != 3} {return} + set npx [llength $xth(me,cmds,$id,xplist)] + if {$npx < 4} {return} + + # copy line points to a new list + set points {} + foreach x $xth(me,cmds,$id,xplist) { + if {$x != 0} { + lappend points [concat $xth(me,cmds,$id,$x,x) $xth(me,cmds,$id,$x,y)] + } + } + + # reduce points + set points [simplify_line_RDP $points $xth(gui,me,line,simp_limit)] + + set type $xth(me,cmds,$id,type) + set opts " $xth(me,cmds,$id,options)" + if {$xth(me,cmds,$id,reverse)} { + set opts "$opts -reverse on" + } + if {$xth(me,cmds,$id,close)} { + set opts "$opts -close on" + } + xth_me_cmds_delete $id + xth_me_cmds_create_line 0 2 $type $opts $points + xth_me_cmds_set_mode 0 + return +} + proc xth_me_cmds_line_poly2bezier {} { global xth set id $xth(me,cmds,selid) diff --git a/xtherion/msgxth.tcl b/xtherion/msgxth.tcl index f64445c..4bfc71b 100644 --- a/xtherion/msgxth.tcl +++ b/xtherion/msgxth.tcl @@ -3131,6 +3131,15 @@ ::msgcat::mcset sk "Split line" [encoding convertfrom utf-8 "Rozdeli\305\245 krivku"] ::msgcat::mcset sq "Split line" [encoding convertfrom utf-8 "ndaje rjeshtin-vijen"] + ::msgcat::mcset bg "Trace line" [encoding convertfrom utf-8 "\320\237\321\200\320\276\321\201\320\273\320\265\320\264\321\217\320\262\320\260\320\275\320\265 \320\276\321\202 \320\272\320\260\321\200\321\202\320\270\320\275\320\260\321\202\320\260"] + ::msgcat::mcset en "Trace line" [encoding convertfrom utf-8 "Trace line"] + + ::msgcat::mcset bg "Convert to curve" [encoding convertfrom utf-8 "\320\232\320\276\320\275\320\262\320\265\321\200\321\202\320\270\321\200\320\260\320\275\320\265 \320\262 \320\221\320\265\320\267\320\270\320\265"] + ::msgcat::mcset en "Convert to curve" [encoding convertfrom utf-8 "Convert to curve"] + + ::msgcat::mcset bg "Simplify line" [encoding convertfrom utf-8 "\320\236\320\277\321\200\320\276\321\201\321\202\321\217\320\262\320\260\320\275\320\265 \320\275\320\260 \320\273\320\270\320\275\320\270\321\217"] + ::msgcat::mcset en "Simplify line" [encoding convertfrom utf-8 "Simplify line"] + ::msgcat::mcset bg "deleting line point" [encoding convertfrom utf-8 "\320\230\320\267\321\202\321\200\320\270\320\271 \321\202\320\276\321\207\320\272\320\260 \320\276\321\202 \320\273\320\270\320\275\320\270\321\217\321\202\320\260"] ::msgcat::mcset cz "deleting line point" [encoding convertfrom utf-8 "mazan\303\255 bodu na k\305\231ivce"] ::msgcat::mcset de "deleting line point" [encoding convertfrom utf-8 "Linienpunkt l\303\266schen"] diff --git a/xtherion/xtherion.ini b/xtherion/xtherion.ini index edb0966..bdfdb07 100644 --- a/xtherion/xtherion.ini +++ b/xtherion/xtherion.ini @@ -94,6 +94,9 @@ ## width of start line tick # set xth(gui,me,line,tickwidth) 3 +## simplification limit for lines. Larger simp_limit = less points; smaller simp_limit = more points and smoother line +# set xth(gui,me,line,simp_limit) 10 + ## whether inactive scraps should be hidden by default # set xth(me,hinactives) 0 -- 2.6.4.windows.1