36 |
36 |
import voronoi
|
37 |
37 |
from sets import Set
|
38 |
38 |
|
|
39 |
# For comparing equality in lat/long - 10^6 meters are < 1 degree
|
|
40 |
# so this gives mm resolution at lat=0. For finer resolution tasks
|
|
41 |
# a localised projection will likely be used, so this should be OK.
|
|
42 |
FLT_EPSILON = 10**-9
|
|
43 |
|
39 |
44 |
class GeometryDialog( QDialog, Ui_Dialog ):
|
40 |
45 |
def __init__( self, iface, function ):
|
41 |
46 |
QDialog.__init__( self, iface.mainWindow() )
|
... | ... | |
729 |
734 |
""" Clip voronoi function based on code written for Inkscape
|
730 |
735 |
Copyright (C) 2010 Alvin Penner, [email protected]
|
731 |
736 |
"""
|
|
737 |
def float_eq( a, b ):
|
|
738 |
# the initial == test is for efficiency
|
|
739 |
return a == b or abs( a - b ) <= FLT_EPSILON
|
|
740 |
|
732 |
741 |
def clip_line( x1, y1, x2, y2, w, h, x, y ):
|
|
742 |
# where both x's are left of the clipping region no line needed
|
733 |
743 |
if x1 < 0 - x and x2 < 0 - x:
|
734 |
744 |
return [ 0, 0, 0, 0 ]
|
|
745 |
# where both x's are right of the clipping region no line needed
|
735 |
746 |
if x1 > w + x and x2 > w + x:
|
736 |
747 |
return [ 0, 0, 0, 0 ]
|
737 |
|
if x1 < 0 - x:
|
738 |
|
y1 = ( y1 * x2 - y2 * x1 ) / ( x2 - x1 )
|
739 |
|
x1 = 0 - x
|
740 |
|
if x2 < 0 - x:
|
741 |
|
y2 = ( y1 * x2 - y2 * x1 ) / ( x2 - x1 )
|
742 |
|
x2 = 0 - x
|
743 |
|
if x1 > w + x:
|
744 |
|
y1 = y1 + ( w + x - x1 ) * ( y2 - y1 ) / ( x2 - x1 )
|
745 |
|
x1 = w + x
|
746 |
|
if x2 > w + x:
|
747 |
|
y2 = y1 + ( w + x - x1 ) *( y2 - y1 ) / ( x2 - x1 )
|
748 |
|
x2 = w + x
|
|
748 |
# where both y's are below the clipping region no line needed
|
749 |
749 |
if y1 < 0 - y and y2 < 0 - y:
|
750 |
750 |
return [ 0, 0, 0, 0 ]
|
|
751 |
# where both y's are above the clipping region no line needed
|
751 |
752 |
if y1 > h + y and y2 > h + y:
|
752 |
753 |
return [ 0, 0, 0, 0 ]
|
753 |
|
if x1 == x2 and y1 == y2:
|
|
754 |
# where end points are too close to tell apart no line needed
|
|
755 |
if float_eq( x1, x2 ) and float_eq( y1, y2 ):
|
754 |
756 |
return [ 0, 0, 0, 0 ]
|
755 |
|
if y1 < 0 - y:
|
756 |
|
x1 = ( x1 * y2 - x2 * y1 ) / ( y2 - y1 )
|
|
757 |
# y = mx + b: calculate gradient but make sure is not a vertical line
|
|
758 |
if not float_eq( x1, x2 ):
|
|
759 |
m = (y2 - y1) / (x2 - x1)
|
|
760 |
else:
|
|
761 |
m = float("+inf") # vertical lines have infinite gradient
|
|
762 |
# y = mx + b: calculate intercept, if horizontal m==0 so use first Y value
|
|
763 |
if ( not float_eq( y1, y2 ) and not float_eq( x1, x2 ) ) or float_eq( y1, y2):
|
|
764 |
b = y1 - m*x1 # b = y1 when y1 == y2
|
|
765 |
else: # y1 != y2 and x1 == x2
|
|
766 |
b = float("nan") # vertical lines have no intercept
|
|
767 |
# for simplicity later define if the line is vertical
|
|
768 |
is_vertical = ( m == float("+inf") and b == float("nan") )
|
|
769 |
# where either of the x1,y1 or x2,y2 points are outside of the clipping region
|
|
770 |
# need to move them to be on the border of the region; this is done by recalculating
|
|
771 |
# the x or y value based on the equation of the line holding the other axis as the
|
|
772 |
# value of the clipping rectangle border that is violated.
|
|
773 |
if x1 < 0 - x: # first point is left of region
|
|
774 |
# impossible to have vertical line here, could be horizontal
|
|
775 |
# but that doesn't matter as m = 0, b = y1 in that case
|
|
776 |
x1 = 0 - x
|
|
777 |
y1 = m*x1 + b
|
|
778 |
if x2 < 0 - x: # second point is left of region
|
|
779 |
# impossible to have vertical line here, could be horizontal
|
|
780 |
# but that doesn't matter as m = 0, b = y1 in that case
|
|
781 |
x2 = 0 - x
|
|
782 |
y2 = m*x2 + b
|
|
783 |
if x1 > w + x: # first point is right of region
|
|
784 |
# impossible to have vertical line here, could be horizontal
|
|
785 |
# but that doesn't matter as m = 0, b = y1 in that case
|
|
786 |
x1 = w + x
|
|
787 |
y1 = m*x1 + b
|
|
788 |
if x2 > w + x: # second point is right of region
|
|
789 |
# impossible to have vertical line here, could be horizontal
|
|
790 |
# but that doesn't matter as m = 0, b = y1 in that case
|
|
791 |
x2 = w + x
|
|
792 |
y2 = m*x2 + b
|
|
793 |
if y1 < 0 - y: # first point is below the region
|
|
794 |
# impossible to have horizontal line here, could be vertical though
|
|
795 |
# if is vertical then x value does not need to change
|
757 |
796 |
y1 = 0 - y
|
758 |
|
if y2 < 0 - y:
|
759 |
|
x2 = ( x1 * y2 - x2 * y1 ) / ( y2 - y1 )
|
|
797 |
if not is_vertical: # if veritical then X doesn't need to change
|
|
798 |
x1 = (y1 - b) / m
|
|
799 |
if y2 < 0 - y: # second point is below the region
|
|
800 |
# impossible to have horizontal line here, could be vertical though
|
|
801 |
# if is vertical then x value does not need to change
|
760 |
802 |
y2 = 0 - y
|
761 |
|
if y1 > h + y:
|
762 |
|
x1 = x1 + ( h + y - y1 ) * ( x2 - x1 ) / ( y2 - y1 )
|
|
803 |
if not is_vertical: # if vertical then X doesn't need to change
|
|
804 |
x2 = (y2 - b) / m
|
|
805 |
if y1 > h + y: # first point is above the region
|
|
806 |
# impossible to have horizontal line here, could be vertical though
|
|
807 |
# if is vertical then x value does not need to change
|
763 |
808 |
y1 = h + y
|
764 |
|
if y2 > h + y:
|
765 |
|
x2 = x1 + ( h + y - y1) * ( x2 - x1 ) / ( y2 - y1 )
|
|
809 |
if not is_vertical: # if vertical then X doesn't need to change
|
|
810 |
x1 = (y1 - b) / m
|
|
811 |
if y2 > h + y: # second point is above the region
|
|
812 |
# impossible to have horizontal line here, could be vertical though
|
|
813 |
# if is vertical then x value does not need to change
|
766 |
814 |
y2 = h + y
|
|
815 |
if not is_vertical: # if vertical then X doesn't need to change
|
|
816 |
x2 = (y2 - b) / m
|
|
817 |
# recheck point approximate equivalance because both points may have been
|
|
818 |
# outside the region and thus were both clipped to a point on the boundary
|
|
819 |
if float_eq( x1, x2 ) and float_eq( y1, y2 ):
|
|
820 |
return [ 0, 0, 0, 0 ]
|
|
821 |
# return the clipped region
|
767 |
822 |
return [ x1, y1, x2, y2 ]
|
768 |
823 |
lines = []
|
769 |
824 |
hasXMin = False
|
... | ... | |
772 |
827 |
hasYMax = False
|
773 |
828 |
for edge in edges:
|
774 |
829 |
if edge[ 1 ] >= 0 and edge[ 2 ] >= 0: # two vertices
|
775 |
|
[ x1, y1, x2, y2 ] = clip_line( c.vertices[ edge[ 1 ] ][ 0 ], c.vertices[ edge[ 1 ] ][ 1 ], c.vertices[ edge[ 2 ] ][ 0 ], c.vertices[ edge[ 2 ] ][ 1 ], width, height, exX, exY )
|
|
830 |
[ x1, y1, x2, y2 ] = clip_line( c.vertices[ edge[ 1 ] ][ 0 ], c.vertices[ edge[ 1 ] ][ 1 ], c.vertices[ edge[ 2 ] ][ 0 ], c.vertices[ edge[ 2 ] ][ 1 ], width, height, exX, exY )
|
776 |
831 |
elif edge[ 1 ] >= 0: # only one vertex
|
777 |
832 |
if c.lines[ edge[ 0 ] ][ 1 ] == 0: # vertical line
|
778 |
|
xtemp = c.lines[ edge[ 0 ] ][ 2 ] / c.lines[ edge[ 0 ] ][ 0 ]
|
|
833 |
xtemp = c.vertices[ edge[ 1 ] ][ 0 ]
|
779 |
834 |
if c.vertices[ edge[ 1 ] ][ 1 ] > ( height + exY ) / 2:
|
780 |
835 |
ytemp = height + exY
|
781 |
836 |
else:
|
782 |
|
ytemp = 0 - exX
|
|
837 |
ytemp = 0.0 - exY
|
783 |
838 |
else:
|
784 |
839 |
xtemp = width + exX
|
785 |
|
ytemp = ( c.lines[ edge[ 0 ] ][ 2 ] - ( width + exX ) * c.lines[ edge[ 0 ] ][ 0 ] ) / c.lines[ edge[ 0 ] ][ 1 ]
|
|
840 |
ytemp = ( c.lines[ edge[ 0 ] ][ 2 ] - xtemp * c.lines[ edge[ 0 ] ][ 0 ] ) / c.lines[ edge[ 0 ] ][ 1 ]
|
786 |
841 |
[ x1, y1, x2, y2 ] = clip_line( c.vertices[ edge[ 1 ] ][ 0 ], c.vertices[ edge[ 1 ] ][ 1 ], xtemp, ytemp, width, height, exX, exY )
|
787 |
842 |
elif edge[ 2 ] >= 0: # only one vertex
|
788 |
843 |
if c.lines[ edge[ 0 ] ][ 1 ] == 0: # vertical line
|
789 |
|
xtemp = c.lines[ edge[ 0 ] ][ 2 ] / c.lines[ edge[ 0 ] ][ 0 ]
|
|
844 |
xtemp = c.vertices[ edge[ 2 ] ][ 0 ]
|
790 |
845 |
if c.vertices[ edge[ 2 ] ][ 1 ] > ( height + exY ) / 2:
|
791 |
846 |
ytemp = height + exY
|
792 |
847 |
else:
|
793 |
848 |
ytemp = 0.0 - exY
|
794 |
849 |
else:
|
795 |
850 |
xtemp = 0.0 - exX
|
796 |
|
ytemp = c.lines[ edge[ 0 ] ][ 2 ] / c.lines[ edge[ 0 ] ][ 1 ]
|
|
851 |
ytemp = ( c.lines[ edge[ 0 ] ][ 2 ] - xtemp * c.lines[ edge[ 0 ] ][ 0 ] ) / c.lines[ edge[ 0 ] ][ 1 ]
|
797 |
852 |
[ x1, y1, x2, y2 ] = clip_line( xtemp, ytemp, c.vertices[ edge[ 2 ] ][ 0 ], c.vertices[ edge[ 2 ] ][ 1 ], width, height, exX, exY )
|
798 |
853 |
if x1 or x2 or y1 or y2:
|
799 |
854 |
lines.append( QgsPoint( x1 + extent.xMinimum(), y1 + extent.yMinimum() ) )
|
800 |
855 |
lines.append( QgsPoint( x2 + extent.xMinimum(), y2 + extent.yMinimum() ) )
|
801 |
|
if 0 - exX in ( x1, x2 ):
|
|
856 |
if 0.0 - exX in ( x1, x2 ):
|
802 |
857 |
hasXMin = True
|
803 |
|
if 0 - exY in ( y1, y2 ):
|
|
858 |
if 0.0 - exY in ( y1, y2 ):
|
804 |
859 |
hasYMin = True
|
805 |
860 |
if height + exY in ( y1, y2 ):
|
806 |
861 |
hasYMax = True
|