Imported Upstream version 9.0
Tobias Winchen
7 years ago
0 | # Example script for using ParseDig class to extract curves and their points from Engauge DIG file, and apply | |
1 | # curve fitting | |
2 | # | |
3 | # Requirements: | |
4 | # 1) python3 (versus python2) | |
5 | # 2) numpy | |
6 | # 3) DefaultListOrderedDict.py from the Engauge scripts directory | |
7 | # 4) ParseDig.py from the Engauge scripts directory | |
8 | ||
9 | from ParseDig import ParseDig | |
10 | from numpy import poly1d | |
11 | from numpy import polyfit | |
12 | ||
13 | import sys | |
14 | ||
15 | defaultHighestOrder = 3 | |
16 | if len(sys.argv) < 2: | |
17 | print ("Usage: python3 CurveFitting.py <dig file> [<highest order>]") | |
18 | print ("where:") | |
19 | print (" <dig file> Version 6 or newer DIG file") | |
20 | print (" <highest order> Highest order of polynomial to be fit to the data. Default is " + defaultHighestOrder) | |
21 | print ("Example: python3 CurveFitting.py samples/CurveFitting.dig") | |
22 | else: | |
23 | parseDig = ParseDig (sys.argv [1]) | |
24 | highestOrderUser = defaultHighestOrder | |
25 | if len(sys.argv) == 3: | |
26 | highestOrderUser = int (sys.argv [2]) | |
27 | curveNames = parseDig.curveNames() | |
28 | for curveName in curveNames: | |
29 | ||
30 | print () | |
31 | ||
32 | # Show (x,y) points as Nx2 matrix | |
33 | curve = parseDig.curve (curveName) | |
34 | ||
35 | # Show (x,y) points as 2 vectors | |
36 | xVector = [row [0] for row in curve] | |
37 | yVector = [row [1] for row in curve] | |
38 | ||
39 | # Fit linear and higher order polynomials. Highest order is less than number of points to prevent overfitting | |
40 | highestOrderNoOverfit = len (xVector) - 1 | |
41 | for order in range (0, 1 + min (highestOrderUser, highestOrderNoOverfit)): | |
42 | z = polyfit (xVector, yVector, order) | |
43 | p = poly1d (z) | |
44 | rmsError = 0 | |
45 | for i in range (0, len (xVector)): | |
46 | x = xVector [i] | |
47 | y = yVector [i] | |
48 | rmsError += (p (x) - y) * (p (x) - y) | |
49 | print ("Curve '" + curveName + "' with polynomial fit to order " + str (order) + " has rms error " + str (rmsError)) | |
50 |
17 | 17 | curveNames = parseDig.curveNames() |
18 | 18 | print ("Curve names = ", curveNames, "\n") |
19 | 19 | for curveName in curveNames: |
20 | ||
21 | # Show (x,y) points as Nx2 matrix | |
20 | 22 | curve = parseDig.curve (curveName) |
21 | 23 | print ("Curve ", "'" + curveName + "'", " = ", curve, "\n"); |
24 | ||
25 | # Show (x,y) points as 2 vectors | |
26 | x = [row [0] for row in curve] | |
27 | y = [row [1] for row in curve] | |
28 | print ("x=", x, "y=", y) | |
29 | ||
30 |
0 | #!/usr/bin/python | |
1 | # | |
2 | # Usage - python insert_derived_column.py <csv file> | |
3 | # Purpose - This script reads in a table of (longitude,latitude) data points, and then | |
4 | # outputs a set of evenly spaced waypoints through those points assuming a constant | |
5 | # velocity (variable velocityMps) | |
6 | # Installation requirements - 1) sudo apt-get install python | |
7 | # 2) sudo apt-get install python-dev (or python-devel) | |
8 | # 3) sudo pip install numpy | |
9 | ||
10 | from datetime import datetime, timedelta | |
11 | import fileinput | |
12 | import math | |
13 | import numpy as np | |
14 | ||
15 | def is_number(s): | |
16 | try: | |
17 | float(s) | |
18 | return True | |
19 | except ValueError: | |
20 | return False | |
21 | ||
22 | try: | |
23 | import unicodedata | |
24 | unicodedata.numeric(s) | |
25 | return True | |
26 | except (TypeError, ValueError): | |
27 | return False | |
28 | ||
29 | def readFieldsWithCommas(line): | |
30 | return line.replace ("\n", "").split (",") | |
31 | ||
32 | def xyzFromLatLonAlt (latLonAlt): | |
33 | rearth = 6378160 | |
34 | pi = 3.1415926535 | |
35 | radians2degrees = pi / 180.0 | |
36 | lat = latLonAlt [0] * radians2degrees | |
37 | lon = latLonAlt [1] * radians2degrees | |
38 | radius = rearth + latLonAlt [2] | |
39 | x = radius * math.cos (lat) * math.cos (lon) | |
40 | y = radius * math.cos (lat) * math.sin (lon) | |
41 | z = radius * math.sin (lat) | |
42 | return np.array ([x, y, z]) | |
43 | ||
44 | # User inputs | |
45 | altitudeM = 5000 | |
46 | velocityMps = 69 # 69 m/s = 250 km/hr | |
47 | curDateTime = datetime (2015, 1, 1, 0, 0, 0) | |
48 | ||
49 | # Loop through input file lines | |
50 | isFirst = True | |
51 | xyzLast = np.array ([0, 0, 0]) | |
52 | for line in fileinput.input(): | |
53 | fields = readFieldsWithCommas (line) | |
54 | ||
55 | # Skip header which does not have numeric fields | |
56 | if is_number (fields [0]) and is_number (fields [1]): | |
57 | ||
58 | # Convert latitude and longitude to cartesian x,y,z coordinates | |
59 | lat = float (fields [1]) | |
60 | lon = float (fields [0]) | |
61 | ||
62 | latLonAlt = np.array ([lat, | |
63 | lon, | |
64 | altitudeM]) | |
65 | xyz = xyzFromLatLonAlt (latLonAlt) | |
66 | xyzDeltaMag = 0 | |
67 | if isFirst: | |
68 | isFirst = False | |
69 | else: | |
70 | xyzDelta = np.subtract (xyz, xyzLast) | |
71 | xyzDeltaMag = np.linalg.norm (xyzDelta) | |
72 | ||
73 | # Output | |
74 | timestamp = curDateTime.strftime ('"%j %Y %H:%M:%S.%f"') | |
75 | fields.insert (0, timestamp) | |
76 | ||
77 | # Use one of the following lines. The first is for python2, and the second is for python3 | |
78 | print ', '.join (str (x) for x in fields) | |
79 | #print (', '.join (str (x) for x in fields)) | |
80 | ||
81 | # Update for next iteration | |
82 | timeTraveledS = xyzDeltaMag / velocityMps | |
83 | curDateTime = curDateTime + timedelta(seconds = timeTraveledS) | |
84 | xyzLast = xyz | |
85 |
0 | CurveFitting.py Python script that reads in a DIG file and performs polynomial curve fitting | |
0 | 1 | ExampleParseDig.py Python script that shows how to use ParseDig.py. This script dumps the DIG file specified in |
1 | 2 | the command line. This code can serve as a starting point for other scripts that can process |
2 | 3 | the information into other output formats - like SQL tables and NETCDF. |
3 | insert_derived_column.py Python script that reads in (longitude,latitude) points and output those points with a timestamp | |
4 | InsertDerivedColumn.py Python script that reads in (longitude,latitude) points and output those points with a timestamp | |
4 | 5 | at each point that is computed assuming a constant speed through the points |
5 | 6 | ParseDig.py Python class that reads Engauge Digitizer DIG files, and provides that information through a |
6 | 7 | very simplie application programming interface (API) |
0 | #!/usr/bin/python | |
1 | # | |
2 | # Usage - python insert_derived_column.py <csv file> | |
3 | # Purpose - This script reads in a table of (longitude,latitude) data points, and then | |
4 | # outputs a set of evenly spaced waypoints through those points assuming a constant | |
5 | # velocity (variable velocityMps) | |
6 | # Installation requirements - 1) sudo apt-get install python | |
7 | # 2) sudo apt-get install python-dev (or python-devel) | |
8 | # 3) sudo pip install numpy | |
9 | ||
10 | from datetime import datetime, timedelta | |
11 | import fileinput | |
12 | import math | |
13 | import numpy as np | |
14 | ||
15 | def is_number(s): | |
16 | try: | |
17 | float(s) | |
18 | return True | |
19 | except ValueError: | |
20 | return False | |
21 | ||
22 | try: | |
23 | import unicodedata | |
24 | unicodedata.numeric(s) | |
25 | return True | |
26 | except (TypeError, ValueError): | |
27 | return False | |
28 | ||
29 | def readFieldsWithCommas(line): | |
30 | return line.replace ("\n", "").split (",") | |
31 | ||
32 | def xyzFromLatLonAlt (latLonAlt): | |
33 | rearth = 6378160 | |
34 | pi = 3.1415926535 | |
35 | radians2degrees = pi / 180.0 | |
36 | lat = latLonAlt [0] * radians2degrees | |
37 | lon = latLonAlt [1] * radians2degrees | |
38 | radius = rearth + latLonAlt [2] | |
39 | x = radius * math.cos (lat) * math.cos (lon) | |
40 | y = radius * math.cos (lat) * math.sin (lon) | |
41 | z = radius * math.sin (lat) | |
42 | return np.array ([x, y, z]) | |
43 | ||
44 | # User inputs | |
45 | altitudeM = 5000 | |
46 | velocityMps = 69 # 69 m/s = 250 km/hr | |
47 | curDateTime = datetime (2015, 1, 1, 0, 0, 0) | |
48 | ||
49 | # Loop through input file lines | |
50 | isFirst = True | |
51 | xyzLast = np.array ([0, 0, 0]) | |
52 | for line in fileinput.input(): | |
53 | fields = readFieldsWithCommas (line) | |
54 | ||
55 | # Skip header which does not have numeric fields | |
56 | if is_number (fields [0]) and is_number (fields [1]): | |
57 | ||
58 | # Convert latitude and longitude to cartesian x,y,z coordinates | |
59 | lat = float (fields [1]) | |
60 | lon = float (fields [0]) | |
61 | ||
62 | latLonAlt = np.array ([lat, | |
63 | lon, | |
64 | altitudeM]) | |
65 | xyz = xyzFromLatLonAlt (latLonAlt) | |
66 | xyzDeltaMag = 0 | |
67 | if isFirst: | |
68 | isFirst = False | |
69 | else: | |
70 | xyzDelta = np.subtract (xyz, xyzLast) | |
71 | xyzDeltaMag = np.linalg.norm (xyzDelta) | |
72 | ||
73 | # Output | |
74 | timestamp = curDateTime.strftime ('"%j %Y %H:%M:%S.%f"') | |
75 | fields.insert (0, timestamp) | |
76 | ||
77 | # Use one of the following lines. The first is for python2, and the second is for python3 | |
78 | print ', '.join (str (x) for x in fields) | |
79 | #print (', '.join (str (x) for x in fields)) | |
80 | ||
81 | # Update for next iteration | |
82 | timeTraveledS = xyzDeltaMag / velocityMps | |
83 | curDateTime = curDateTime + timedelta(seconds = timeTraveledS) | |
84 | xyzLast = xyz | |
85 |
0 | <?xml version="1.0" encoding="UTF-8"?> | |
1 | <!DOCTYPE engauge> | |
2 | <Document VersionNumber="9.0" AxesPointsRequired="0"> | |
3 | <Image Width="1028" Height="593"><![CDATA[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]]></Image> | |
4 | <CoordSystem> | |
5 | <General CursorSize="3" ExtraPrecision="1"/> | |
6 | <Coords Type="0" TypeString="Cartesian" Coords="0" ScaleXTheta="0" ScaleXThetaString="Linear" ScaleYRadius="0" ScaleYRadiusString="Linear" UnitsX="0" UnitsXString="Number" UnitsY="0" UnitsYString="Number" UnitsTheta="0" UnitsThetaString="Degrees (DDD.DDDDD)" UnitsRadius="0" UnitsRadiusString="Number" UnitsDate="3" UnitsDateString="YYYY/MM/DD" UnitsTime="2" UnitsTimeString="HH:MM:SS"/> | |
7 | <DigitizeCurve CursorInnerRadius="5" CursorLineWidth="2" CursorSize="1" CursorStandardCross="True"/> | |
8 | <Export PointsSelectionFunctions="0" PointsSelectionFunctionsString="InterpolateAllCurves" PointsIntervalFunctions="10" PointsIntervalUnitsFunctions="1" PointsSelectionRelations="0" PointsSelectionRelationsString="Interpolate" PointsIntervalUnitsRelations="1" PointsIntervalRelations="10" LayoutFunctions="0" LayoutFunctionsString="AllPerLine" Delimiter="0" OverrideCsvTsv="True" DelimiterString="Commas" Header="1" HeaderString="Simple" XLabel="x"> | |
9 | <CurveNamesNotExported/> | |
10 | </Export> | |
11 | <AxesChecker Mode="1" Seconds="3" LineColor="6"/> | |
12 | <GridDisplay Stable="True" DisableX="0" CountX="7" StartX="0" StepX="1" StopX="6" DisableY="0" CountY="4" StartY="0" StepY="5" StopY="15" Color="0" ColorString="Black"/> | |
13 | <GridRemoval Stable="False" DefinedGridLines="False" CloseDistance="10" CoordDisableX="0" CoordDisableXString="Count" CountX="26" StartX="0.184793" StepX="0.110612" StopX="2.95008" CoordDisableY="0" CoordDisableYString="Count" CountY="6" StartY="-10.0584" StepY="2.82517" StopY="4.06742"/> | |
14 | <PointMatch PointSize="48" ColorAccepted="4" ColorAcceptedString="Green" ColorCandidate="7" ColorCandidateString="Yellow" ColorRejected="6" ColorRejectedString="Red"/> | |
15 | <Segments PointSeparation="25" MinLength="2" FillCorners="False" LineWidth="4" LineColor="4" LineColorString="Green"/> | |
16 | <Curve CurveName="Axes"> | |
17 | <ColorFilter CurveName="Axes" Mode="2" ModeString="Intensity" IntensityLow="0" IntensityHigh="50" ForegroundLow="0" ForegroundHigh="10" HueLow="180" HueHigh="360" SaturationLow="50" SaturationHigh="100" ValueLow="0" ValueHigh="50"/> | |
18 | <CurveStyle CurveName="Axes"> | |
19 | <LineStyle Width="0" Color="8" ColorString="Transparent" ConnectAs="4" ConnectAsString="ConnectSkipForAxisCurve"/> | |
20 | <PointStyle Radius="10" LineWidth="1" Color="6" ColorString="Red" Shape="1" ShapeString="Cross"/> | |
21 | </CurveStyle> | |
22 | <CurvePoints> | |
23 | <Point Identifier="Axes	point	1" Ordinal="1" IsAxisPoint="True" IsXOnly="False" Index="18"> | |
24 | <PositionScreen X="61.5043" Y="350.18"/> | |
25 | <PositionGraph X="0.5" Y="0"/> | |
26 | </Point> | |
27 | <Point Identifier="Axes	point	3" Ordinal="2" IsAxisPoint="True" IsXOnly="False" Index="18"> | |
28 | <PositionScreen X="830.707" Y="350.9"/> | |
29 | <PositionGraph X="5.5" Y="0"/> | |
30 | </Point> | |
31 | <Point Identifier="Axes	point	5" Ordinal="3" IsAxisPoint="True" IsXOnly="False" Index="18"> | |
32 | <PositionScreen X="61.5043" Y="21.616"/> | |
33 | <PositionGraph X="0.5" Y="15"/> | |
34 | </Point> | |
35 | </CurvePoints> | |
36 | </Curve> | |
37 | <CurvesGraphs> | |
38 | <Curve CurveName="linear"> | |
39 | <ColorFilter CurveName="linear" Mode="2" ModeString="Intensity" IntensityLow="0" IntensityHigh="50" ForegroundLow="0" ForegroundHigh="10" HueLow="180" HueHigh="360" SaturationLow="50" SaturationHigh="100" ValueLow="0" ValueHigh="50"/> | |
40 | <CurveStyle CurveName="linear"> | |
41 | <LineStyle Width="1" Color="1" ColorString="Blue" ConnectAs="0" ConnectAsString="FunctionSmooth"/> | |
42 | <PointStyle Radius="10" LineWidth="1" Color="1" ColorString="Blue" Shape="1" ShapeString="Cross"/> | |
43 | </CurveStyle> | |
44 | <CurvePoints> | |
45 | <Point Identifier="linear	point	6" Ordinal="0" IsAxisPoint="False" IsXOnly="False" Index="18"> | |
46 | <PositionScreen X="137.386" Y="347.298"/> | |
47 | </Point> | |
48 | <Point Identifier="linear	point	7" Ordinal="1" IsAxisPoint="False" IsXOnly="False" Index="18"> | |
49 | <PositionScreen X="290.747" Y="325.682"/> | |
50 | </Point> | |
51 | <Point Identifier="linear	point	8" Ordinal="2" IsAxisPoint="False" IsXOnly="False" Index="18"> | |
52 | <PositionScreen X="446.505" Y="305.507"/> | |
53 | </Point> | |
54 | </CurvePoints> | |
55 | </Curve> | |
56 | <Curve CurveName="quadratic"> | |
57 | <ColorFilter CurveName="quadratic" Mode="2" ModeString="Intensity" IntensityLow="0" IntensityHigh="50" ForegroundLow="0" ForegroundHigh="10" HueLow="180" HueHigh="360" SaturationLow="50" SaturationHigh="100" ValueLow="0" ValueHigh="50"/> | |
58 | <CurveStyle CurveName="quadratic"> | |
59 | <LineStyle Width="1" Color="1" ColorString="Blue" ConnectAs="0" ConnectAsString="FunctionSmooth"/> | |
60 | <PointStyle Radius="10" LineWidth="1" Color="1" ColorString="Blue" Shape="5" ShapeString="X"/> | |
61 | </CurveStyle> | |
62 | <CurvePoints> | |
63 | <Point Identifier="quadratic	point	9" Ordinal="0" IsAxisPoint="False" IsXOnly="False" Index="18"> | |
64 | <PositionScreen X="138.185" Y="175.81"/> | |
65 | </Point> | |
66 | <Point Identifier="quadratic	point	10" Ordinal="1" IsAxisPoint="False" IsXOnly="False" Index="18"> | |
67 | <PositionScreen X="292.345" Y="244.261"/> | |
68 | </Point> | |
69 | <Point Identifier="quadratic	point	11" Ordinal="2" IsAxisPoint="False" IsXOnly="False" Index="18"> | |
70 | <PositionScreen X="444.908" Y="282.45"/> | |
71 | </Point> | |
72 | <Point Identifier="quadratic	point	12" Ordinal="3" IsAxisPoint="False" IsXOnly="False" Index="18"> | |
73 | <PositionScreen X="599.068" Y="244.261"/> | |
74 | </Point> | |
75 | </CurvePoints> | |
76 | </Curve> | |
77 | <Curve CurveName="cubic"> | |
78 | <ColorFilter CurveName="cubic" Mode="2" ModeString="Intensity" IntensityLow="0" IntensityHigh="50" ForegroundLow="0" ForegroundHigh="10" HueLow="180" HueHigh="360" SaturationLow="50" SaturationHigh="100" ValueLow="0" ValueHigh="50"/> | |
79 | <CurveStyle CurveName="cubic"> | |
80 | <LineStyle Width="1" Color="1" ColorString="Blue" ConnectAs="0" ConnectAsString="FunctionSmooth"/> | |
81 | <PointStyle Radius="10" LineWidth="1" Color="1" ColorString="Blue" Shape="2" ShapeString="Diamond"/> | |
82 | </CurveStyle> | |
83 | <CurvePoints> | |
84 | <Point Identifier="cubic	point	13" Ordinal="0" IsAxisPoint="False" IsXOnly="False" Index="18"> | |
85 | <PositionScreen X="139.782" Y="425.836"/> | |
86 | </Point> | |
87 | <Point Identifier="cubic	point	14" Ordinal="1" IsAxisPoint="False" IsXOnly="False" Index="18"> | |
88 | <PositionScreen X="291.546" Y="472.671"/> | |
89 | </Point> | |
90 | <Point Identifier="cubic	point	15" Ordinal="2" IsAxisPoint="False" IsXOnly="False" Index="18"> | |
91 | <PositionScreen X="446.505" Y="443.849"/> | |
92 | </Point> | |
93 | <Point Identifier="cubic	point	16" Ordinal="3" IsAxisPoint="False" IsXOnly="False" Index="18"> | |
94 | <PositionScreen X="599.068" Y="311.991"/> | |
95 | </Point> | |
96 | <Point Identifier="cubic	point	17" Ordinal="4" IsAxisPoint="False" IsXOnly="False" Index="18"> | |
97 | <PositionScreen X="753.228" Y="48.9964"/> | |
98 | </Point> | |
99 | </CurvePoints> | |
100 | </Curve> | |
101 | </CurvesGraphs> | |
102 | </CoordSystem> | |
103 | </Document> |
0 | <?xml version="1.0" encoding="UTF-8"?> | |
1 | <!DOCTYPE engauge> | |
2 | <Document VersionNumber="9.0" AxesPointsRequired="0"> | |
3 | <Image Width="1028" Height="593"><![CDATA[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]]></Image> | |
4 | <CoordSystem> | |
5 | <General CursorSize="3" ExtraPrecision="1"/> | |
6 | <Coords Type="0" TypeString="Cartesian" Coords="0" ScaleXTheta="0" ScaleXThetaString="Linear" ScaleYRadius="0" ScaleYRadiusString="Linear" UnitsX="0" UnitsXString="Number" UnitsY="0" UnitsYString="Number" UnitsTheta="0" UnitsThetaString="Degrees (DDD.DDDDD)" UnitsRadius="0" UnitsRadiusString="Number" UnitsDate="3" UnitsDateString="YYYY/MM/DD" UnitsTime="2" UnitsTimeString="HH:MM:SS"/> | |
7 | <DigitizeCurve CursorInnerRadius="5" CursorLineWidth="2" CursorSize="1" CursorStandardCross="True"/> | |
8 | <Export PointsSelectionFunctions="0" PointsSelectionFunctionsString="InterpolateAllCurves" PointsIntervalFunctions="10" PointsIntervalUnitsFunctions="1" PointsSelectionRelations="0" PointsSelectionRelationsString="Interpolate" PointsIntervalUnitsRelations="1" PointsIntervalRelations="10" LayoutFunctions="0" LayoutFunctionsString="AllPerLine" Delimiter="0" OverrideCsvTsv="True" DelimiterString="Commas" Header="1" HeaderString="Simple" XLabel="x"> | |
9 | <CurveNamesNotExported/> | |
10 | </Export> | |
11 | <AxesChecker Mode="1" Seconds="3" LineColor="6"/> | |
12 | <GridDisplay Stable="True" DisableX="0" CountX="7" StartX="0" StepX="1" StopX="6" DisableY="0" CountY="4" StartY="0" StepY="5" StopY="15" Color="0" ColorString="Black"/> | |
13 | <GridRemoval Stable="False" DefinedGridLines="False" CloseDistance="10" CoordDisableX="0" CoordDisableXString="Count" CountX="26" StartX="0.184793" StepX="0.110612" StopX="2.95008" CoordDisableY="0" CoordDisableYString="Count" CountY="6" StartY="-10.0584" StepY="2.82516" StopY="4.06741"/> | |
14 | <PointMatch PointSize="48" ColorAccepted="4" ColorAcceptedString="Green" ColorCandidate="7" ColorCandidateString="Yellow" ColorRejected="6" ColorRejectedString="Red"/> | |
15 | <Segments PointSeparation="25" MinLength="2" FillCorners="False" LineWidth="4" LineColor="4" LineColorString="Green"/> | |
16 | <Curve CurveName="Axes"> | |
17 | <ColorFilter CurveName="Axes" Mode="2" ModeString="Intensity" IntensityLow="0" IntensityHigh="50" ForegroundLow="0" ForegroundHigh="10" HueLow="180" HueHigh="360" SaturationLow="50" SaturationHigh="100" ValueLow="0" ValueHigh="50"/> | |
18 | <CurveStyle CurveName="Axes"> | |
19 | <LineStyle Width="0" Color="8" ColorString="Transparent" ConnectAs="4" ConnectAsString="ConnectSkipForAxisCurve"/> | |
20 | <PointStyle Radius="10" LineWidth="1" Color="6" ColorString="Red" Shape="1" ShapeString="Cross"/> | |
21 | </CurveStyle> | |
22 | <CurvePoints> | |
23 | <Point Identifier="Axes	point	1" Ordinal="1" IsAxisPoint="True" IsXOnly="False" Index="40"> | |
24 | <PositionScreen X="61.5043" Y="350.18"/> | |
25 | <PositionGraph X="0.5" Y="0"/> | |
26 | </Point> | |
27 | <Point Identifier="Axes	point	3" Ordinal="2" IsAxisPoint="True" IsXOnly="False" Index="40"> | |
28 | <PositionScreen X="830.707" Y="350.9"/> | |
29 | <PositionGraph X="5.5" Y="0"/> | |
30 | </Point> | |
31 | <Point Identifier="Axes	point	5" Ordinal="3" IsAxisPoint="True" IsXOnly="False" Index="40"> | |
32 | <PositionScreen X="61.5043" Y="21.616"/> | |
33 | <PositionGraph X="0.5" Y="15"/> | |
34 | </Point> | |
35 | </CurvePoints> | |
36 | </Curve> | |
37 | <CurvesGraphs> | |
38 | <Curve CurveName="linear"> | |
39 | <ColorFilter CurveName="linear" Mode="2" ModeString="Intensity" IntensityLow="0" IntensityHigh="50" ForegroundLow="0" ForegroundHigh="10" HueLow="180" HueHigh="360" SaturationLow="50" SaturationHigh="100" ValueLow="0" ValueHigh="50"/> | |
40 | <CurveStyle CurveName="linear"> | |
41 | <LineStyle Width="1" Color="1" ColorString="Blue" ConnectAs="0" ConnectAsString="FunctionSmooth"/> | |
42 | <PointStyle Radius="10" LineWidth="1" Color="1" ColorString="Blue" Shape="1" ShapeString="Cross"/> | |
43 | </CurveStyle> | |
44 | <CurvePoints> | |
45 | <Point Identifier="linear	point	6" Ordinal="0" IsAxisPoint="False" IsXOnly="False" Index="40"> | |
46 | <PositionScreen X="137.386" Y="347.298"/> | |
47 | </Point> | |
48 | <Point Identifier="linear	point	18" Ordinal="1" IsAxisPoint="False" IsXOnly="False" Index="40"> | |
49 | <PositionScreen X="178.123" Y="341.533"/> | |
50 | </Point> | |
51 | <Point Identifier="linear	point	19" Ordinal="2" IsAxisPoint="False" IsXOnly="False" Index="40"> | |
52 | <PositionScreen X="235.633" Y="334.328"/> | |
53 | </Point> | |
54 | <Point Identifier="linear	point	7" Ordinal="3" IsAxisPoint="False" IsXOnly="False" Index="40"> | |
55 | <PositionScreen X="290.747" Y="325.682"/> | |
56 | </Point> | |
57 | <Point Identifier="linear	point	20" Ordinal="4" IsAxisPoint="False" IsXOnly="False" Index="40"> | |
58 | <PositionScreen X="330.685" Y="320.638"/> | |
59 | </Point> | |
60 | <Point Identifier="linear	point	21" Ordinal="5" IsAxisPoint="False" IsXOnly="False" Index="40"> | |
61 | <PositionScreen X="399.378" Y="311.271"/> | |
62 | </Point> | |
63 | <Point Identifier="linear	point	8" Ordinal="6" IsAxisPoint="False" IsXOnly="False" Index="40"> | |
64 | <PositionScreen X="446.505" Y="305.507"/> | |
65 | </Point> | |
66 | </CurvePoints> | |
67 | </Curve> | |
68 | <Curve CurveName="quadratic"> | |
69 | <ColorFilter CurveName="quadratic" Mode="2" ModeString="Intensity" IntensityLow="0" IntensityHigh="50" ForegroundLow="0" ForegroundHigh="10" HueLow="180" HueHigh="360" SaturationLow="50" SaturationHigh="100" ValueLow="0" ValueHigh="50"/> | |
70 | <CurveStyle CurveName="quadratic"> | |
71 | <LineStyle Width="1" Color="1" ColorString="Blue" ConnectAs="0" ConnectAsString="FunctionSmooth"/> | |
72 | <PointStyle Radius="10" LineWidth="1" Color="1" ColorString="Blue" Shape="5" ShapeString="X"/> | |
73 | </CurveStyle> | |
74 | <CurvePoints> | |
75 | <Point Identifier="quadratic	point	9" Ordinal="0" IsAxisPoint="False" IsXOnly="False" Index="40"> | |
76 | <PositionScreen X="138.185" Y="175.81"/> | |
77 | </Point> | |
78 | <Point Identifier="quadratic	point	22" Ordinal="1" IsAxisPoint="False" IsXOnly="False" Index="40"> | |
79 | <PositionScreen X="169.336" Y="189.501"/> | |
80 | </Point> | |
81 | <Point Identifier="quadratic	point	23" Ordinal="2" IsAxisPoint="False" IsXOnly="False" Index="40"> | |
82 | <PositionScreen X="234.036" Y="219.043"/> | |
83 | </Point> | |
84 | <Point Identifier="quadratic	point	10" Ordinal="3" IsAxisPoint="False" IsXOnly="False" Index="40"> | |
85 | <PositionScreen X="292.345" Y="244.261"/> | |
86 | </Point> | |
87 | <Point Identifier="quadratic	point	24" Ordinal="4" IsAxisPoint="False" IsXOnly="False" Index="40"> | |
88 | <PositionScreen X="331.484" Y="258.672"/> | |
89 | </Point> | |
90 | <Point Identifier="quadratic	point	11" Ordinal="5" IsAxisPoint="False" IsXOnly="False" Index="40"> | |
91 | <PositionScreen X="444.908" Y="282.45"/> | |
92 | </Point> | |
93 | <Point Identifier="quadratic	point	12" Ordinal="6" IsAxisPoint="False" IsXOnly="False" Index="40"> | |
94 | <PositionScreen X="599.068" Y="244.261"/> | |
95 | </Point> | |
96 | </CurvePoints> | |
97 | </Curve> | |
98 | <Curve CurveName="cubic"> | |
99 | <ColorFilter CurveName="cubic" Mode="2" ModeString="Intensity" IntensityLow="0" IntensityHigh="50" ForegroundLow="0" ForegroundHigh="10" HueLow="180" HueHigh="360" SaturationLow="50" SaturationHigh="100" ValueLow="0" ValueHigh="50"/> | |
100 | <CurveStyle CurveName="cubic"> | |
101 | <LineStyle Width="1" Color="1" ColorString="Blue" ConnectAs="0" ConnectAsString="FunctionSmooth"/> | |
102 | <PointStyle Radius="10" LineWidth="1" Color="1" ColorString="Blue" Shape="2" ShapeString="Diamond"/> | |
103 | </CurveStyle> | |
104 | <CurvePoints> | |
105 | <Point Identifier="cubic	point	13" Ordinal="0" IsAxisPoint="False" IsXOnly="False" Index="40"> | |
106 | <PositionScreen X="139.782" Y="425.836"/> | |
107 | </Point> | |
108 | <Point Identifier="cubic	point	14" Ordinal="1" IsAxisPoint="False" IsXOnly="False" Index="40"> | |
109 | <PositionScreen X="291.546" Y="472.671"/> | |
110 | </Point> | |
111 | <Point Identifier="cubic	point	15" Ordinal="2" IsAxisPoint="False" IsXOnly="False" Index="40"> | |
112 | <PositionScreen X="446.505" Y="443.849"/> | |
113 | </Point> | |
114 | <Point Identifier="cubic	point	16" Ordinal="3" IsAxisPoint="False" IsXOnly="False" Index="40"> | |
115 | <PositionScreen X="599.068" Y="311.991"/> | |
116 | </Point> | |
117 | <Point Identifier="cubic	point	26" Ordinal="4" IsAxisPoint="False" IsXOnly="False" Index="40"> | |
118 | <PositionScreen X="673.352" Y="195.985"/> | |
119 | </Point> | |
120 | <Point Identifier="cubic	point	25" Ordinal="5" IsAxisPoint="False" IsXOnly="False" Index="40"> | |
121 | <PositionScreen X="715.686" Y="118.888"/> | |
122 | </Point> | |
123 | <Point Identifier="cubic	point	17" Ordinal="6" IsAxisPoint="False" IsXOnly="False" Index="40"> | |
124 | <PositionScreen X="753.228" Y="48.9964"/> | |
125 | </Point> | |
126 | </CurvePoints> | |
127 | </Curve> | |
128 | <Curve CurveName="linear-3-points"> | |
129 | <ColorFilter CurveName="linear-3-points" Mode="2" ModeString="Intensity" IntensityLow="0" IntensityHigh="50" ForegroundLow="0" ForegroundHigh="10" HueLow="180" HueHigh="360" SaturationLow="50" SaturationHigh="100" ValueLow="0" ValueHigh="50"/> | |
130 | <CurveStyle CurveName="linear-3-points"> | |
131 | <LineStyle Width="1" Color="1" ColorString="Blue" ConnectAs="0" ConnectAsString="FunctionSmooth"/> | |
132 | <PointStyle Radius="10" LineWidth="1" Color="1" ColorString="Blue" Shape="3" ShapeString="Square"/> | |
133 | </CurveStyle> | |
134 | <CurvePoints> | |
135 | <Point Identifier="linear-3-points	point	27" Ordinal="0" IsAxisPoint="False" IsXOnly="False" Index="40"> | |
136 | <PositionScreen X="137.386" Y="346.577"/> | |
137 | </Point> | |
138 | <Point Identifier="linear-3-points	point	28" Ordinal="1" IsAxisPoint="False" IsXOnly="False" Index="40"> | |
139 | <PositionScreen X="291.546" Y="325.682"/> | |
140 | </Point> | |
141 | <Point Identifier="linear-3-points	point	29" Ordinal="2" IsAxisPoint="False" IsXOnly="False" Index="40"> | |
142 | <PositionScreen X="445.706" Y="304.066"/> | |
143 | </Point> | |
144 | </CurvePoints> | |
145 | </Curve> | |
146 | <Curve CurveName="quadratic-4-points"> | |
147 | <ColorFilter CurveName="quadratic-4-points" Mode="2" ModeString="Intensity" IntensityLow="0" IntensityHigh="50" ForegroundLow="0" ForegroundHigh="10" HueLow="180" HueHigh="360" SaturationLow="50" SaturationHigh="100" ValueLow="0" ValueHigh="50"/> | |
148 | <CurveStyle CurveName="quadratic-4-points"> | |
149 | <LineStyle Width="1" Color="1" ColorString="Blue" ConnectAs="0" ConnectAsString="FunctionSmooth"/> | |
150 | <PointStyle Radius="10" LineWidth="1" Color="1" ColorString="Blue" Shape="1" ShapeString="Cross"/> | |
151 | </CurveStyle> | |
152 | <CurvePoints> | |
153 | <Point Identifier="quadratic-4-points	point	30" Ordinal="0" IsAxisPoint="False" IsXOnly="False" Index="40"> | |
154 | <PositionScreen X="138.185" Y="176.531"/> | |
155 | </Point> | |
156 | <Point Identifier="quadratic-4-points	point	31" Ordinal="1" IsAxisPoint="False" IsXOnly="False" Index="40"> | |
157 | <PositionScreen X="292.345" Y="241.379"/> | |
158 | </Point> | |
159 | <Point Identifier="quadratic-4-points	point	32" Ordinal="2" IsAxisPoint="False" IsXOnly="False" Index="40"> | |
160 | <PositionScreen X="444.908" Y="281.009"/> | |
161 | </Point> | |
162 | <Point Identifier="quadratic-4-points	point	33" Ordinal="3" IsAxisPoint="False" IsXOnly="False" Index="40"> | |
163 | <PositionScreen X="598.269" Y="244.261"/> | |
164 | </Point> | |
165 | </CurvePoints> | |
166 | </Curve> | |
167 | <Curve CurveName="cubic-5-points"> | |
168 | <ColorFilter CurveName="cubic-5-points" Mode="2" ModeString="Intensity" IntensityLow="0" IntensityHigh="50" ForegroundLow="0" ForegroundHigh="10" HueLow="180" HueHigh="360" SaturationLow="50" SaturationHigh="100" ValueLow="0" ValueHigh="50"/> | |
169 | <CurveStyle CurveName="cubic-5-points"> | |
170 | <LineStyle Width="1" Color="1" ColorString="Blue" ConnectAs="0" ConnectAsString="FunctionSmooth"/> | |
171 | <PointStyle Radius="10" LineWidth="1" Color="1" ColorString="Blue" Shape="5" ShapeString="X"/> | |
172 | </CurveStyle> | |
173 | <CurvePoints> | |
174 | <Point Identifier="cubic-5-points	point	34" Ordinal="0" IsAxisPoint="False" IsXOnly="False" Index="40"> | |
175 | <PositionScreen X="138.984" Y="424.395"/> | |
176 | </Point> | |
177 | <Point Identifier="cubic-5-points	point	35" Ordinal="1" IsAxisPoint="False" IsXOnly="False" Index="40"> | |
178 | <PositionScreen X="290.747" Y="473.391"/> | |
179 | </Point> | |
180 | <Point Identifier="cubic-5-points	point	36" Ordinal="2" IsAxisPoint="False" IsXOnly="False" Index="40"> | |
181 | <PositionScreen X="446.505" Y="444.57"/> | |
182 | </Point> | |
183 | <Point Identifier="cubic-5-points	point	37" Ordinal="3" IsAxisPoint="False" IsXOnly="False" Index="40"> | |
184 | <PositionScreen X="599.068" Y="311.271"/> | |
185 | </Point> | |
186 | <Point Identifier="cubic-5-points	point	38" Ordinal="4" IsAxisPoint="False" IsXOnly="False" Index="40"> | |
187 | <PositionScreen X="673.352" Y="193.824"/> | |
188 | </Point> | |
189 | <Point Identifier="cubic-5-points	point	39" Ordinal="5" IsAxisPoint="False" IsXOnly="False" Index="40"> | |
190 | <PositionScreen X="754.825" Y="48.2758"/> | |
191 | </Point> | |
192 | </CurvePoints> | |
193 | </Curve> | |
194 | </CurvesGraphs> | |
195 | </CoordSystem> | |
196 | </Document> |
0 | 0 | <?xml version="1.0" encoding="UTF-8"?> |
1 | 1 | <!DOCTYPE QtCreatorProject> |
2 | <!-- Written by QtCreator 3.0.1, 2016-07-06T22:13:50. --> | |
2 | <!-- Written by QtCreator 3.0.1, 2016-07-17T17:20:43. --> | |
3 | 3 | <qtcreator> |
4 | 4 | <data> |
5 | 5 | <variable>ProjectExplorer.Project.ActiveTarget</variable> |
12 | 12 | <key>CFBundleExecutable</key> |
13 | 13 | <string>Engauge Digitizer</string> |
14 | 14 | <key>CFBundleVersion</key> |
15 | <string>8.3</string> | |
15 | <string>9.0</string> | |
16 | 16 | <key>CFBundleShortVersionString</key> |
17 | <string>8.3</string> | |
17 | <string>9.0</string> | |
18 | 18 | <key>LSApplicationCategoryType</key> |
19 | 19 | <string>public.app-category.utilities</string> |
20 | 20 | <key>CFBundleIdentifier</key> |
0 | rem Usage: build_msi_and_zip.bat <norelease> | |
1 | ||
2 | set ARG1=%1 | |
3 | ||
0 | 4 | call C:\"Program Files (x86)"\"Microsoft Visual Studio 12.0"\VC\vcvarsall.bat x86 |
1 | 5 | |
2 | 6 | set QTDIRS=bearer iconengines imageformats platforms printsupport sqldrivers |
4 | 8 | |
5 | 9 | set ENGAUGE_CONFIG='pdf' |
6 | 10 | set QTLIBEXT='.lib' |
7 | set LOG4CPPDLLINK='https://dl.dropboxusercontent.com/u/1147076/log4cpp-1.1.1.zip' | |
11 | set LOG4CPPDLLINK="https://dl.dropboxusercontent.com/s/gyqcfg2xpm4jjby/log4cpp_null.zip" | |
12 | set FFTWLINK="ftp://ftp.fftw.org/pub/fftw/fftw-3.3.4-dll32.zip" | |
13 | set POPPLERLINK="https://dl.dropboxusercontent.com/u/1147076/poppler-qt5.zip" | |
8 | 14 | |
9 | 15 | set SCRIPTDIR=%cd% |
10 | 16 | |
11 | 17 | rem Double-double quotes are needed in next line if the directory has a space |
12 | 18 | set RESULTDIR=""%SCRIPTDIR%\Engauge Digitizer"" |
13 | 19 | |
14 | mkdir "%RESULTDIR%" | |
20 | rem Next step removes stale files like engauge.log from the release | |
21 | if "%ARG1%" neq "norelease" ( | |
22 | if exist "%RESULTDIR%" del /Q /F "%RESULTDIR%" 2>nul | |
23 | ) | |
24 | if not exist "%RESULTDIR%" mkdir "%RESULTDIR%" | |
15 | 25 | |
16 | 26 | rem Directory containing engauge.pro |
17 | 27 | set APPVEYOR_BUILD_FOLDER="%SCRIPTDIR%\..\.." |
18 | 28 | |
29 | if not exist "%APPVEYOR_BUILD_FOLDER%" mkdir "%APPVEYOR_BUILD_FOLDER%" | |
30 | cd "%APPVEYOR_BUILD_FOLDER%" | |
31 | ||
32 | curl "%LOG4CPPDLLINK%" -o log4cpp_null.zip | |
33 | curl "%FFTWLINK%" -o fftw-3.3.4-dll32.zip | |
34 | curl "%POPPLERLINK%" -o poppler-qt5.zip | |
35 | ||
19 | 36 | rem Nominal Qt installation is QTDIR="C:\Qt\5.6\msvc2013" or QTDIR="C:\Qt\5.7\msvc2013" |
20 | 37 | set PATH=%QTDIR%\bin;%PATH% |
21 | 38 | |
22 | mkdir "%APPVEYOR_BUILD_FOLDER%" | |
23 | cd "%APPVEYOR_BUILD_FOLDER%" | |
24 | curl "%LOG4CPPDLLINK%" -o log4cpp-1.1.1.zip | |
25 | 7z x log4cpp-1.1.1.zip -aoa | |
26 | mkdir fftw-3.3.4-dll32 | |
39 | 7z x log4cpp_null.zip -aoa | |
40 | ||
41 | if not exist fftw-3.3.4-dll32 mkdir fftw-3.3.4-dll32 | |
27 | 42 | cd fftw-3.3.4-dll32 |
28 | curl 'ftp://ftp.fftw.org/pub/fftw/fftw-3.3.4-dll32.zip' -o fftw-3.3.4-dll32.zip | |
43 | ||
29 | 44 | 7z x fftw-3.3.4-dll32.zip -aoa |
30 | 45 | lib /def:libfftw3-3.def |
31 | 46 | lib /def:libfftw3f-3.def |
32 | 47 | lib /def:libfftw3l-3.def |
33 | mkdir include | |
34 | mkdir lib | |
48 | if not exist include mkdir include | |
49 | if not exist lib mkdir lib | |
35 | 50 | move fftw3.h include |
36 | 51 | move *dll lib |
37 | 52 | move *def lib |
38 | 53 | move *.lib lib |
39 | 54 | cd "%APPVEYOR_BUILD_FOLDER%" |
40 | curl 'https://dl.dropboxusercontent.com/u/1147076/poppler-qt5.zip' -o poppler-qt5.zip | |
55 | ||
41 | 56 | 7z x poppler-qt5.zip -aoa |
42 | 57 | |
43 | 58 | cd "%APPVEYOR_BUILD_FOLDER%" |
45 | 60 | set POPPLER_INCLUDE="%APPVEYOR_BUILD_FOLDER%\poppler-qt5\include\poppler\qt5" |
46 | 61 | set POPPLER_LIB="%APPVEYOR_BUILD_FOLDER%\poppler-qt5" |
47 | 62 | lrelease engauge.pro |
48 | qmake engauge.pro "CONFIG+=%ENGAUGE_CONFIG%" | |
63 | qmake engauge.pro "CONFIG+=%ENGAUGE_CONFIG%" "DEFINES+=WIN_RELEASE" | |
49 | 64 | rem move Makefile Makefile.orig |
50 | 65 | rem ps: gc Makefile.orig | %{ $_ -replace '551.lib', %QTLIBEXT% } > Makefile |
66 | if "%ARG1%" neq "norelease" ( | |
67 | nmake clean | |
68 | ) | |
51 | 69 | nmake |
52 | 70 | |
53 | 71 | cd "%APPVEYOR_BUILD_FOLDER%" |
54 | mkdir "%RESULTDIR%"\documentation | |
55 | for %%I in (%QTDIRS%) do mkdir "%RESULTDIR%\%%I" | |
72 | if not exist "%RESULTDIR%"\documentation mkdir "%RESULTDIR%"\documentation | |
73 | for %%I in (%QTDIRS%) do ( | |
74 | if not exist "%RESULTDIR%\%%I" mkdir "%RESULTDIR%\%%I" | |
75 | ) | |
56 | 76 | for %%I in (%QTDIRS%) do copy %QTDIR%\plugins\%%I\*.dll "%RESULTDIR%\%%I" |
57 | 77 | for %%I in (%QTLIBS%) do copy %QTDIR%\bin\%%I.dll "%RESULTDIR%" |
58 | 78 | del /S *d.dll |
59 | 79 | copy bin\engauge.exe "%RESULTDIR%" |
60 | 80 | |
61 | copy "%LOG4CPP_HOME%\lib\log4cpp.dll" "%RESULTDIR%" | |
81 | copy "%APPVEYOR_BUILD_FOLDER%\log4cpp_null\lib\log4cpp.dll" "%RESULTDIR%" | |
62 | 82 | |
63 | 83 | copy fftw-3.3.4-dll32\lib\libfftw3-3.dll "%RESULTDIR%" |
64 | 84 | copy "%APPVEYOR_BUILD_FOLDER%"\poppler-qt5\*.dll "%RESULTDIR%" |
68 | 88 | move engauge.qch "%RESULTDIR%"\documentation |
69 | 89 | move engauge.qhc "%RESULTDIR%"\documentation |
70 | 90 | cd .. |
71 | 7z a "%RESULTDIR%.7z" "%RESULTDIR%" | |
72 | 91 | |
73 | echo ***creating msi | |
74 | cd "%SCRIPTDIR%" | |
75 | findStr "char *VERSION_NUMBER" ..\..\src\util\Version.cpp | |
76 | findStr "Version=" engauge.wxs | findStr /v InstallerVersion | |
77 | set /p VERSION_NUMBER_CODE="If the version numbers are correct, enter the version number seen above to continue and build releases> " | |
92 | copy "%APPVEYOR_BUILD_FOLDER%"\translations "%RESULTDIR%" | |
78 | 93 | |
79 | candle engauge.wxs | |
80 | candle WixUI_InstallDir_NoLicense.wxs | |
81 | light.exe -ext WixUIExtension -ext WixUtilExtension engauge.wixobj WixUI_InstallDir_NoLicense.wixobj -o digit-exe-windows-32-bit-installer-%VERSION_NUMBER_CODE%.msi | |
94 | if "%ARG1%" neq "norelease" ( | |
95 | 7z a "%RESULTDIR%.7z" "%RESULTDIR%" | |
82 | 96 | |
83 | echo *** creating zip | |
84 | rem "Engauge Digitizer" in next line is needed since zip crashes on %RESULTDIR% due to the space | |
85 | zip -r "digit-exe-windows-32-bit-without-installer-file-%VERSION_NUMBER_CODE%.zip" "Engauge Digitizer" | |
97 | echo ***creating msi | |
98 | cd "%SCRIPTDIR%" | |
99 | findStr "char *VERSION_NUMBER" ..\..\src\util\Version.cpp | |
100 | findStr "Version=" engauge.wxs | findStr /v InstallerVersion | |
101 | set /p VERNUM="If the version numbers are correct, enter the version number seen above to continue and build releases>" | |
102 | echo "Version number will be %VERNUM%" | |
103 | ||
104 | candle engauge.wxs | |
105 | candle WixUI_InstallDir_NoLicense.wxs | |
106 | light.exe -ext WixUIExtension -ext WixUtilExtension engauge.wixobj WixUI_InstallDir_NoLicense.wixobj -o "digit-exe-windows-32-bit-installer-%VERNUM%.msi" | |
107 | ||
108 | echo *** creating zip | |
109 | rem "Engauge Digitizer" in next line is needed since zip crashes on %RESULTDIR% due to the space | |
110 | zip -r "digit-exe-windows-32-bit-without-installer-file-%VERNUM%.zip" "Engauge Digitizer" | |
111 | ) |
1 | 1 | <Wix xmlns='http://schemas.microsoft.com/wix/2006/wi'> |
2 | 2 | <Product Name='Engauge Digitizer' |
3 | 3 | Manufacturer='Engauge Open Source Developers' |
4 | Id='C111CD75-C12E-45D2-AD60-F0DD78831DC0' | |
4 | Id='1262BCFA-A719-4249-85CC-8C4085E08644' | |
5 | 5 | UpgradeCode='00A6792B-65ED-4894-A48B-B95D63C62CC6' |
6 | 6 | Language='1033' Codepage='1252' |
7 | Version='8.3'> | |
7 | Version='9.0'> | |
8 | 8 | <Package Id='*' Keywords='Installer' Description="Engauge Digitizer Installer" |
9 | 9 | Comments='Engauge Digitizer is available from github.com' Manufacturer='Engauge Open Source Developers' |
10 | 10 | InstallerVersion='100' Languages='1033' Compressed='yes' SummaryCodepage='1252' /> |
13 | 13 | # At some point, Qt may provide its own support for this format, at which point this can be skipped |
14 | 14 | # 3) Add 'pdf' to the qmake command line to include support for PDF input files. Requires |
15 | 15 | # 1) previous installation of the poppler-qt5 development package. Engauge has been tested with versions 0.24.5 and 0.44.0 |
16 | # 2) POPPLER_INCLUDE environment variable pointing to directory containing Document.h | |
16 | # 2) POPPLER_INCLUDE environment variable pointing to directory containing poppler-qt5.h | |
17 | 17 | # 3) POPPLER_LIB environment variable pointing to directory containing libpoppler-qt5.so |
18 | 18 | # Sample command lines: |
19 | 19 | # qmake CONFIG+=pdf |
85 | 85 | src/Cmd/CmdCut.h \ |
86 | 86 | src/Cmd/CmdDelete.h \ |
87 | 87 | src/Cmd/CmdEditPointAxis.h \ |
88 | src/Cmd/CmdEditPointGraph.h \ | |
88 | 89 | src/Cmd/CmdFactory.h \ |
89 | 90 | src/Cmd/CmdMediator.h \ |
90 | 91 | src/Cmd/CmdMoveBy.h \ |
158 | 159 | src/DigitizeState/DigitizeStateSegment.h \ |
159 | 160 | src/DigitizeState/DigitizeStateSelect.h \ |
160 | 161 | src/Dlg/DlgAbout.h \ |
161 | src/Dlg/DlgEditPoint.h \ | |
162 | src/Dlg/DlgEditPointAxis.h \ | |
163 | src/Dlg/DlgEditPointGraph.h \ | |
164 | src/Dlg/DlgEditPointGraphLineEdit.h \ | |
162 | 165 | src/Dlg/DlgErrorReport.h \ |
163 | 166 | src/Dlg/DlgFilterCommand.h \ |
164 | 167 | src/Dlg/DlgFilterThread.h \ |
165 | 168 | src/Dlg/DlgFilterWorker.h \ |
166 | 169 | src/Dlg/DlgImportAdvanced.h \ |
170 | src/Dlg/DlgImportCroppingNonPdf.h \ | |
167 | 171 | src/Dlg/DlgRequiresTransform.h \ |
168 | 172 | src/Dlg/DlgSettingsAbstractBase.h \ |
169 | 173 | src/Dlg/DlgSettingsAxesChecker.h \ |
240 | 244 | src/Format/FormatDegreesMinutesSecondsNonPolarTheta.h \ |
241 | 245 | src/Format/FormatDegreesMinutesSecondsPolarTheta.h \ |
242 | 246 | src/Callback/functor.h \ |
247 | src/Geometry/GeometryModel.h \ | |
248 | src/Geometry/GeometryStrategyAbstractBase.h \ | |
249 | src/Geometry/GeometryStrategyContext.h \ | |
250 | src/Geometry/GeometryStrategyFunctionSmooth.h \ | |
251 | src/Geometry/GeometryStrategyFunctionStraight.h \ | |
252 | src/Geometry/GeometryStrategyRelationSmooth.h \ | |
253 | src/Geometry/GeometryStrategyRelationStraight.h \ | |
254 | src/Geometry/GeometryWindow.h \ | |
243 | 255 | src/Ghosts/GhostEllipse.h \ |
244 | 256 | src/Ghosts/GhostPath.h \ |
245 | 257 | src/Ghosts/GhostPolygon.h \ |
246 | 258 | src/Ghosts/Ghosts.h \ |
247 | 259 | src/Graphics/GraphicsArcItem.h \ |
260 | src/Graphics/GraphicsItemsExtractor.h \ | |
248 | 261 | src/Graphics/GraphicsItemType.h \ |
249 | 262 | src/Graphics/GraphicsLinesForCurve.h \ |
250 | 263 | src/Graphics/GraphicsLinesForCurves.h \ |
261 | 274 | src/Grid/GridInitializer.h \ |
262 | 275 | src/Grid/GridLine.h \ |
263 | 276 | src/Grid/GridLineFactory.h \ |
277 | src/Grid/GridLineLimiter.h \ | |
264 | 278 | src/Grid/GridLines.h \ |
265 | 279 | src/Grid/GridLineStyle.h \ |
266 | 280 | src/Grid/GridRemoval.h \ |
267 | 281 | src/Help/HelpBrowser.h \ |
268 | 282 | src/Help/HelpWindow.h \ |
283 | src/Import/ImportCropping.h \ | |
284 | src/Import/ImportCroppingUtilBase.h \ | |
285 | src/Import/ImportCroppingUtilNonPdf.h \ | |
269 | 286 | src/Line/LineStyle.h \ |
270 | 287 | src/Load/LoadFileInfo.h \ |
271 | 288 | src/Load/LoadImageFromUrl.h \ |
278 | 295 | src/Mime/MimePoints.h \ |
279 | 296 | src/util/mmsubs.h \ |
280 | 297 | src/Network/NetworkClient.h \ |
298 | src/NonPdf/NonPdf.h \ | |
299 | src/NonPdf/NonPdfCropping.h \ | |
300 | src/NonPdf/NonPdfFrameHandle.h \ | |
281 | 301 | src/Ordinal/OrdinalGenerator.h \ |
282 | 302 | src/Ordinal/OrdinalToGraphicsPoint.h \ |
283 | 303 | src/Pdf/PdfResolution.h \ |
379 | 399 | src/Cmd/CmdCut.cpp \ |
380 | 400 | src/Cmd/CmdDelete.cpp \ |
381 | 401 | src/Cmd/CmdEditPointAxis.cpp \ |
402 | src/Cmd/CmdEditPointGraph.cpp \ | |
382 | 403 | src/Cmd/CmdFactory.cpp \ |
383 | 404 | src/Cmd/CmdMediator.cpp \ |
384 | 405 | src/Cmd/CmdMoveBy.cpp \ |
449 | 470 | src/DigitizeState/DigitizeStateSegment.cpp \ |
450 | 471 | src/DigitizeState/DigitizeStateSelect.cpp \ |
451 | 472 | src/Dlg/DlgAbout.cpp \ |
452 | src/Dlg/DlgEditPoint.cpp \ | |
473 | src/Dlg/DlgEditPointAxis.cpp \ | |
474 | src/Dlg/DlgEditPointGraph.cpp \ | |
475 | src/Dlg/DlgEditPointGraphLineEdit.cpp \ | |
453 | 476 | src/Dlg/DlgErrorReport.cpp \ |
454 | 477 | src/Dlg/DlgFilterCommand.cpp \ |
455 | 478 | src/Dlg/DlgFilterThread.cpp \ |
456 | 479 | src/Dlg/DlgFilterWorker.cpp \ |
457 | 480 | src/Dlg/DlgImportAdvanced.cpp \ |
481 | src/Dlg/DlgImportCroppingNonPdf.cpp \ | |
458 | 482 | src/Dlg/DlgRequiresTransform.cpp \ |
459 | 483 | src/Dlg/DlgSettingsAbstractBase.cpp \ |
460 | 484 | src/Dlg/DlgSettingsAxesChecker.cpp \ |
524 | 548 | src/Format/FormatDegreesMinutesSecondsBase.cpp \ |
525 | 549 | src/Format/FormatDegreesMinutesSecondsNonPolarTheta.cpp \ |
526 | 550 | src/Format/FormatDegreesMinutesSecondsPolarTheta.cpp \ |
551 | src/Geometry/GeometryModel.cpp \ | |
552 | src/Geometry/GeometryStrategyAbstractBase.cpp \ | |
553 | src/Geometry/GeometryStrategyContext.cpp \ | |
554 | src/Geometry/GeometryStrategyFunctionSmooth.cpp \ | |
555 | src/Geometry/GeometryStrategyFunctionStraight.cpp \ | |
556 | src/Geometry/GeometryStrategyRelationSmooth.cpp \ | |
557 | src/Geometry/GeometryStrategyRelationStraight.cpp \ | |
558 | src/Geometry/GeometryWindow.cpp \ | |
527 | 559 | src/Ghosts/GhostEllipse.cpp \ |
528 | 560 | src/Ghosts/GhostPath.cpp \ |
529 | 561 | src/Ghosts/GhostPolygon.cpp \ |
530 | 562 | src/Ghosts/Ghosts.cpp \ |
531 | 563 | src/Graphics/GraphicsArcItem.cpp \ |
564 | src/Graphics/GraphicsItemsExtractor.cpp \ | |
532 | 565 | src/Graphics/GraphicsLinesForCurve.cpp \ |
533 | 566 | src/Graphics/GraphicsLinesForCurves.cpp \ |
534 | 567 | src/Graphics/GraphicsPoint.cpp \ |
544 | 577 | src/Grid/GridInitializer.cpp \ |
545 | 578 | src/Grid/GridLine.cpp \ |
546 | 579 | src/Grid/GridLineFactory.cpp \ |
580 | src/Grid/GridLineLimiter.cpp \ | |
547 | 581 | src/Grid/GridLines.cpp \ |
548 | 582 | src/Grid/GridRemoval.cpp \ |
549 | 583 | src/Help/HelpBrowser.cpp \ |
550 | 584 | src/Help/HelpWindow.cpp \ |
585 | src/Import/ImportCroppingUtilBase.cpp \ | |
586 | src/Import/ImportCroppingUtilNonPdf.cpp \ | |
551 | 587 | src/Line/LineStyle.cpp \ |
552 | 588 | src/Load/LoadFileInfo.cpp \ |
553 | 589 | src/Load/LoadImageFromUrl.cpp \ |
560 | 596 | src/Mime/MimePoints.cpp \ |
561 | 597 | src/util/mmsubs.cpp \ |
562 | 598 | src/Network/NetworkClient.cpp \ |
599 | src/NonPdf/NonPdf.cpp \ | |
600 | src/NonPdf/NonPdfCropping.cpp \ | |
601 | src/NonPdf/NonPdfFrameHandle.cpp \ | |
563 | 602 | src/Ordinal/OrdinalGenerator.cpp \ |
564 | 603 | src/Pdf/PdfResolution.cpp \ |
565 | 604 | src/Point/Point.cpp \ |
676 | 715 | src/FileCmd \ |
677 | 716 | src/Filter \ |
678 | 717 | src/Format \ |
718 | src/Geometry \ | |
679 | 719 | src/Ghosts \ |
680 | 720 | src/Graphics \ |
681 | 721 | src/Grid \ |
682 | 722 | src/Help \ |
683 | 723 | src/img \ |
724 | src/Import \ | |
684 | 725 | src/include \ |
685 | 726 | src/Line \ |
686 | 727 | src/Load \ |
688 | 729 | src/main \ |
689 | 730 | src/Mime \ |
690 | 731 | src/Network \ |
732 | src/NonPdf \ | |
691 | 733 | src/Ordinal \ |
692 | 734 | src/Pdf \ |
693 | 735 | src/Plot \ |
761 | 803 | DEFINES += "ENGAUGE_PDF" |
762 | 804 | LIBS += -L$$(POPPLER_LIB) -lpoppler-qt5 |
763 | 805 | INCLUDEPATH += $$(POPPLER_INCLUDE) |
764 | HEADERS += src/Dlg/DlgPdfFrame.h \ | |
806 | HEADERS += src/Dlg/DlgImportCroppingPdf.h \ | |
807 | src/Import/ImportCroppingUtilPdf.h \ | |
765 | 808 | src/Pdf/Pdf.h \ |
766 | src/Pdf/PdfFrame.h \ | |
809 | src/Pdf/PdfCropping.h \ | |
767 | 810 | src/Pdf/PdfFrameHandle.h |
768 | SOURCES += src/Dlg/DlgPdfFrame.cpp \ | |
811 | SOURCES += src/Dlg/DlgImportCroppingPdf.cpp \ | |
812 | src/Import/ImportCroppingUtilPdf.cpp \ | |
769 | 813 | src/Pdf/Pdf.cpp \ |
770 | src/Pdf/PdfFrame.cpp \ | |
814 | src/Pdf/PdfCropping.cpp \ | |
771 | 815 | src/Pdf/PdfFrameHandle.cpp |
772 | 816 | |
773 | 817 | } else { |
0 | engauge.qch⏎ |
0 | <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> | |
1 | <HTML> | |
2 | <HEAD> | |
3 | <TITLE>Engauge Digitizer - Discretizing</TITLE> | |
4 | <META NAME="keywords" CONTENT="Engauge Digitizer, browser based documentation, online manual, selection, issue, problem"> | |
5 | <META NAME="description" CONTENT="Selecting Points"> | |
6 | </HEAD> | |
7 | <BODY> | |
8 | <H2> | |
9 | <A HREF="index.html"> | |
10 | <IMG SRC="animation.png" ALIGN=MIDDLE ALT="" STYLE="border: 0px"></A> | |
11 | Engauge Digitizer - Selecting Points</H2> | |
12 | <HR WIDTH="100%"> | |
13 | <H2>Selecting one or more points</H2> | |
14 | <P>To select one or more axis or graph points using the Select Tool, either one of the following options can be used:</P> | |
15 | <OL> | |
16 | <LI>Option 1 - Left click on one axis or curve point, and then release the mouse button</LI> | |
17 | <LI>Option 2- Left click and then drag to select all curve points within the rectangular box, and then release the mouse button</LI> | |
18 | </OL> | |
19 | <P>If successful, the result should be one or more selected points. Each selected point will have a dashed square | |
20 | around it.</P> | |
21 | <H2>Editing one or more points</H2> | |
22 | <P>To edit one or more axis or graph points, the following steps are required:</P> | |
23 | <OL> | |
24 | <LI>Step 1 - Select the desired point(s) using the Select Tool (see above)</LI> | |
25 | <LI>Step 2 - Right click on one of the selected points</LI> | |
26 | </OL> | |
27 | <P>Note:</P> | |
28 | <UL> | |
29 | <LI>Axis and graph points cannot be edited at the same time, and must be edited separately.</LI> | |
30 | <LI>Right clicking on an unselected point will have no effect</LI> | |
31 | <LI>Double clicking on any point will have no effect</LI> | |
32 | </BODY> | |
33 | </HTML> |
27 | 27 | </section> |
28 | 28 | <section title="Answers for users who are having problems"> |
29 | 29 | <section title="What happened to my image?" ref="answerdiscretizing.html"></section> |
30 | <section title="Why am I unable to select or edit a point?" ref="answerselecting.html"></section> | |
30 | 31 | <section title="The coordinates are wrong, how do I fix them?" ref="fixingaxispoints.html"></section> |
31 | 32 | </section> |
32 | 33 | </toc> |
42 | 43 | <keyword name="Multiple coordinate systems" ref="answermultiplecoordsystems.html"/> |
43 | 44 | <keyword name="Point graph" ref="answerpointgraph.html"/> |
44 | 45 | <keyword name="Select mode" ref="answerselectmode.html"/> |
46 | <keyword name="Selecting" ref="answerselecting.html"/> | |
45 | 47 | </keywords> |
46 | 48 | <files> |
47 | 49 | <file>animation.png</file> |
53 | 55 | <file>answerother.html</file> |
54 | 56 | <file>answerout.html</file> |
55 | 57 | <file>answerpointgraph.html</file> |
58 | <file>answerselecting.html</file> | |
56 | 59 | <file>answerselectmode.html</file> |
57 | 60 | <file>betteraccuracy.html</file> |
58 | 61 | <file>commandlineoptions.html</file> |
Binary diff not shown
119 | 119 | if (anyPointsRepeatPair (m_screenInputs)) { |
120 | 120 | |
121 | 121 | m_isError = true; |
122 | m_errorMessage = QObject::tr ("New axis point cannot be at the same screen position as an exisiting axis point"); | |
122 | m_errorMessage = QObject::tr ("New axis point cannot be at the same screen position as an existing axis point"); | |
123 | 123 | rtn = CALLBACK_SEARCH_RETURN_INTERRUPT; |
124 | 124 | |
125 | 125 | } else if (anyPointsRepeatPair (m_graphOutputs)) { |
213 | 213 | anyPointsRepeatPair (m_screenInputsY)) { |
214 | 214 | |
215 | 215 | m_isError = true; |
216 | m_errorMessage = QObject::tr ("New axis point cannot be at the same screen position as an exisiting axis point"); | |
216 | m_errorMessage = QObject::tr ("New axis point cannot be at the same screen position as an existing axis point"); | |
217 | 217 | rtn = CALLBACK_SEARCH_RETURN_INTERRUPT; |
218 | 218 | |
219 | 219 | } else if (anyPointsRepeatSingle (m_graphOutputsX) || |
7 | 7 | #include "DataKey.h" |
8 | 8 | #include "Document.h" |
9 | 9 | #include "EngaugeAssert.h" |
10 | #include "GeometryWindow.h" | |
10 | 11 | #include "GraphicsLinesForCurves.h" |
11 | 12 | #include "GraphicsScene.h" |
12 | 13 | #include "Point.h" |
14 | 15 | |
15 | 16 | CallbackSceneUpdateAfterCommand::CallbackSceneUpdateAfterCommand(GraphicsLinesForCurves &graphicsLinesForCurves, |
16 | 17 | GraphicsScene &scene, |
17 | const Document &document) : | |
18 | const Document &document, | |
19 | GeometryWindow *geometryWindow) : | |
18 | 20 | m_graphicsLinesForCurves (graphicsLinesForCurves), |
19 | 21 | m_scene (scene), |
20 | m_document (document) | |
22 | m_document (document), | |
23 | m_geometryWindow (geometryWindow) | |
21 | 24 | { |
22 | 25 | } |
23 | 26 | |
29 | 32 | m_graphicsLinesForCurves.updateAfterCommand (m_scene, |
30 | 33 | m_document.modelCurveStyles (), |
31 | 34 | curveName, |
32 | point); | |
35 | point, | |
36 | m_geometryWindow); | |
33 | 37 | |
34 | 38 | return rtn; |
35 | 39 | } |
10 | 10 | #include "PointStyle.h" |
11 | 11 | |
12 | 12 | class Document; |
13 | class GeometryWindow; | |
13 | 14 | class GraphicsLinesForCurves; |
14 | 15 | class GraphicsScene; |
15 | 16 | class Point; |
21 | 22 | /// Single constructor. |
22 | 23 | CallbackSceneUpdateAfterCommand(GraphicsLinesForCurves &graphicsLinesForCurves, |
23 | 24 | GraphicsScene &scene, |
24 | const Document &document); | |
25 | const Document &document, | |
26 | GeometryWindow *geometryWindow); | |
25 | 27 | |
26 | 28 | /// Callback method. |
27 | 29 | CallbackSearchReturn callback (const QString & /* curveName */, |
33 | 35 | GraphicsLinesForCurves &m_graphicsLinesForCurves; |
34 | 36 | GraphicsScene &m_scene; |
35 | 37 | const Document &m_document; |
38 | GeometryWindow *m_geometryWindow; | |
36 | 39 | }; |
37 | 40 | |
38 | 41 | #endif // CALLBACK_SCENE_UPDATE_AFTER_COMMAND_H |
226 | 226 | GridLineFactory factory (m_scene, |
227 | 227 | pointRadius, |
228 | 228 | points, |
229 | modelCoords, | |
230 | transformation); | |
231 | m_gridLines.add (factory.createGridLine (xFrom, yFrom, xFrom, yTo )); | |
232 | m_gridLines.add (factory.createGridLine (xFrom, yTo , xTo , yTo )); | |
233 | m_gridLines.add (factory.createGridLine (xTo , yTo , xTo , yFrom)); | |
234 | m_gridLines.add (factory.createGridLine (xTo , yFrom, xFrom, yFrom)); | |
229 | modelCoords); | |
230 | m_gridLines.add (factory.createGridLine (xFrom, yFrom, xFrom, yTo , transformation)); | |
231 | m_gridLines.add (factory.createGridLine (xFrom, yTo , xTo , yTo , transformation)); | |
232 | m_gridLines.add (factory.createGridLine (xTo , yTo , xTo , yFrom, transformation)); | |
233 | m_gridLines.add (factory.createGridLine (xTo , yFrom, xFrom, yFrom, transformation)); | |
235 | 234 | |
236 | 235 | updateModelAxesChecker (modelAxesChecker); |
237 | 236 | } |
8 | 8 | |
9 | 9 | #include "CmdPointChangeBase.h" |
10 | 10 | #include <QPointF> |
11 | #include <QString> | |
11 | 12 | |
12 | 13 | class QXmlStreamReader; |
13 | 14 |
0 | /****************************************************************************************************** | |
1 | * (C) 2016 markummitchell@github.com. This file is part of Engauge Digitizer, which is released * | |
2 | * under GNU General Public License version 2 (GPLv2) or (at your option) any later version. See file * | |
3 | * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. * | |
4 | ******************************************************************************************************/ | |
5 | ||
6 | #include "CmdEditPointGraph.h" | |
7 | #include "Document.h" | |
8 | #include "DocumentSerialize.h" | |
9 | #include "EngaugeAssert.h" | |
10 | #include "Logger.h" | |
11 | #include "MainWindow.h" | |
12 | #include <QTextStream> | |
13 | #include "QtToString.h" | |
14 | #include <QXmlStreamReader> | |
15 | #include "Xml.h" | |
16 | ||
17 | const QString CMD_DESCRIPTION ("Edit curve points"); | |
18 | ||
19 | CmdEditPointGraph::CmdEditPointGraph (MainWindow &mainWindow, | |
20 | Document &document, | |
21 | const QStringList &pointIdentifiers, | |
22 | bool isX, | |
23 | bool isY, | |
24 | double x, | |
25 | double y) : | |
26 | CmdPointChangeBase (mainWindow, | |
27 | document, | |
28 | CMD_DESCRIPTION), | |
29 | m_pointIdentifiers (pointIdentifiers), | |
30 | m_isX (isX), | |
31 | m_isY (isY), | |
32 | m_x (x), | |
33 | m_y (y) | |
34 | { | |
35 | LOG4CPP_INFO_S ((*mainCat)) << "CmdEditPointGraph::CmdEditPointGraph point=" | |
36 | << pointIdentifiers.join(" ").toLatin1 ().data () | |
37 | << " x=" << (m_isX ? QString::number (x).toLatin1().data() : "") | |
38 | << " y=" << (m_isY ? QString::number (y).toLatin1().data() : ""); | |
39 | } | |
40 | ||
41 | CmdEditPointGraph::CmdEditPointGraph (MainWindow &mainWindow, | |
42 | Document &document, | |
43 | const QString &cmdDescription, | |
44 | QXmlStreamReader &reader) : | |
45 | CmdPointChangeBase (mainWindow, | |
46 | document, | |
47 | cmdDescription) | |
48 | { | |
49 | LOG4CPP_INFO_S ((*mainCat)) << "CmdEditPointGraph::CmdEditPointGraph"; | |
50 | ||
51 | QXmlStreamAttributes attributes = reader.attributes(); | |
52 | ||
53 | if (!attributes.hasAttribute(DOCUMENT_SERIALIZE_EDIT_GRAPH_IS_X) || | |
54 | !attributes.hasAttribute(DOCUMENT_SERIALIZE_EDIT_GRAPH_IS_Y) || | |
55 | !attributes.hasAttribute(DOCUMENT_SERIALIZE_EDIT_GRAPH_X) || | |
56 | !attributes.hasAttribute(DOCUMENT_SERIALIZE_EDIT_GRAPH_Y) ) { | |
57 | xmlExitWithError (reader, | |
58 | QString ("%1 %2, %3, %4 %5 %6") | |
59 | .arg (QObject::tr ("Missing attribute(s)")) | |
60 | .arg (DOCUMENT_SERIALIZE_EDIT_GRAPH_IS_X) | |
61 | .arg (DOCUMENT_SERIALIZE_EDIT_GRAPH_IS_Y) | |
62 | .arg (DOCUMENT_SERIALIZE_EDIT_GRAPH_X) | |
63 | .arg (QObject::tr ("and/or")) | |
64 | .arg (DOCUMENT_SERIALIZE_EDIT_GRAPH_Y)); | |
65 | } else { | |
66 | ||
67 | // Boolean attributes | |
68 | QString isX = attributes.value(DOCUMENT_SERIALIZE_EDIT_GRAPH_IS_X).toString(); | |
69 | QString isY = attributes.value(DOCUMENT_SERIALIZE_EDIT_GRAPH_IS_Y).toString(); | |
70 | ||
71 | m_isX = (isX == DOCUMENT_SERIALIZE_BOOL_TRUE); | |
72 | m_isY = (isY == DOCUMENT_SERIALIZE_BOOL_TRUE); | |
73 | m_x = attributes.value(DOCUMENT_SERIALIZE_EDIT_GRAPH_X).toDouble(); | |
74 | m_y = attributes.value(DOCUMENT_SERIALIZE_EDIT_GRAPH_Y).toDouble(); | |
75 | ||
76 | bool success = true; | |
77 | while (loadNextFromReader (reader)) { | |
78 | ||
79 | if (reader.atEnd() || reader.hasError ()) { | |
80 | success = false; | |
81 | break; | |
82 | } | |
83 | ||
84 | if ((reader.tokenType() == QXmlStreamReader::EndElement) & | |
85 | (reader.name() == DOCUMENT_SERIALIZE_CMD)) { | |
86 | break; | |
87 | } | |
88 | ||
89 | // Not done yet | |
90 | if ((reader.tokenType() == QXmlStreamReader::StartElement) && | |
91 | (reader.name() == DOCUMENT_SERIALIZE_POINT)) { | |
92 | ||
93 | // This is an entry that we need to add | |
94 | QXmlStreamAttributes attributes = reader.attributes (); | |
95 | ||
96 | if (attributes.hasAttribute(DOCUMENT_SERIALIZE_IDENTIFIER)) { | |
97 | ||
98 | m_pointIdentifiers << attributes.value(DOCUMENT_SERIALIZE_IDENTIFIER).toString(); | |
99 | } | |
100 | } | |
101 | } | |
102 | ||
103 | if (!success) { | |
104 | reader.raiseError (QObject::tr ("Cannot read graph points")); | |
105 | } | |
106 | } | |
107 | } | |
108 | ||
109 | CmdEditPointGraph::~CmdEditPointGraph () | |
110 | { | |
111 | } | |
112 | ||
113 | void CmdEditPointGraph::cmdRedo () | |
114 | { | |
115 | LOG4CPP_INFO_S ((*mainCat)) << "CmdEditPointGraph::cmdRedo"; | |
116 | ||
117 | saveOrCheckPreCommandDocumentStateHash (document ()); | |
118 | saveDocumentState (document ()); | |
119 | document().editPointGraph (m_isX, | |
120 | m_isY, | |
121 | m_x, | |
122 | m_y, | |
123 | m_pointIdentifiers, | |
124 | mainWindow().transformation()); | |
125 | document().updatePointOrdinals (mainWindow().transformation()); | |
126 | mainWindow().updateAfterCommand(); | |
127 | saveOrCheckPostCommandDocumentStateHash (document ()); | |
128 | } | |
129 | ||
130 | void CmdEditPointGraph::cmdUndo () | |
131 | { | |
132 | LOG4CPP_INFO_S ((*mainCat)) << "CmdEditPointGraph::cmdUndo"; | |
133 | ||
134 | saveOrCheckPostCommandDocumentStateHash (document ()); | |
135 | restoreDocumentState (document ()); | |
136 | mainWindow().updateAfterCommand(); | |
137 | saveOrCheckPreCommandDocumentStateHash (document ()); | |
138 | } | |
139 | ||
140 | void CmdEditPointGraph::saveXml (QXmlStreamWriter &writer) const | |
141 | { | |
142 | writer.writeStartElement(DOCUMENT_SERIALIZE_CMD); | |
143 | writer.writeAttribute(DOCUMENT_SERIALIZE_CMD_TYPE, DOCUMENT_SERIALIZE_CMD_EDIT_POINT_GRAPH); | |
144 | writer.writeAttribute(DOCUMENT_SERIALIZE_CMD_DESCRIPTION, QUndoCommand::text ()); | |
145 | writer.writeAttribute(DOCUMENT_SERIALIZE_EDIT_GRAPH_IS_X, m_isX ? | |
146 | DOCUMENT_SERIALIZE_BOOL_TRUE : | |
147 | DOCUMENT_SERIALIZE_BOOL_FALSE); | |
148 | writer.writeAttribute(DOCUMENT_SERIALIZE_EDIT_GRAPH_IS_Y, m_isY ? | |
149 | DOCUMENT_SERIALIZE_BOOL_TRUE : | |
150 | DOCUMENT_SERIALIZE_BOOL_FALSE); | |
151 | writer.writeAttribute(DOCUMENT_SERIALIZE_EDIT_GRAPH_X, QString::number (m_x)); | |
152 | writer.writeAttribute(DOCUMENT_SERIALIZE_EDIT_GRAPH_Y, QString::number (m_y)); | |
153 | ||
154 | for (int index = 0; index < m_pointIdentifiers.count(); index++) { | |
155 | ||
156 | writer.writeStartElement (DOCUMENT_SERIALIZE_POINT); | |
157 | writer.writeAttribute(DOCUMENT_SERIALIZE_IDENTIFIER, m_pointIdentifiers.at (index)); | |
158 | writer.writeEndElement(); | |
159 | } | |
160 | writer.writeEndElement(); | |
161 | } |
0 | /****************************************************************************************************** | |
1 | * (C) 2016 markummitchell@github.com. This file is part of Engauge Digitizer, which is released * | |
2 | * under GNU General Public License version 2 (GPLv2) or (at your option) any later version. See file * | |
3 | * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. * | |
4 | ******************************************************************************************************/ | |
5 | ||
6 | #ifndef CMD_EDIT_POINT_GRAPH_H | |
7 | #define CMD_EDIT_POINT_GRAPH_H | |
8 | ||
9 | #include "CmdPointChangeBase.h" | |
10 | #include <QPointF> | |
11 | #include <QStringList> | |
12 | ||
13 | class QXmlStreamReader; | |
14 | ||
15 | /// Command for editing the graph coordinates of one or more graph points. The screen coordinates are | |
16 | /// handled by another command | |
17 | class CmdEditPointGraph : public CmdPointChangeBase | |
18 | { | |
19 | public: | |
20 | /// Constructor for normal creation | |
21 | CmdEditPointGraph(MainWindow &mainWindow, | |
22 | Document &document, | |
23 | const QStringList &pointIdentifiers, | |
24 | bool isX, | |
25 | bool isY, | |
26 | double x, | |
27 | double y); | |
28 | ||
29 | /// Constructor for parsing error report file xml | |
30 | CmdEditPointGraph(MainWindow &mainWindow, | |
31 | Document &document, | |
32 | const QString &cmdDescription, | |
33 | QXmlStreamReader &reader); | |
34 | ||
35 | virtual ~CmdEditPointGraph(); | |
36 | ||
37 | virtual void cmdRedo (); | |
38 | virtual void cmdUndo (); | |
39 | virtual void saveXml (QXmlStreamWriter &writer) const; | |
40 | ||
41 | private: | |
42 | CmdEditPointGraph(); | |
43 | ||
44 | QStringList m_pointIdentifiers; | |
45 | bool m_isX; | |
46 | bool m_isY; | |
47 | double m_x; | |
48 | double m_y; | |
49 | }; | |
50 | ||
51 | #endif // CMD_EDIT_POINT_GRAPH_H |
11 | 11 | #include "CmdCut.h" |
12 | 12 | #include "CmdDelete.h" |
13 | 13 | #include "CmdEditPointAxis.h" |
14 | #include "CmdEditPointGraph.h" | |
14 | 15 | #include "CmdFactory.h" |
15 | 16 | #include "CmdMoveBy.h" |
16 | 17 | #include "CmdPaste.h" |
91 | 92 | document, |
92 | 93 | cmdDescription, |
93 | 94 | reader); |
95 | } else if (cmdType == DOCUMENT_SERIALIZE_CMD_EDIT_POINT_GRAPH) { | |
96 | cmd = new CmdEditPointGraph (mainWindow, | |
97 | document, | |
98 | cmdDescription, | |
99 | reader); | |
94 | 100 | } else if (cmdType == DOCUMENT_SERIALIZE_CMD_MOVE_BY) { |
95 | 101 | cmd = new CmdMoveBy (mainWindow, |
96 | 102 | document, |
173 | 173 | { |
174 | 174 | if (m_strategies.contains (colorFilterMode)) { |
175 | 175 | |
176 | return m_strategies [colorFilterMode]->pixelToZeroToOne (pixel, | |
177 | rgbBackground); | |
176 | // Ignore false positive cmake compiler warning about -Wreturn-stack-address in next line (bug #26396) | |
177 | const ColorFilterStrategyAbstractBase *strategy = m_strategies [colorFilterMode]; | |
178 | return strategy->pixelToZeroToOne (pixel, | |
179 | rgbBackground); | |
178 | 180 | |
179 | 181 | } else { |
180 | 182 | |
189 | 191 | { |
190 | 192 | if (m_strategies.contains (colorFilterMode)) { |
191 | 193 | |
192 | return m_strategies [colorFilterMode]->zeroToOneToValue (s); | |
194 | const ColorFilterStrategyAbstractBase *strategy = m_strategies [colorFilterMode]; | |
195 | return strategy->zeroToOneToValue (s); | |
193 | 196 | |
194 | 197 | } else { |
195 | 198 |
135 | 135 | double ColorFilterSettings::high () const |
136 | 136 | { |
137 | 137 | if (m_strategies.contains (m_colorFilterMode)) { |
138 | return m_strategies [m_colorFilterMode]->high (*this); | |
138 | ||
139 | // Ignore false positive cmake compiler warning about -Wreturn-stack-address in next line (bug #26396) | |
140 | const ColorFilterSettingsStrategyAbstractBase *strategy = m_strategies.value (m_colorFilterMode); | |
141 | return strategy->high (*this); | |
139 | 142 | } else { |
140 | 143 | ENGAUGE_ASSERT (false); |
141 | 144 | return m_strategies [COLOR_FILTER_MODE_INTENSITY]->high (*this); |
214 | 217 | double ColorFilterSettings::low () const |
215 | 218 | { |
216 | 219 | if (m_strategies.contains (m_colorFilterMode)) { |
217 | return m_strategies [m_colorFilterMode]->low (*this); | |
220 | const ColorFilterSettingsStrategyAbstractBase *strategy = m_strategies.value (m_colorFilterMode); | |
221 | return strategy->low (*this); | |
218 | 222 | } else { |
219 | 223 | ENGAUGE_ASSERT (false); |
220 | 224 | return m_strategies [COLOR_FILTER_MODE_INTENSITY]->low (*this); |
229 | 233 | indentation += INDENTATION_DELTA; |
230 | 234 | |
231 | 235 | if (m_strategies.contains (m_colorFilterMode)) { |
232 | return m_strategies [m_colorFilterMode]->printStream (*this, | |
233 | indentation, | |
234 | str); | |
236 | const ColorFilterSettingsStrategyAbstractBase *strategy = m_strategies.value (m_colorFilterMode); | |
237 | return strategy->printStream (*this, | |
238 | indentation, | |
239 | str); | |
235 | 240 | } |
236 | 241 | } |
237 | 242 | |
287 | 292 | void ColorFilterSettings::setHigh (double s0To1) |
288 | 293 | { |
289 | 294 | if (m_strategies.contains (m_colorFilterMode)) { |
290 | return m_strategies [m_colorFilterMode]->setHigh (*this, | |
291 | s0To1); | |
295 | ColorFilterSettingsStrategyAbstractBase *strategy = m_strategies [m_colorFilterMode]; | |
296 | return strategy->setHigh (*this, | |
297 | s0To1); | |
292 | 298 | } else { |
293 | 299 | ENGAUGE_ASSERT (false); |
294 | 300 | } |
321 | 327 | void ColorFilterSettings::setLow (double s0To1) |
322 | 328 | { |
323 | 329 | if (m_strategies.contains (m_colorFilterMode)) { |
324 | return m_strategies [m_colorFilterMode]->setLow (*this, | |
325 | s0To1); | |
330 | ColorFilterSettingsStrategyAbstractBase *strategy = m_strategies [m_colorFilterMode]; | |
331 | return strategy->setLow (*this, | |
332 | s0To1); | |
326 | 333 | } else { |
327 | 334 | ENGAUGE_ASSERT (false); |
328 | 335 | } |
264 | 264 | void CoordSystem::editPointAxis (const QPointF &posGraph, |
265 | 265 | const QString &identifier) |
266 | 266 | { |
267 | LOG4CPP_INFO_S ((*mainCat)) << "CoordSystem::editPointAxis posGraph=(" | |
268 | << posGraph.x () << ", " << posGraph.y () << ") identifier=" | |
269 | << identifier.toLatin1 ().data (); | |
270 | ||
271 | m_curveAxes->editPoint (posGraph, | |
272 | identifier); | |
267 | LOG4CPP_INFO_S ((*mainCat)) << "CoordSystem::editPointAxis" | |
268 | << " posGraph=(" << posGraph.x () << ", " << posGraph.y () << ") identifier=" | |
269 | << " identifier=" << identifier.toLatin1 ().data (); | |
270 | ||
271 | m_curveAxes->editPointAxis (posGraph, | |
272 | identifier); | |
273 | } | |
274 | ||
275 | void CoordSystem::editPointGraph (bool isX, | |
276 | bool isY, | |
277 | double x, | |
278 | double y, | |
279 | const QStringList &identifiers, | |
280 | const Transformation &transformation) | |
281 | { | |
282 | LOG4CPP_INFO_S ((*mainCat)) << "CoordSystem::editPointGraph posGraph=(" | |
283 | << " x=" << (isX ? QString::number (x).toLatin1().data() : "") | |
284 | << " y=" << (isY ? QString::number (y).toLatin1().data() : "") | |
285 | << ") identifiers=" << identifiers.join(" ").toLatin1 ().data (); | |
286 | ||
287 | m_curvesGraphs.editPointGraph (isX, | |
288 | isY, | |
289 | x, | |
290 | y, | |
291 | identifiers, | |
292 | transformation); | |
273 | 293 | } |
274 | 294 | |
275 | 295 | bool CoordSystem::isXOnly (const QString &pointIdentifier) const |
24 | 24 | #include <QList> |
25 | 25 | #include <QPixmap> |
26 | 26 | #include <QString> |
27 | #include <QStringList> | |
27 | 28 | #include <QXmlStreamReader> |
28 | 29 | |
29 | 30 | class Curve; |
84 | 85 | virtual int curvesGraphsNumPoints (const QString &curveName) const; |
85 | 86 | virtual void editPointAxis (const QPointF &posGraph, |
86 | 87 | const QString &identifier); |
88 | virtual void editPointGraph (bool isX, | |
89 | bool isY, | |
90 | double x, | |
91 | double y, | |
92 | const QStringList &identifiers, | |
93 | const Transformation &transformation); | |
87 | 94 | |
88 | 95 | /// Return true if y coordinate is undefined, otherwise x coordinae is undefined in DOCUMENT_AXES_POINT_REQUIRE_4 mode. |
89 | 96 | /// Applies to axes points only |
208 | 208 | identifier); |
209 | 209 | } |
210 | 210 | |
211 | void CoordSystemContext::editPointGraph (bool isX, | |
212 | bool isY, | |
213 | double x, | |
214 | double y, | |
215 | const QStringList &identifiers, | |
216 | const Transformation &transformation) | |
217 | { | |
218 | LOG4CPP_INFO_S ((*mainCat)) << "CoordSystemContext::editPointGraph"; | |
219 | ||
220 | m_coordSystems [m_coordSystemIndex]->editPointGraph (isX, | |
221 | isY, | |
222 | x, | |
223 | y, | |
224 | identifiers, | |
225 | transformation); | |
226 | } | |
227 | ||
211 | 228 | bool CoordSystemContext::isXOnly (const QString &pointIdentifier) const |
212 | 229 | { |
213 | 230 | LOG4CPP_INFO_S ((*mainCat)) << "CoordSystemContext::isXOnly"; |
80 | 80 | virtual int curvesGraphsNumPoints (const QString &curveName) const; |
81 | 81 | virtual void editPointAxis (const QPointF &posGraph, |
82 | 82 | const QString &identifier); |
83 | virtual void editPointGraph (bool isX, | |
84 | bool isY, | |
85 | double x, | |
86 | double y, | |
87 | const QStringList &identifiers, | |
88 | const Transformation &transformation); | |
83 | 89 | |
84 | 90 | /// True/false if y/x value is empty |
85 | 91 | bool isXOnly (const QString &pointIdentifier) const; |
114 | 114 | virtual void editPointAxis (const QPointF &posGraph, |
115 | 115 | const QString &identifier) = 0; |
116 | 116 | |
117 | /// Edit the graph coordinates of one or more graph points | |
118 | virtual void editPointGraph (bool isX, | |
119 | bool isY, | |
120 | double x, | |
121 | double y, | |
122 | const QStringList &identifiers, | |
123 | const Transformation &transformation) = 0; | |
124 | ||
117 | 125 | /// See Curve::iterateThroughCurvePoints, for the axes curve. |
118 | 126 | virtual void iterateThroughCurvePointsAxes (const Functor2wRet<const QString &, const Point &, CallbackSearchReturn> &ftorWithCallback) = 0; |
119 | 127 |
140 | 140 | return m_curveStyle; |
141 | 141 | } |
142 | 142 | |
143 | void Curve::editPoint (const QPointF &posGraph, | |
144 | const QString &identifier) | |
143 | void Curve::editPointAxis (const QPointF &posGraph, | |
144 | const QString &identifier) | |
145 | 145 | { |
146 | 146 | // Search for the point with matching identifier |
147 | 147 | QList<Point>::iterator itr; |
153 | 153 | point.setPosGraph (posGraph); |
154 | 154 | break; |
155 | 155 | |
156 | } | |
157 | } | |
158 | } | |
159 | ||
160 | void Curve::editPointGraph (bool isX, | |
161 | bool isY, | |
162 | double x, | |
163 | double y, | |
164 | const QStringList &identifiers, | |
165 | const Transformation &transformation) | |
166 | { | |
167 | LOG4CPP_INFO_S ((*mainCat)) << "Curve::editPointGraph" | |
168 | << " identifiers=" << identifiers.join(" ").toLatin1().data(); | |
169 | ||
170 | if (transformation.transformIsDefined()) { | |
171 | ||
172 | // Search for the point with matching identifier | |
173 | QList<Point>::iterator itr; | |
174 | for (itr = m_points.begin(); itr != m_points.end(); itr++) { | |
175 | ||
176 | Point &point = *itr; | |
177 | ||
178 | if (identifiers.contains (point.identifier ())) { | |
179 | ||
180 | // Although one or more graph coordinates are specified, it is the screen coordinates that must be | |
181 | // moved. This is because only the screen coordinates of the graph points are tracked (not the graph coordinates). | |
182 | // So we compute posScreen and call Point::setPosScreen instead of Point::setPosGraph | |
183 | ||
184 | // Get original graph coordinates | |
185 | QPointF posScreen = point.posScreen (); | |
186 | QPointF posGraph; | |
187 | transformation.transformScreenToRawGraph (posScreen, | |
188 | posGraph); | |
189 | ||
190 | // Override one or both coordinates | |
191 | if (isX) { | |
192 | posGraph.setX (x); | |
193 | } | |
194 | ||
195 | if (isY) { | |
196 | posGraph.setY (y); | |
197 | } | |
198 | ||
199 | // Set the screen coordinates | |
200 | transformation.transformRawGraphToScreen(posGraph, | |
201 | posScreen); | |
202 | ||
203 | point.setPosScreen (posScreen); | |
204 | } | |
156 | 205 | } |
157 | 206 | } |
158 | 207 | } |
61 | 61 | CurveStyle curveStyle() const; |
62 | 62 | |
63 | 63 | /// Edit the graph coordinates of an axis point. This method does not apply to a graph point |
64 | void editPoint (const QPointF &posGraph, | |
65 | const QString &identifier); | |
64 | void editPointAxis (const QPointF &posGraph, | |
65 | const QString &identifier); | |
66 | ||
67 | /// Edit the graph coordinates of one or more graph points. This method does not apply to an axis point | |
68 | void editPointGraph (bool isX, | |
69 | bool isY, | |
70 | double x, | |
71 | double y, | |
72 | const QStringList &identifiers, | |
73 | const Transformation &transformation); | |
66 | 74 | |
67 | 75 | /// Export points in this Curve found in the specified point list. |
68 | 76 | void exportToClipboard (const QHash<QString, bool> &selectedHash, |
92 | 92 | return 0; |
93 | 93 | } |
94 | 94 | |
95 | void CurvesGraphs::editPointGraph (bool isX, | |
96 | bool isY, | |
97 | double x, | |
98 | double y, | |
99 | const QStringList &identifiers, | |
100 | const Transformation &transformation) | |
101 | { | |
102 | CurveList::iterator itr; | |
103 | for (itr = m_curvesGraphs.begin (); itr != m_curvesGraphs.end (); itr++) { | |
104 | ||
105 | Curve &curve = *itr; | |
106 | curve.editPointGraph (isX, | |
107 | isY, | |
108 | x, | |
109 | y, | |
110 | identifiers, | |
111 | transformation); | |
112 | } | |
113 | } | |
114 | ||
95 | 115 | void CurvesGraphs::iterateThroughCurvePoints (const QString &curveNameWanted, |
96 | 116 | const Functor2wRet<const QString &, const Point &, CallbackSearchReturn> &ftorWithCallback) |
97 | 117 | { |
43 | 43 | /// Point count. |
44 | 44 | int curvesGraphsNumPoints (const QString &curveName) const; |
45 | 45 | |
46 | /// Set the x and/or y coordinate values of the specified points | |
47 | void editPointGraph (bool isX, | |
48 | bool isY, | |
49 | double x, | |
50 | double y, | |
51 | const QStringList &identifiers, | |
52 | const Transformation &transformation); | |
53 | ||
46 | 54 | /// Apply functor to Points in the specified axis or graph Curve. |
47 | 55 | void iterateThroughCurvePoints (const QString &curveNameWanted, |
48 | 56 | const Functor2wRet<const QString &, const Point &, CallbackSearchReturn> &ftorWithCallback); |
3 | 3 | * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. * |
4 | 4 | ******************************************************************************************************/ |
5 | 5 | |
6 | #include "CmdEditPointAxis.h" | |
7 | 6 | #include "CmdMediator.h" |
8 | 7 | #include "DigitizeStateAbstractBase.h" |
9 | 8 | #include "DigitizeStateContext.h" |
10 | #include "DlgEditPoint.h" | |
11 | 9 | #include "Document.h" |
12 | 10 | #include "Logger.h" |
13 | 11 | #include "MainWindow.h" |
14 | #include <QApplication> | |
12 | #include "MainWindowModel.h" | |
13 | #include <QCursor> | |
15 | 14 | #include <QGraphicsScene> |
16 | 15 | #include <QImage> |
17 | #include <QMessageBox> | |
18 | 16 | #include <QTimer> |
19 | 17 | #include "QtToString.h" |
20 | #include "Version.h" | |
18 | #include "Transformation.h" | |
21 | 19 | |
22 | 20 | DigitizeStateAbstractBase::DigitizeStateAbstractBase(DigitizeStateContext &context) : |
23 | m_context (context), | |
24 | m_isOverrideCursor (false) | |
21 | m_context (context) | |
25 | 22 | { |
26 | 23 | } |
27 | 24 | |
39 | 36 | return m_context; |
40 | 37 | } |
41 | 38 | |
42 | void DigitizeStateAbstractBase::handleContextMenuEvent (CmdMediator *cmdMediator, | |
43 | const QString &pointIdentifier) | |
44 | { | |
45 | LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateAbstractBase::handleContextMenuEvent point=" << pointIdentifier.toLatin1 ().data (); | |
46 | ||
47 | QPointF posScreen = cmdMediator->document().positionScreen (pointIdentifier); | |
48 | QPointF posGraphBefore = cmdMediator->document().positionGraph (pointIdentifier); | |
49 | bool isXOnly = cmdMediator->document().isXOnly (pointIdentifier); | |
50 | ||
51 | // Ask user for coordinates | |
52 | double x = posGraphBefore.x(); | |
53 | double y = posGraphBefore.y(); | |
54 | ||
55 | DlgEditPoint *dlg = new DlgEditPoint(context().mainWindow(), | |
56 | *this, | |
57 | cmdMediator->document().modelCoords(), | |
58 | context().mainWindow().modelMainWindow(), | |
59 | cursor (cmdMediator), | |
60 | context().mainWindow().transformation(), | |
61 | cmdMediator->document().documentAxesPointsRequired(), | |
62 | isXOnly, | |
63 | &x, | |
64 | &y); | |
65 | int rtn = dlg->exec (); | |
66 | ||
67 | QPointF posGraphAfter = dlg->posGraph (isXOnly); // This call returns new values for isXOnly and the graph position | |
68 | delete dlg; | |
69 | ||
70 | if (rtn == QDialog::Accepted) { | |
71 | ||
72 | // User wants to edit this axis point, but let's perform sanity checks first | |
73 | ||
74 | bool isError; | |
75 | QString errorMessage; | |
76 | ||
77 | context().mainWindow().cmdMediator()->document().checkEditPointAxis(pointIdentifier, | |
78 | posScreen, | |
79 | posGraphAfter, | |
80 | isError, | |
81 | errorMessage); | |
82 | ||
83 | if (isError) { | |
84 | ||
85 | QMessageBox::warning (0, | |
86 | engaugeWindowTitle(), | |
87 | errorMessage); | |
88 | ||
89 | } else { | |
90 | ||
91 | // Create a command to edit the point | |
92 | CmdEditPointAxis *cmd = new CmdEditPointAxis (context().mainWindow(), | |
93 | cmdMediator->document(), | |
94 | pointIdentifier, | |
95 | posGraphBefore, | |
96 | posGraphAfter, | |
97 | isXOnly); | |
98 | context().appendNewCmd(cmdMediator, | |
99 | cmd); | |
100 | } | |
101 | } | |
102 | } | |
103 | ||
104 | void DigitizeStateAbstractBase::handleLeave (CmdMediator * /* cmdMediator */) | |
105 | { | |
106 | LOG4CPP_DEBUG_S ((*mainCat)) << "DigitizeStateAbstractBase::handleLeave"; | |
107 | ||
108 | removeOverrideCursor (); | |
109 | } | |
110 | ||
111 | void DigitizeStateAbstractBase::handleSetOverrideCursor (CmdMediator * /* cmdMediator */, | |
112 | const QCursor &cursor) | |
113 | { | |
114 | removeOverrideCursor (); | |
115 | ||
116 | LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateAbstractBase::handleSetOverrideCursor setOverrideCursor=" | |
117 | << QtCursorToString (cursor.shape ()).toLatin1 ().data (); | |
118 | ||
119 | QApplication::setOverrideCursor (cursor); | |
120 | m_isOverrideCursor = true; | |
121 | } | |
122 | ||
123 | void DigitizeStateAbstractBase::removeOverrideCursor () | |
124 | { | |
125 | if (m_isOverrideCursor) { | |
126 | ||
127 | LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateAbstractBase::handleLeave restoreOverrideCursor=" | |
128 | << QtCursorToString (QApplication::overrideCursor ()->shape ()).toLatin1 ().data (); | |
129 | ||
130 | // Override cursor from last QDialog must be restored | |
131 | QApplication::restoreOverrideCursor (); | |
132 | ||
133 | m_isOverrideCursor = false; | |
134 | } | |
135 | } | |
136 | ||
137 | 39 | void DigitizeStateAbstractBase::setCursor(CmdMediator *cmdMediator) |
138 | 40 | { |
139 | 41 | LOG4CPP_DEBUG_S ((*mainCat)) << "DigitizeStateAbstractBase::setCursor"; |
140 | 42 | |
141 | removeOverrideCursor (); | |
142 | context().view().setCursor (cursor (cmdMediator)); | |
43 | // Note that we are setting the QGraphicsView cursor and NOT the QApplication override cursor | |
44 | m_context.view ().setCursor (cursor (cmdMediator)); | |
143 | 45 | } |
16 | 16 | class DocumentModelSegments; |
17 | 17 | class QGraphicsScene; |
18 | 18 | class QImage; |
19 | class QString; | |
20 | class QStringList; | |
19 | 21 | class QTimer; |
20 | 22 | |
21 | 23 | /// Set of possible states of Digitize toolbar. |
55 | 57 | /// Method that is called at the exact moment a state is exited. Typically called just before begin for the next state |
56 | 58 | virtual void end() = 0; |
57 | 59 | |
58 | /// Handle a right click that was intercepted earlier. This is done in the superclass since it works the same in all states. | |
59 | void handleContextMenuEvent (CmdMediator *cmdMediator, | |
60 | const QString &pointIdentifier); | |
60 | /// Handle a right click, on an axis point, that was intercepted earlier | |
61 | virtual void handleContextMenuEventAxis (CmdMediator *cmdMediator, | |
62 | const QString &pointIdentifier) = 0; | |
63 | ||
64 | /// Handle a right click, on a graph point, that was intercepted earlier | |
65 | virtual void handleContextMenuEventGraph (CmdMediator *cmdMediator, | |
66 | const QStringList &pointIdentifiers) = 0; | |
61 | 67 | |
62 | 68 | /// Handle the selection of a new curve. At a minimum, DigitizeStateSegment will generate a new set of Segments |
63 | 69 | virtual void handleCurveChange (CmdMediator *cmdMediator) = 0; |
66 | 72 | virtual void handleKeyPress (CmdMediator *cmdMediator, |
67 | 73 | Qt::Key key, |
68 | 74 | bool atLeastOneSelectedItem) = 0; |
69 | ||
70 | /// Handle leave in case an override cursor is in effect from last QDialog, by resetting the override cursor. | |
71 | virtual void handleLeave (CmdMediator *cmdMediator); | |
72 | 75 | |
73 | 76 | /// Handle a mouse move. This is part of an experiment to see if augmenting the cursor in Point Match mode is worthwhile |
74 | 77 | virtual void handleMouseMove (CmdMediator *cmdMediator, |
82 | 85 | virtual void handleMouseRelease (CmdMediator *cmdMediator, |
83 | 86 | QPointF pos) = 0; |
84 | 87 | |
85 | /// Handle the command to set the override cursor | |
86 | void handleSetOverrideCursor (CmdMediator *cmdMediator, | |
87 | const QCursor &cursor); | |
88 | ||
89 | /// Remove the override cursor if it is in use. This is called after a leave event, and prior to displaying a QDialog | |
90 | void removeOverrideCursor (); | |
91 | ||
92 | 88 | /// Update the cursor according to the current state. |
93 | 89 | void setCursor(CmdMediator *cmdMediator); |
94 | 90 | |
95 | 91 | /// State name for debugging |
96 | 92 | virtual QString state() const = 0; |
93 | ||
94 | /// Update graphics attributes after possible new points. This is useful for highlight opacity | |
95 | virtual void updateAfterPointAddition () = 0; | |
97 | 96 | |
98 | 97 | /// Update the digitize curve settings |
99 | 98 | virtual void updateModelDigitizeCurve (CmdMediator *cmdMediator, |
111 | 110 | |
112 | 111 | DigitizeStateContext &m_context; |
113 | 112 | |
114 | bool m_isOverrideCursor; // Checking QApplication::overrideCursor()==0 is unreliable so this tracks the override cursor state | |
115 | 113 | }; |
116 | 114 | |
117 | 115 | #endif // DIGITIZE_STATE_ABSTRACT_BASE_H |
8 | 8 | #include "CursorFactory.h" |
9 | 9 | #include "DigitizeStateAxis.h" |
10 | 10 | #include "DigitizeStateContext.h" |
11 | #include "DlgEditPoint.h" | |
11 | #include "DlgEditPointAxis.h" | |
12 | 12 | #include "Document.h" |
13 | 13 | #include "GraphicsScene.h" |
14 | 14 | #include "GraphicsView.h" |
49 | 49 | { |
50 | 50 | LOG4CPP_DEBUG_S ((*mainCat)) << "DigitizeStateAxis::createTemporaryPoint"; |
51 | 51 | |
52 | // Temporary point that user can see while DlgEditPoint is active | |
52 | GeometryWindow *NULL_GEOMETRY_WINDOW = 0; | |
53 | ||
54 | // Temporary point that user can see while DlgEditPointAxis is active | |
53 | 55 | const Curve &curveAxes = cmdMediator->curveAxes(); |
54 | 56 | PointStyle pointStyleAxes = curveAxes.curveStyle().pointStyle(); |
55 | 57 | GraphicsPoint *point = context().mainWindow().scene().createPoint(Point::temporaryPointIdentifier (), |
56 | 58 | pointStyleAxes, |
57 | posScreen); | |
59 | posScreen, | |
60 | NULL_GEOMETRY_WINDOW); | |
58 | 61 | |
59 | 62 | context().mainWindow().scene().addTemporaryPoint (Point::temporaryPointIdentifier(), |
60 | 63 | point); |
73 | 76 | void DigitizeStateAxis::end () |
74 | 77 | { |
75 | 78 | LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateAxis::end"; |
79 | } | |
80 | ||
81 | void DigitizeStateAxis::handleContextMenuEventAxis (CmdMediator * /* cmdMediator */, | |
82 | const QString &pointIdentifier) | |
83 | { | |
84 | LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateAxis::handleContextMenuEventAxis " | |
85 | << " point=" << pointIdentifier.toLatin1 ().data (); | |
86 | } | |
87 | ||
88 | void DigitizeStateAxis::handleContextMenuEventGraph (CmdMediator * /* cmdMediator */, | |
89 | const QStringList &pointIdentifiers) | |
90 | { | |
91 | LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateAxis::handleContextMenuEventGraph " | |
92 | << "points=" << pointIdentifiers.join(",").toLatin1 ().data (); | |
76 | 93 | } |
77 | 94 | |
78 | 95 | void DigitizeStateAxis::handleCurveChange(CmdMediator * /* cmdMediator */) |
117 | 134 | posScreen); |
118 | 135 | |
119 | 136 | // Ask user for coordinates |
120 | DlgEditPoint *dlg = new DlgEditPoint (context ().mainWindow (), | |
121 | *this, | |
122 | cmdMediator->document().modelCoords(), | |
123 | context().mainWindow().modelMainWindow(), | |
124 | cursor (cmdMediator), | |
125 | context().mainWindow().transformation(), | |
126 | cmdMediator->document().documentAxesPointsRequired()); | |
137 | DlgEditPointAxis *dlg = new DlgEditPointAxis (context ().mainWindow (), | |
138 | cmdMediator->document().modelCoords(), | |
139 | context().mainWindow().modelMainWindow(), | |
140 | context().mainWindow().transformation(), | |
141 | cmdMediator->document().documentAxesPointsRequired()); | |
127 | 142 | int rtn = dlg->exec (); |
128 | 143 | |
129 | 144 | bool isXOnly; |
175 | 190 | return "DigitizeStateAxis"; |
176 | 191 | } |
177 | 192 | |
193 | void DigitizeStateAxis::updateAfterPointAddition () | |
194 | { | |
195 | LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateAxis::updateAfterPointAddition"; | |
196 | } | |
197 | ||
178 | 198 | void DigitizeStateAxis::updateModelDigitizeCurve (CmdMediator *cmdMediator, |
179 | 199 | const DocumentModelDigitizeCurve & /*modelDigitizeCurve */) |
180 | 200 | { |
24 | 24 | DigitizeState previousState); |
25 | 25 | virtual QCursor cursor (CmdMediator *cmdMediator) const; |
26 | 26 | virtual void end(); |
27 | virtual void handleContextMenuEventAxis (CmdMediator *cmdMediator, | |
28 | const QString &pointIdentifier); | |
29 | virtual void handleContextMenuEventGraph (CmdMediator *cmdMediator, | |
30 | const QStringList &pointIdentifiers); | |
27 | 31 | virtual void handleCurveChange(CmdMediator *cmdMediator); |
28 | 32 | virtual void handleKeyPress (CmdMediator *cmdMediator, |
29 | 33 | Qt::Key key, |
35 | 39 | virtual void handleMouseRelease (CmdMediator *cmdMediator, |
36 | 40 | QPointF posScreen); |
37 | 41 | virtual QString state() const; |
42 | virtual void updateAfterPointAddition (); | |
38 | 43 | virtual void updateModelDigitizeCurve (CmdMediator *cmdMediator, |
39 | 44 | const DocumentModelDigitizeCurve &modelDigitizeCurve); |
40 | 45 | virtual void updateModelSegments(const DocumentModelSegments &modelSegments); |
219 | 219 | return false; |
220 | 220 | } |
221 | 221 | |
222 | void DigitizeStateColorPicker::handleContextMenuEventAxis (CmdMediator * /* cmdMediator */, | |
223 | const QString &pointIdentifier) | |
224 | { | |
225 | LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateColorPicker::handleContextMenuEventAxis " | |
226 | << " point=" << pointIdentifier.toLatin1 ().data (); | |
227 | } | |
228 | ||
229 | void DigitizeStateColorPicker::handleContextMenuEventGraph (CmdMediator * /* cmdMediator */, | |
230 | const QStringList &pointIdentifiers) | |
231 | { | |
232 | LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateColorPicker ::handleContextMenuEventGraph " | |
233 | << "points=" << pointIdentifiers.join(",").toLatin1 ().data (); | |
234 | } | |
235 | ||
222 | 236 | void DigitizeStateColorPicker::handleCurveChange(CmdMediator * /* cmdMediator */) |
223 | 237 | { |
224 | 238 | LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateColorPicker::handleCurveChange"; |
320 | 334 | return "DigitizeStateColorPicker"; |
321 | 335 | } |
322 | 336 | |
337 | void DigitizeStateColorPicker::updateAfterPointAddition () | |
338 | { | |
339 | LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateColorPicker::updateAfterPointAddition"; | |
340 | } | |
341 | ||
323 | 342 | void DigitizeStateColorPicker::updateModelDigitizeCurve (CmdMediator * /* cmdMediator */, |
324 | 343 | const DocumentModelDigitizeCurve & /*modelDigitizeCurve */) |
325 | 344 | { |
29 | 29 | DigitizeState previousState); |
30 | 30 | virtual QCursor cursor (CmdMediator *cmdMediator) const; |
31 | 31 | virtual void end(); |
32 | virtual void handleContextMenuEventAxis (CmdMediator *cmdMediator, | |
33 | const QString &pointIdentifier); | |
34 | virtual void handleContextMenuEventGraph (CmdMediator *cmdMediator, | |
35 | const QStringList &pointIdentifiers); | |
32 | 36 | virtual void handleCurveChange(CmdMediator *cmdMediator); |
33 | 37 | virtual void handleKeyPress (CmdMediator *cmdMediator, |
34 | 38 | Qt::Key key, |
40 | 44 | virtual void handleMouseRelease (CmdMediator *cmdMediator, |
41 | 45 | QPointF posScreen); |
42 | 46 | virtual QString state() const; |
47 | virtual void updateAfterPointAddition (); | |
43 | 48 | virtual void updateModelDigitizeCurve (CmdMediator *cmdMediator, |
44 | 49 | const DocumentModelDigitizeCurve &modelDigitizeCurve); |
45 | 50 | virtual void updateModelSegments(const DocumentModelSegments &modelSegments); |
18 | 18 | #include "GraphicsView.h" |
19 | 19 | #include "Logger.h" |
20 | 20 | #include "MainWindow.h" |
21 | #include <QApplication> | |
22 | 21 | #include <QCursor> |
23 | 22 | #include <QGraphicsScene> |
24 | 23 | #include <QGraphicsView> |
88 | 87 | } |
89 | 88 | } |
90 | 89 | |
91 | void DigitizeStateContext::handleContextMenuEvent (CmdMediator *cmdMediator, | |
92 | const QString &pointIdentifier) | |
93 | { | |
94 | m_states [m_currentState]->handleContextMenuEvent (cmdMediator, | |
95 | pointIdentifier); | |
90 | void DigitizeStateContext::handleContextMenuEventAxis (CmdMediator *cmdMediator, | |
91 | const QString &pointIdentifier) | |
92 | { | |
93 | m_states [m_currentState]->handleContextMenuEventAxis (cmdMediator, | |
94 | pointIdentifier); | |
95 | } | |
96 | ||
97 | void DigitizeStateContext::handleContextMenuEventGraph (CmdMediator *cmdMediator, | |
98 | const QStringList &pointIdentifiers) | |
99 | { | |
100 | m_states [m_currentState]->handleContextMenuEventGraph (cmdMediator, | |
101 | pointIdentifiers); | |
96 | 102 | } |
97 | 103 | |
98 | 104 | void DigitizeStateContext::handleCurveChange (CmdMediator *cmdMediator) |
112 | 118 | |
113 | 119 | } |
114 | 120 | |
115 | void DigitizeStateContext::handleLeave (CmdMediator *cmdMediator) | |
116 | { | |
117 | m_states [m_currentState]->handleLeave (cmdMediator); | |
118 | ||
119 | completeRequestedStateTransitionIfExists(cmdMediator); | |
120 | ||
121 | } | |
122 | ||
123 | 121 | void DigitizeStateContext::handleMouseMove (CmdMediator *cmdMediator, |
124 | 122 | QPointF pos) |
125 | 123 | { |
147 | 145 | pos); |
148 | 146 | |
149 | 147 | completeRequestedStateTransitionIfExists(cmdMediator); |
150 | } | |
151 | ||
152 | void DigitizeStateContext::handleSetOverrideCursor (CmdMediator *cmdMediator, | |
153 | const QCursor &cursor) | |
154 | { | |
155 | m_states [m_currentState]->handleSetOverrideCursor (cmdMediator, | |
156 | cursor); | |
157 | 148 | } |
158 | 149 | |
159 | 150 | bool DigitizeStateContext::isGnuplot () const |
229 | 220 | return m_states [m_currentState]->state(); |
230 | 221 | } |
231 | 222 | |
223 | void DigitizeStateContext::updateAfterPointAddition () | |
224 | { | |
225 | ENGAUGE_ASSERT (m_currentState != NUM_DIGITIZE_STATES); | |
226 | ||
227 | m_states [m_currentState]->updateAfterPointAddition (); | |
228 | } | |
229 | ||
232 | 230 | void DigitizeStateContext::updateModelDigitizeCurve (CmdMediator *cmdMediator, |
233 | 231 | const DocumentModelDigitizeCurve &modelDigitizeCurve) |
234 | 232 | { |
17 | 17 | class DocumentModelDigitizeCurve; |
18 | 18 | class DocumentModelSegments; |
19 | 19 | class MainWindow; |
20 | class MainWindowModel; | |
20 | 21 | class QUndoCommand; |
21 | 22 | |
22 | 23 | /// Container for all DigitizeStateAbstractBase subclasses. This functions as the context class in a standard state machine implementation |
38 | 39 | void appendNewCmd(CmdMediator *cmdMediator, |
39 | 40 | QUndoCommand *cmd); |
40 | 41 | |
41 | /// See DigitizeStateAbstractBase::handleContextMenuEvent. | |
42 | void handleContextMenuEvent (CmdMediator *cmdMediator, | |
43 | const QString &pointIdentifier); | |
42 | /// See DigitizeStateAbstractBase::handleContextMenuEventAxis. | |
43 | void handleContextMenuEventAxis (CmdMediator *cmdMediator, | |
44 | const QString &pointIdentifier); | |
45 | ||
46 | /// See DigitizeStateAbstractBase::handleContextMenuEventGraph. | |
47 | void handleContextMenuEventGraph (CmdMediator *cmdMediator, | |
48 | const QStringList &pointIdentifiers); | |
44 | 49 | |
45 | 50 | /// See DigitizeStateAbstractBase::handleCurveChange. |
46 | 51 | void handleCurveChange (CmdMediator *cmdMediator); |
49 | 54 | void handleKeyPress (CmdMediator *cmdMediator, |
50 | 55 | Qt::Key key, |
51 | 56 | bool atLeastOneSelectedItem); |
52 | ||
53 | /// See DigitizeStateAbstractBase::handleLeave. | |
54 | void handleLeave (CmdMediator *cmdMediator); | |
55 | 57 | |
56 | 58 | /// See DigitizeStateAbstractBase::handleMouseMove. |
57 | 59 | void handleMouseMove (CmdMediator *cmdMediator, |
64 | 66 | /// See DigitizeStateAbstractBase::handleMouseRelease. |
65 | 67 | void handleMouseRelease (CmdMediator *cmdMediator, |
66 | 68 | QPointF pos); |
67 | ||
68 | /// See DigitizeStateAbstractBase::handleSetOverrideCursor | |
69 | void handleSetOverrideCursor (CmdMediator *cmdMediator, | |
70 | const QCursor &cursor); | |
71 | 69 | |
72 | 70 | /// Get method for gnuplot flag |
73 | 71 | bool isGnuplot () const; |
101 | 99 | /// State name for debugging |
102 | 100 | QString state() const; |
103 | 101 | |
102 | /// Update the graphics attributes | |
103 | void updateAfterPointAddition (); | |
104 | ||
104 | 105 | /// Update the digitize curve settings |
105 | 106 | void updateModelDigitizeCurve (CmdMediator *cmdMediator, |
106 | 107 | const DocumentModelDigitizeCurve &modelDigitizeCurve); |
54 | 54 | LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateCurve::end"; |
55 | 55 | } |
56 | 56 | |
57 | void DigitizeStateCurve::handleContextMenuEventAxis (CmdMediator * /* cmdMediator */, | |
58 | const QString &pointIdentifier) | |
59 | { | |
60 | LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateCurve::handleContextMenuEventAxis " | |
61 | << " point=" << pointIdentifier.toLatin1 ().data (); | |
62 | } | |
63 | ||
64 | void DigitizeStateCurve::handleContextMenuEventGraph (CmdMediator * /* cmdMediator */, | |
65 | const QStringList &pointIdentifiers) | |
66 | { | |
67 | LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateCurve ::handleContextMenuEventGraph " | |
68 | << "points=" << pointIdentifiers.join(",").toLatin1 ().data (); | |
69 | } | |
70 | ||
57 | 71 | void DigitizeStateCurve::handleCurveChange(CmdMediator * /* cmdMediator */) |
58 | 72 | { |
59 | 73 | LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateCurve::handleCurveChange"; |
105 | 119 | return "DigitizeStateCurve"; |
106 | 120 | } |
107 | 121 | |
122 | void DigitizeStateCurve::updateAfterPointAddition () | |
123 | { | |
124 | LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateCurve::updateAfterPointAddition"; | |
125 | } | |
126 | ||
108 | 127 | void DigitizeStateCurve::updateModelDigitizeCurve (CmdMediator *cmdMediator, |
109 | 128 | const DocumentModelDigitizeCurve & /*modelDigitizeCurve */) |
110 | 129 | { |
21 | 21 | DigitizeState previousState); |
22 | 22 | virtual QCursor cursor (CmdMediator *cmdMediator) const; |
23 | 23 | virtual void end(); |
24 | virtual void handleContextMenuEventAxis (CmdMediator *cmdMediator, | |
25 | const QString &pointIdentifier); | |
26 | virtual void handleContextMenuEventGraph (CmdMediator *cmdMediator, | |
27 | const QStringList &pointIdentifiers); | |
24 | 28 | virtual void handleCurveChange(CmdMediator *cmdMediator); |
25 | 29 | virtual void handleKeyPress (CmdMediator *cmdMediator, |
26 | 30 | Qt::Key key, |
32 | 36 | virtual void handleMouseRelease (CmdMediator *cmdMediator, |
33 | 37 | QPointF posScreen); |
34 | 38 | virtual QString state() const; |
39 | virtual void updateAfterPointAddition (); | |
35 | 40 | virtual void updateModelDigitizeCurve (CmdMediator *cmdMediator, |
36 | 41 | const DocumentModelDigitizeCurve &modelDigitizeCurve); |
37 | 42 | virtual void updateModelSegments(const DocumentModelSegments &modelSegments); |
44 | 44 | LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateEmpty::end"; |
45 | 45 | } |
46 | 46 | |
47 | void DigitizeStateEmpty::handleContextMenuEventAxis (CmdMediator * /* cmdMediator */, | |
48 | const QString &pointIdentifier) | |
49 | { | |
50 | LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateEmpty::handleContextMenuEventAxis " | |
51 | << " point=" << pointIdentifier.toLatin1 ().data (); | |
52 | } | |
53 | ||
54 | void DigitizeStateEmpty::handleContextMenuEventGraph (CmdMediator * /* cmdMediator */, | |
55 | const QStringList &pointIdentifiers) | |
56 | { | |
57 | LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateEmpty ::handleContextMenuEventGraph " | |
58 | << "points=" << pointIdentifiers.join(",").toLatin1 ().data (); | |
59 | } | |
60 | ||
47 | 61 | void DigitizeStateEmpty::handleCurveChange(CmdMediator * /* cmdMediator */) |
48 | 62 | { |
49 | 63 | LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateEmpty::handleCurveChange"; |
80 | 94 | return "DigitizeStateEmpty"; |
81 | 95 | } |
82 | 96 | |
97 | void DigitizeStateEmpty::updateAfterPointAddition () | |
98 | { | |
99 | LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateEmpty::updateAfterPointAddition"; | |
100 | } | |
101 | ||
83 | 102 | void DigitizeStateEmpty::updateModelDigitizeCurve (CmdMediator * /* cmdMediator */, |
84 | 103 | const DocumentModelDigitizeCurve & /*modelDigitizeCurve */) |
85 | 104 | { |
22 | 22 | virtual QCursor cursor (CmdMediator *cmdMediator) const; |
23 | 23 | virtual void end(); |
24 | 24 | virtual void handleCurveChange(CmdMediator *cmdMediator); |
25 | virtual void handleContextMenuEventAxis (CmdMediator *cmdMediator, | |
26 | const QString &pointIdentifier); | |
27 | virtual void handleContextMenuEventGraph (CmdMediator *cmdMediator, | |
28 | const QStringList &pointIdentifiers); | |
25 | 29 | virtual void handleKeyPress (CmdMediator *cmdMediator, |
26 | 30 | Qt::Key key, |
27 | 31 | bool atLeastOneSelectedItem); |
32 | 36 | virtual void handleMouseRelease (CmdMediator *cmdMediator, |
33 | 37 | QPointF posScreen); |
34 | 38 | virtual QString state() const; |
39 | virtual void updateAfterPointAddition (); | |
35 | 40 | virtual void updateModelDigitizeCurve (CmdMediator *cmdMediator, |
36 | 41 | const DocumentModelDigitizeCurve &modelDigitizeCurve); |
37 | 42 | virtual void updateModelSegments(const DocumentModelSegments &modelSegments); |
88 | 88 | { |
89 | 89 | LOG4CPP_DEBUG_S ((*mainCat)) << "DigitizeStatePointMatch::createTemporaryPoint"; |
90 | 90 | |
91 | GeometryWindow *NULL_GEOMETRY_WINDOW = 0; | |
92 | ||
91 | 93 | const DocumentModelPointMatch &modelPointMatch = cmdMediator->document().modelPointMatch(); |
92 | 94 | |
93 | 95 | // Get point style for current graph, and then override with candidate color |
98 | 100 | // Temporary point that user can see while DlgEditPoint is active |
99 | 101 | GraphicsPoint *point = context().mainWindow().scene().createPoint(Point::temporaryPointIdentifier (), |
100 | 102 | pointStyle, |
101 | posScreen); | |
103 | posScreen, | |
104 | NULL_GEOMETRY_WINDOW); | |
102 | 105 | |
103 | 106 | context().mainWindow().scene().removeTemporaryPointIfExists(); // Only one temporary point at a time is allowed |
104 | 107 | |
164 | 167 | } |
165 | 168 | |
166 | 169 | return samplePointPixels; |
170 | } | |
171 | ||
172 | void DigitizeStatePointMatch::handleContextMenuEventAxis (CmdMediator * /* cmdMediator */, | |
173 | const QString &pointIdentifier) | |
174 | { | |
175 | LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStatePointMatch::handleContextMenuEventAxis " | |
176 | << " point=" << pointIdentifier.toLatin1 ().data (); | |
177 | } | |
178 | ||
179 | void DigitizeStatePointMatch::handleContextMenuEventGraph (CmdMediator * /* cmdMediator */, | |
180 | const QStringList &pointIdentifiers) | |
181 | { | |
182 | LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStatePointMatch ::handleContextMenuEventGraph " | |
183 | << "points=" << pointIdentifiers.join(",").toLatin1 ().data (); | |
167 | 184 | } |
168 | 185 | |
169 | 186 | void DigitizeStatePointMatch::handleCurveChange(CmdMediator * /* cmdMediator */) |
337 | 354 | return "DigitizeStatePointMatch"; |
338 | 355 | } |
339 | 356 | |
357 | void DigitizeStatePointMatch::updateAfterPointAddition () | |
358 | { | |
359 | LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStatePointMatch::updateAfterPointAddition"; | |
360 | } | |
361 | ||
340 | 362 | void DigitizeStatePointMatch::updateModelDigitizeCurve (CmdMediator * /* cmdMediator */, |
341 | 363 | const DocumentModelDigitizeCurve & /*modelDigitizeCurve */) |
342 | 364 | { |
29 | 29 | DigitizeState previousState); |
30 | 30 | virtual QCursor cursor (CmdMediator *cmdMediator) const; |
31 | 31 | virtual void end(); |
32 | virtual void handleContextMenuEventAxis (CmdMediator *cmdMediator, | |
33 | const QString &pointIdentifier); | |
34 | virtual void handleContextMenuEventGraph (CmdMediator *cmdMediator, | |
35 | const QStringList &pointIdentifiers); | |
32 | 36 | virtual void handleCurveChange(CmdMediator *cmdMediator); |
33 | 37 | virtual void handleKeyPress (CmdMediator *cmdMediator, |
34 | 38 | Qt::Key key, |
40 | 44 | virtual void handleMouseRelease (CmdMediator *cmdMediator, |
41 | 45 | QPointF posScreen); |
42 | 46 | virtual QString state() const; |
47 | virtual void updateAfterPointAddition (); | |
43 | 48 | virtual void updateModelDigitizeCurve (CmdMediator *cmdMediator, |
44 | 49 | const DocumentModelDigitizeCurve &modelDigitizeCurve); |
45 | 50 | virtual void updateModelSegments(const DocumentModelSegments &modelSegments); |
62 | 62 | segmentFactory.clearSegments(m_segments); |
63 | 63 | } |
64 | 64 | |
65 | void DigitizeStateSegment::handleContextMenuEventAxis (CmdMediator * /* cmdMediator */, | |
66 | const QString &pointIdentifier) | |
67 | { | |
68 | LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateSegment::handleContextMenuEventAxis " | |
69 | << " point=" << pointIdentifier.toLatin1 ().data (); | |
70 | } | |
71 | ||
72 | void DigitizeStateSegment::handleContextMenuEventGraph (CmdMediator * /* cmdMediator */, | |
73 | const QStringList &pointIdentifiers) | |
74 | { | |
75 | LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateSegment ::handleContextMenuEventGraph " | |
76 | << "points=" << pointIdentifiers.join(",").toLatin1 ().data (); | |
77 | } | |
78 | ||
65 | 79 | void DigitizeStateSegment::handleCurveChange(CmdMediator *cmdMediator) |
66 | 80 | { |
67 | 81 | LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateSegment::handleCurveChange"; |
185 | 199 | return "DigitizeStateSegment"; |
186 | 200 | } |
187 | 201 | |
202 | void DigitizeStateSegment::updateAfterPointAddition () | |
203 | { | |
204 | LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateSegment::updateAfterPointAddition"; | |
205 | } | |
206 | ||
188 | 207 | void DigitizeStateSegment::updateModelDigitizeCurve (CmdMediator * /* cmdMediator */, |
189 | 208 | const DocumentModelDigitizeCurve & /*modelDigitizeCurve */) |
190 | 209 | { |
27 | 27 | DigitizeState previousState); |
28 | 28 | virtual QCursor cursor (CmdMediator *cmdMediator) const; |
29 | 29 | virtual void end(); |
30 | virtual void handleContextMenuEventAxis (CmdMediator *cmdMediator, | |
31 | const QString &pointIdentifier); | |
32 | virtual void handleContextMenuEventGraph (CmdMediator *cmdMediator, | |
33 | const QStringList &pointIdentifiers); | |
30 | 34 | virtual void handleCurveChange(CmdMediator *cmdMediator); |
31 | 35 | virtual void handleKeyPress (CmdMediator *cmdMediator, |
32 | 36 | Qt::Key key, |
38 | 42 | virtual void handleMouseRelease (CmdMediator *cmdMediator, |
39 | 43 | QPointF posScreen); |
40 | 44 | virtual QString state() const; |
45 | virtual void updateAfterPointAddition (); | |
41 | 46 | virtual void updateModelDigitizeCurve (CmdMediator *cmdMediator, |
42 | 47 | const DocumentModelDigitizeCurve &modelDigitizeCurve); |
43 | 48 | virtual void updateModelSegments(const DocumentModelSegments &modelSegments); |
3 | 3 | * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. * |
4 | 4 | ******************************************************************************************************/ |
5 | 5 | |
6 | #include "CmdEditPointAxis.h" | |
7 | #include "CmdEditPointGraph.h" | |
6 | 8 | #include "CmdMediator.h" |
7 | 9 | #include "CmdMoveBy.h" |
8 | 10 | #include "DataKey.h" |
9 | 11 | #include "DigitizeStateContext.h" |
10 | 12 | #include "DigitizeStateSelect.h" |
13 | #include "DlgEditPointAxis.h" | |
14 | #include "DlgEditPointGraph.h" | |
11 | 15 | #include "EngaugeAssert.h" |
16 | #include "GraphicsItemsExtractor.h" | |
12 | 17 | #include "GraphicsItemType.h" |
13 | 18 | #include "GraphicsScene.h" |
14 | 19 | #include "GraphicsView.h" |
17 | 22 | #include <QCursor> |
18 | 23 | #include <QGraphicsItem> |
19 | 24 | #include <QImage> |
25 | #include <QMessageBox> | |
20 | 26 | #include <QObject> |
21 | 27 | #include <QtToString.h> |
28 | #include "Version.h" | |
22 | 29 | |
23 | 30 | const QString MOVE_TEXT_DOWN (QObject::tr ("Move down")); |
24 | 31 | const QString MOVE_TEXT_LEFT (QObject::tr ("Move left")); |
39 | 46 | return context().mainWindow().selectedGraphCurve(); |
40 | 47 | } |
41 | 48 | |
49 | void DigitizeStateSelect::addHoverHighlighting() | |
50 | { | |
51 | LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateSelect::addHoverHighlighting"; | |
52 | ||
53 | QList<QGraphicsItem*> items = context().mainWindow().scene().items(); | |
54 | QList<QGraphicsItem*>::iterator itr; | |
55 | for (itr = items.begin (); itr != items.end (); itr++) { | |
56 | ||
57 | QGraphicsItem *item = *itr; | |
58 | if (item->data (DATA_KEY_GRAPHICS_ITEM_TYPE) == GRAPHICS_ITEM_TYPE_POINT) { | |
59 | item->setAcceptHoverEvents(true); | |
60 | } | |
61 | } | |
62 | } | |
63 | ||
42 | 64 | void DigitizeStateSelect::begin (CmdMediator *cmdMediator, |
43 | 65 | DigitizeState /* previousState */) |
44 | 66 | { |
47 | 69 | setCursor(cmdMediator); |
48 | 70 | context().setDragMode(QGraphicsView::RubberBandDrag); |
49 | 71 | |
50 | setCursorForPoints (); | |
72 | addHoverHighlighting(); | |
51 | 73 | context().mainWindow().updateViewsOfSettings(activeCurve ()); |
52 | 74 | } |
53 | 75 | |
62 | 84 | { |
63 | 85 | LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateSelect::end"; |
64 | 86 | |
65 | unsetCursorForPoints (); | |
87 | removeHoverHighlighting(); | |
88 | } | |
89 | ||
90 | void DigitizeStateSelect::handleContextMenuEventAxis (CmdMediator *cmdMediator, | |
91 | const QString &pointIdentifier) | |
92 | { | |
93 | LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateSelect::handleContextMenuEventAxis " | |
94 | << " point=" << pointIdentifier.toLatin1 ().data (); | |
95 | ||
96 | QPointF posScreen = cmdMediator->document().positionScreen (pointIdentifier); | |
97 | QPointF posGraphBefore = cmdMediator->document().positionGraph (pointIdentifier); | |
98 | bool isXOnly = cmdMediator->document().isXOnly (pointIdentifier); | |
99 | ||
100 | // Ask user for coordinates | |
101 | double x = posGraphBefore.x(); | |
102 | double y = posGraphBefore.y(); | |
103 | ||
104 | DlgEditPointAxis *dlg = new DlgEditPointAxis (context().mainWindow(), | |
105 | cmdMediator->document().modelCoords(), | |
106 | context().mainWindow().modelMainWindow(), | |
107 | context().mainWindow().transformation(), | |
108 | cmdMediator->document().documentAxesPointsRequired(), | |
109 | isXOnly, | |
110 | &x, | |
111 | &y); | |
112 | int rtn = dlg->exec (); | |
113 | ||
114 | QPointF posGraphAfter = dlg->posGraph (isXOnly); // This call returns new values for isXOnly and the graph position | |
115 | delete dlg; | |
116 | ||
117 | if (rtn == QDialog::Accepted) { | |
118 | ||
119 | // User wants to edit this axis point, but let's perform sanity checks first | |
120 | ||
121 | bool isError; | |
122 | QString errorMessage; | |
123 | ||
124 | context().mainWindow().cmdMediator()->document().checkEditPointAxis(pointIdentifier, | |
125 | posScreen, | |
126 | posGraphAfter, | |
127 | isError, | |
128 | errorMessage); | |
129 | ||
130 | if (isError) { | |
131 | ||
132 | QMessageBox::warning (0, | |
133 | engaugeWindowTitle(), | |
134 | errorMessage); | |
135 | ||
136 | } else { | |
137 | ||
138 | // Create a command to edit the point | |
139 | CmdEditPointAxis *cmd = new CmdEditPointAxis (context().mainWindow(), | |
140 | cmdMediator->document(), | |
141 | pointIdentifier, | |
142 | posGraphBefore, | |
143 | posGraphAfter, | |
144 | isXOnly); | |
145 | context().appendNewCmd(cmdMediator, | |
146 | cmd); | |
147 | } | |
148 | } | |
149 | } | |
150 | ||
151 | void DigitizeStateSelect::handleContextMenuEventGraph (CmdMediator *cmdMediator, | |
152 | const QStringList &pointIdentifiers) | |
153 | { | |
154 | LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateSelect::handleContextMenuEventGraph " | |
155 | << "points=" << pointIdentifiers.join(",").toLatin1 ().data (); | |
156 | ||
157 | double *x = 0, *y = 0; | |
158 | ||
159 | if (pointIdentifiers.count() == 1) { | |
160 | ||
161 | // There is exactly one point so pass its coordinates to the dialog | |
162 | x = new double; | |
163 | y = new double; | |
164 | ||
165 | QPointF posScreenBefore = cmdMediator->document().positionScreen (pointIdentifiers.first()); | |
166 | QPointF posGraphBefore; | |
167 | context().mainWindow().transformation().transformScreenToRawGraph (posScreenBefore, | |
168 | posGraphBefore); | |
169 | ||
170 | // Ask user for coordinates | |
171 | *x = posGraphBefore.x(); | |
172 | *y = posGraphBefore.y(); | |
173 | } | |
174 | ||
175 | DlgEditPointGraph *dlg = new DlgEditPointGraph (context().mainWindow(), | |
176 | cmdMediator->document().modelCoords(), | |
177 | context().mainWindow().modelMainWindow(), | |
178 | context().mainWindow().transformation(), | |
179 | x, | |
180 | y); | |
181 | if (x != 0) { | |
182 | delete x; | |
183 | x = 0; | |
184 | } | |
185 | ||
186 | if (y != 0) { | |
187 | delete y; | |
188 | y = 0; | |
189 | } | |
190 | ||
191 | int rtn = dlg->exec (); | |
192 | ||
193 | bool isXGiven, isYGiven; | |
194 | double xGiven, yGiven; | |
195 | dlg->posGraph (isXGiven, xGiven, isYGiven, yGiven); // One or both coordinates are returned | |
196 | delete dlg; | |
197 | ||
198 | if (rtn == QDialog::Accepted) { | |
199 | ||
200 | // Create a command to edit the point | |
201 | CmdEditPointGraph *cmd = new CmdEditPointGraph (context().mainWindow(), | |
202 | cmdMediator->document(), | |
203 | pointIdentifiers, | |
204 | isXGiven, | |
205 | isYGiven, | |
206 | xGiven, | |
207 | yGiven); | |
208 | context().appendNewCmd(cmdMediator, | |
209 | cmd); | |
210 | } | |
66 | 211 | } |
67 | 212 | |
68 | 213 | void DigitizeStateSelect::handleCurveChange(CmdMediator * /* cmdMediator */) |
173 | 318 | } |
174 | 319 | |
175 | 320 | // Create command to move points |
321 | GraphicsItemsExtractor graphicsItemsExtractor; | |
322 | const QList<QGraphicsItem*> &items = context().mainWindow().scene ().selectedItems(); | |
176 | 323 | CmdMoveBy *cmd = new CmdMoveBy (context().mainWindow(), |
177 | 324 | cmdMediator->document(), |
178 | 325 | deltaScreen, |
179 | 326 | moveText, |
180 | context().mainWindow().scene ().selectedPointIdentifiers ()); | |
327 | graphicsItemsExtractor.selectedPointIdentifiers (items)); | |
181 | 328 | context().appendNewCmd (cmdMediator, |
182 | 329 | cmd); |
183 | 330 | } |
206 | 353 | return moveText; |
207 | 354 | } |
208 | 355 | |
209 | void DigitizeStateSelect::setCursorForPoints() | |
210 | { | |
211 | QCursor cursor (Qt::OpenHandCursor); | |
356 | void DigitizeStateSelect::removeHoverHighlighting() | |
357 | { | |
358 | LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateSelect::removeHoverHighlighting"; | |
212 | 359 | |
213 | 360 | QList<QGraphicsItem*> items = context().mainWindow().scene().items(); |
214 | 361 | QList<QGraphicsItem*>::iterator itr; |
216 | 363 | |
217 | 364 | QGraphicsItem *item = *itr; |
218 | 365 | if (item->data (DATA_KEY_GRAPHICS_ITEM_TYPE) == GRAPHICS_ITEM_TYPE_POINT) { |
219 | item->setCursor (cursor); | |
366 | item->setAcceptHoverEvents(false); | |
220 | 367 | } |
221 | 368 | } |
222 | 369 | } |
223 | 370 | |
224 | QString DigitizeStateSelect::state() const | |
225 | { | |
226 | return "DigitizeStateSelect"; | |
227 | } | |
228 | ||
229 | void DigitizeStateSelect::unsetCursorForPoints() | |
230 | { | |
371 | void DigitizeStateSelect::setHoverHighlighting(const MainWindowModel &modelMainWindow) | |
372 | { | |
373 | LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateSelect::addHoverHighlighting"; | |
374 | ||
375 | // Set the opacity for all points. It should be already set for pre-existing points | |
231 | 376 | QList<QGraphicsItem*> items = context().mainWindow().scene().items(); |
232 | 377 | QList<QGraphicsItem*>::iterator itr; |
233 | 378 | for (itr = items.begin (); itr != items.end (); itr++) { |
234 | 379 | |
235 | 380 | QGraphicsItem *item = *itr; |
236 | 381 | if (item->data (DATA_KEY_GRAPHICS_ITEM_TYPE) == GRAPHICS_ITEM_TYPE_POINT) { |
237 | item->unsetCursor (); | |
382 | item->setOpacity (modelMainWindow.highlightOpacity()); | |
238 | 383 | } |
239 | 384 | } |
385 | } | |
386 | ||
387 | QString DigitizeStateSelect::state() const | |
388 | { | |
389 | return "DigitizeStateSelect"; | |
390 | } | |
391 | ||
392 | void DigitizeStateSelect::updateAfterPointAddition () | |
393 | { | |
394 | LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateSelect::updateAfterPointAddition"; | |
395 | ||
396 | addHoverHighlighting (); | |
240 | 397 | } |
241 | 398 | |
242 | 399 | void DigitizeStateSelect::updateModelDigitizeCurve (CmdMediator * /* cmdMediator */, |
9 | 9 | #include "DigitizeStateAbstractBase.h" |
10 | 10 | |
11 | 11 | /// Digitizing state for selecting one or more Points in the Document. |
12 | /// | |
13 | /// Originally this class set the cursor for each QGraphicsItem at the beginning of the state, but that | |
14 | /// triggered Qt bug 4190 which has the description 'If you have set the cursor for some QGraphicsItems | |
15 | /// you can no longer change the cursor for the view in for example a mouseReleaseEvent'. In turn, that | |
16 | /// lead to Engauge issue #155. Unfortunately, this means the user no longer has need feedback that suggests | |
17 | /// the user can do something with the QGraphicsItems. | |
12 | 18 | class DigitizeStateSelect : public DigitizeStateAbstractBase |
13 | 19 | { |
14 | 20 | public: |
21 | 27 | DigitizeState previousState); |
22 | 28 | virtual QCursor cursor (CmdMediator *cmdMediator) const; |
23 | 29 | virtual void end(); |
30 | virtual void handleContextMenuEventAxis (CmdMediator *cmdMediator, | |
31 | const QString &pointIdentifier); | |
32 | virtual void handleContextMenuEventGraph (CmdMediator *cmdMediator, | |
33 | const QStringList &pointIdentifiers); | |
24 | 34 | virtual void handleCurveChange(CmdMediator *cmdMediator); |
25 | 35 | virtual void handleKeyPress (CmdMediator *cmdMediator, |
26 | 36 | Qt::Key key, |
32 | 42 | virtual void handleMouseRelease (CmdMediator *cmdMediator, |
33 | 43 | QPointF posScreen); |
34 | 44 | virtual QString state() const; |
45 | virtual void updateAfterPointAddition (); | |
35 | 46 | virtual void updateModelDigitizeCurve (CmdMediator *cmdMediator, |
36 | 47 | const DocumentModelDigitizeCurve &modelDigitizeCurve); |
37 | 48 | virtual void updateModelSegments(const DocumentModelSegments &modelSegments); |
39 | 50 | private: |
40 | 51 | DigitizeStateSelect(); |
41 | 52 | |
53 | void addHoverHighlighting(); | |
42 | 54 | void keyPressArrow (CmdMediator *cmdMediator, |
43 | 55 | Qt::Key key); |
44 | 56 | QString moveTextFromDeltaScreen (const QPointF &deltaScreen); |
45 | void setCursorForPoints(); | |
46 | void unsetCursorForPoints(); | |
57 | void removeHoverHighlighting(); | |
58 | void setHoverHighlighting(const MainWindowModel &modelMainWindow); | |
47 | 59 | double zoomedToUnzoomedScreenX () const; |
48 | 60 | double zoomedToUnzoomedScreenY () const; |
49 | 61 |
0 | /****************************************************************************************************** | |
1 | * (C) 2014 markummitchell@github.com. This file is part of Engauge Digitizer, which is released * | |
2 | * under GNU General Public License version 2 (GPLv2) or (at your option) any later version. See file * | |
3 | * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. * | |
4 | ******************************************************************************************************/ | |
5 | ||
6 | #include "DigitizeStateAbstractBase.h" | |
7 | #include "DlgEditPoint.h" | |
8 | #include "DlgValidatorAbstract.h" | |
9 | #include "DlgValidatorFactory.h" | |
10 | #include "DocumentAxesPointsRequired.h" | |
11 | #include "DocumentModelCoords.h" | |
12 | #include "EngaugeAssert.h" | |
13 | #include "FormatCoordsUnits.h" | |
14 | #include "FormatDateTime.h" | |
15 | #include "FormatDegreesMinutesSecondsNonPolarTheta.h" | |
16 | #include "FormatDegreesMinutesSecondsPolarTheta.h" | |
17 | #include "Logger.h" | |
18 | #include "MainWindow.h" | |
19 | #include "MainWindowModel.h" | |
20 | #include <QDoubleValidator> | |
21 | #include <QGridLayout> | |
22 | #include <QGroupBox> | |
23 | #include <QHBoxLayout> | |
24 | #include <QLabel> | |
25 | #include <QRect> | |
26 | #include "QtToString.h" | |
27 | #include <QVBoxLayout> | |
28 | #include "Transformation.h" | |
29 | ||
30 | const Qt::Alignment ALIGNMENT = Qt::AlignCenter; | |
31 | ||
32 | const int MIN_WIDTH_TO_FIT_STRANGE_UNITS = 200; | |
33 | ||
34 | const bool IS_X_THETA = true; | |
35 | const bool IS_NOT_X_THETA = false; | |
36 | ||
37 | DlgEditPoint::DlgEditPoint (MainWindow &mainWindow, | |
38 | DigitizeStateAbstractBase &digitizeState, | |
39 | const DocumentModelCoords &modelCoords, | |
40 | const MainWindowModel &modelMainWindow, | |
41 | const QCursor &cursorShape, | |
42 | const Transformation &transformation, | |
43 | DocumentAxesPointsRequired documentAxesPointsRequired, | |
44 | bool isXOnly, | |
45 | const double *xInitialValue, | |
46 | const double *yInitialValue) : | |
47 | QDialog (&mainWindow), | |
48 | m_cursorShape (cursorShape), | |
49 | m_documentAxesPointsRequired (documentAxesPointsRequired), | |
50 | m_modelCoords (modelCoords), | |
51 | m_modelMainWindow (modelMainWindow) | |
52 | { | |
53 | LOG4CPP_INFO_S ((*mainCat)) << "DlgEditPoint::DlgEditPoint"; | |
54 | ||
55 | // Either one or two coordinates are desired | |
56 | bool isX = (documentAxesPointsRequired == DOCUMENT_AXES_POINTS_REQUIRED_3) || isXOnly; | |
57 | bool isY = (documentAxesPointsRequired == DOCUMENT_AXES_POINTS_REQUIRED_3) || !isXOnly; | |
58 | ||
59 | // To guarantee the override cursor is always removed, we call removeOverrideCursor here rather than in the code that | |
60 | // allocates this DlgEditPoint. The digitizeState argument is otherwise unused. | |
61 | digitizeState.removeOverrideCursor(); | |
62 | ||
63 | connect (this, SIGNAL (signalSetOverrideCursor (QCursor)), &mainWindow, SLOT (slotSetOverrideCursor (QCursor))); | |
64 | ||
65 | QVBoxLayout *layout = new QVBoxLayout; | |
66 | setLayout (layout); | |
67 | ||
68 | setCursor (QCursor (Qt::ArrowCursor)); | |
69 | setModal(true); | |
70 | setWindowTitle (tr ("Edit Axis Point")); | |
71 | ||
72 | createCoords (layout); | |
73 | createHint (layout); | |
74 | createOkCancel (layout); | |
75 | ||
76 | initializeGraphCoordinates (xInitialValue, | |
77 | yInitialValue, | |
78 | transformation, | |
79 | isX, | |
80 | isY); | |
81 | ||
82 | updateControls (); | |
83 | } | |
84 | ||
85 | DlgEditPoint::~DlgEditPoint() | |
86 | { | |
87 | LOG4CPP_INFO_S ((*mainCat)) << "DlgEditPoint::~DlgEditPoint"; | |
88 | ||
89 | emit signalSetOverrideCursor (m_cursorShape); | |
90 | } | |
91 | ||
92 | void DlgEditPoint::createCoords (QVBoxLayout *layoutOuter) | |
93 | { | |
94 | // Constraints on x and y are needed for log scaling | |
95 | bool isConstraintX = (m_modelCoords.coordScaleXTheta() == COORD_SCALE_LOG); | |
96 | bool isConstraintY = (m_modelCoords.coordScaleYRadius() == COORD_SCALE_LOG); | |
97 | DlgValidatorFactory dlgValidatorFactory; | |
98 | m_validatorGraphX = dlgValidatorFactory.createCartesianOrPolarWithPolarPolar (m_modelCoords.coordScaleXTheta(), | |
99 | isCartesian (), | |
100 | m_modelCoords.coordUnitsX(), | |
101 | m_modelCoords.coordUnitsTheta(), | |
102 | m_modelCoords.coordUnitsDate(), | |
103 | m_modelCoords.coordUnitsTime(), | |
104 | m_modelMainWindow.locale()); | |
105 | m_validatorGraphY = dlgValidatorFactory.createCartesianOrPolarWithNonPolarPolar (m_modelCoords.coordScaleYRadius(), | |
106 | isCartesian (), | |
107 | m_modelCoords.coordUnitsY(), | |
108 | m_modelCoords.coordUnitsRadius(), | |
109 | m_modelCoords.coordUnitsDate(), | |
110 | m_modelCoords.coordUnitsTime(), | |
111 | m_modelMainWindow.locale()); | |
112 | ||
113 | // Label, with guidance in terms of legal ranges and units | |
114 | QString description = QString ("%1 (%2, %3)%4%5%6%7%8%9 %10 (%11, %12):") | |
115 | .arg (tr ("Graph Coordinates")) | |
116 | .arg (nameXTheta ()) | |
117 | .arg (nameYRadius ()) | |
118 | .arg (isConstraintX || isConstraintY ? " with " : "") | |
119 | .arg (isConstraintX ? QString (nameXTheta ()) : "") | |
120 | .arg (isConstraintX ? " > 0" : "") | |
121 | .arg (isConstraintX && isConstraintY ? " and " : "") | |
122 | .arg ( isConstraintY ? QString (nameYRadius ()) : "") | |
123 | .arg ( isConstraintY ? " > 0" : "") | |
124 | .arg (tr ("as")) | |
125 | .arg (unitsType (IS_X_THETA)) | |
126 | .arg (unitsType (IS_NOT_X_THETA)); | |
127 | QGroupBox *panel = new QGroupBox (description, this); | |
128 | layoutOuter->addWidget (panel); | |
129 | ||
130 | QHBoxLayout *layout = new QHBoxLayout (panel); | |
131 | panel->setLayout (layout); | |
132 | ||
133 | // Row | |
134 | QLabel *labelGraphParLeft = new QLabel (tr ("("), this); | |
135 | layout->addWidget(labelGraphParLeft, 0); | |
136 | ||
137 | m_editGraphX = new QLineEdit; | |
138 | m_editGraphX->setMinimumWidth(MIN_WIDTH_TO_FIT_STRANGE_UNITS); | |
139 | m_editGraphX->setAlignment (ALIGNMENT); | |
140 | m_editGraphX->setValidator (m_validatorGraphX); | |
141 | // setStatusTip does not work for modal dialogs | |
142 | m_editGraphX->setWhatsThis (tr ("Enter the first graph coordinate of the axis point.\n\n" | |
143 | "For cartesian plots this is X. For polar plots this is the radius R.\n\n" | |
144 | "The expected format of the coordinate value is determined by the locale setting. If " | |
145 | "typed values are not recognized as expected, check the locale setting in Settings / Main Window...")); | |
146 | layout->addWidget(m_editGraphX, 0); | |
147 | connect (m_editGraphX, SIGNAL (textChanged (const QString &)), this, SLOT (slotTextChanged (const QString &))); | |
148 | ||
149 | QLabel *labelGraphComma = new QLabel (tr (", "), this); | |
150 | layout->addWidget(labelGraphComma, 0); | |
151 | ||
152 | m_editGraphY = new QLineEdit; | |
153 | m_editGraphY->setMinimumWidth(MIN_WIDTH_TO_FIT_STRANGE_UNITS); | |
154 | m_editGraphY->setAlignment (ALIGNMENT); | |
155 | m_editGraphY->setValidator (m_validatorGraphY); | |
156 | // setStatusTip does not work for modal dialogs | |
157 | m_editGraphY->setWhatsThis (tr ("Enter the second graph coordinate of the axis point.\n\n" | |
158 | "For cartesian plots this is Y. For plot plots this is the angle Theta.\n\n" | |
159 | "The expected format of the coordinate value is determined by the locale setting. If " | |
160 | "typed values are not recognized as expected, check the locale setting in Settings / Main Window...")); | |
161 | layout->addWidget(m_editGraphY, 0); | |
162 | connect (m_editGraphY, SIGNAL (textChanged (const QString &)), this, SLOT (slotTextChanged (const QString &))); | |
163 | ||
164 | QLabel *labelGraphParRight = new QLabel (tr (")"), this); | |
165 | layout->addWidget(labelGraphParRight, 0); | |
166 | } | |
167 | ||
168 | void DlgEditPoint::createHint (QVBoxLayout *layoutOuter) | |
169 | { | |
170 | // Insert a hint explaining why decimal points may not be accepted. Very confusing for user to figure out the problem at first, and | |
171 | // then figure out which setting should change to fix it. The hint is centered so it is slightly less intrusive | |
172 | ||
173 | QWidget *widget = new QWidget; | |
174 | layoutOuter->addWidget (widget, 0, Qt::AlignCenter); | |
175 | ||
176 | QHBoxLayout *layout = new QHBoxLayout; | |
177 | widget->setLayout (layout); | |
178 | ||
179 | QString locale = QLocaleToString (m_modelMainWindow.locale ()); | |
180 | QString hint = QString ("%1: %2") | |
181 | .arg (tr ("Number format")) | |
182 | .arg (locale); | |
183 | QLabel *label = new QLabel (hint); | |
184 | layout->addWidget (label); | |
185 | } | |
186 | ||
187 | void DlgEditPoint::createOkCancel (QVBoxLayout *layoutOuter) | |
188 | { | |
189 | QWidget *panel = new QWidget (this); | |
190 | layoutOuter->addWidget (panel, 0, Qt::AlignCenter); | |
191 | ||
192 | QHBoxLayout *layout = new QHBoxLayout (panel); | |
193 | panel->setLayout (layout); | |
194 | ||
195 | m_btnOk = new QPushButton (tr ("Ok"), this); | |
196 | layout->addWidget(m_btnOk); | |
197 | connect (m_btnOk, SIGNAL (released ()), this, SLOT (accept ())); | |
198 | ||
199 | m_btnCancel = new QPushButton (tr ("Cancel"), this); | |
200 | layout->addWidget(m_btnCancel); | |
201 | connect (m_btnCancel, SIGNAL (released ()), this, SLOT (reject ())); | |
202 | } | |
203 | ||
204 | void DlgEditPoint::initializeGraphCoordinates (const double *xInitialValue, | |
205 | const double *yInitialValue, | |
206 | const Transformation &transformation, | |
207 | bool isX, | |
208 | bool isY) | |
209 | { | |
210 | LOG4CPP_INFO_S ((*mainCat)) << "DlgEditPoint::initializeGraphCoordinates"; | |
211 | ||
212 | QString xTheta, yRadius; | |
213 | if ((xInitialValue != 0) && | |
214 | (yInitialValue != 0)) { | |
215 | ||
216 | FormatCoordsUnits format; | |
217 | format.unformattedToFormatted (*xInitialValue, | |
218 | *yInitialValue, | |
219 | m_modelCoords, | |
220 | m_modelMainWindow, | |
221 | xTheta, | |
222 | yRadius, | |
223 | transformation); | |
224 | } | |
225 | ||
226 | if (isX) { | |
227 | m_editGraphX->setText (xTheta); | |
228 | } else { | |
229 | m_editGraphX->setText (""); | |
230 | } | |
231 | ||
232 | if (isY) { | |
233 | m_editGraphY->setText (yRadius); | |
234 | } else { | |
235 | m_editGraphY->setText (""); | |
236 | } | |
237 | } | |
238 | ||
239 | bool DlgEditPoint::isCartesian () const | |
240 | { | |
241 | return (m_modelCoords.coordsType() == COORDS_TYPE_CARTESIAN); | |
242 | } | |
243 | ||
244 | QChar DlgEditPoint::nameXTheta () const | |
245 | { | |
246 | return (isCartesian () ? QChar ('X') : THETA); | |
247 | } | |
248 | ||
249 | QChar DlgEditPoint::nameYRadius () const | |
250 | { | |
251 | return (isCartesian () ? QChar ('Y') : QChar ('R')); | |
252 | } | |
253 | ||
254 | QPointF DlgEditPoint::posGraph (bool &isXOnly) const | |
255 | { | |
256 | double xTheta, yRadius; | |
257 | ||
258 | FormatCoordsUnits format; | |
259 | ||
260 | format.formattedToUnformatted (m_editGraphX->text(), | |
261 | m_editGraphY->text(), | |
262 | m_modelCoords, | |
263 | m_modelMainWindow, | |
264 | xTheta, | |
265 | yRadius); | |
266 | ||
267 | // If yRadius value is empty then this is the xTheta value only | |
268 | isXOnly = m_editGraphY->text().isEmpty(); | |
269 | ||
270 | return QPointF (xTheta, | |
271 | yRadius); | |
272 | } | |
273 | ||
274 | void DlgEditPoint::slotTextChanged (const QString &) | |
275 | { | |
276 | updateControls (); | |
277 | } | |
278 | ||
279 | QString DlgEditPoint::unitsType (bool isXTheta) const | |
280 | { | |
281 | if (isCartesian ()) { | |
282 | if (isXTheta) { | |
283 | return coordUnitsNonPolarThetaToBriefType (m_modelCoords.coordUnitsX()); | |
284 | } else { | |
285 | return coordUnitsNonPolarThetaToBriefType (m_modelCoords.coordUnitsY()); | |
286 | } | |
287 | } else { | |
288 | if (isXTheta) { | |
289 | return coordUnitsPolarThetaToBriefType (m_modelCoords.coordUnitsTheta()); | |
290 | } else { | |
291 | return coordUnitsNonPolarThetaToBriefType (m_modelCoords.coordUnitsRadius()); | |
292 | } | |
293 | } | |
294 | } | |
295 | ||
296 | void DlgEditPoint::updateControls () | |
297 | { | |
298 | QString textX = m_editGraphX->text(); | |
299 | QString textY = m_editGraphY->text(); | |
300 | ||
301 | int posX, posY; | |
302 | ||
303 | if (m_documentAxesPointsRequired == DOCUMENT_AXES_POINTS_REQUIRED_4) { | |
304 | ||
305 | bool gotX = (!textX.isEmpty() && | |
306 | (m_validatorGraphX->validate(textX, posX) == QValidator::Acceptable)); | |
307 | bool gotY = (!textY.isEmpty() && | |
308 | (m_validatorGraphY->validate(textY, posY) == QValidator::Acceptable)); | |
309 | ||
310 | // Check for not empty in one coordinate and for valid number in the other coordinate | |
311 | m_btnOk->setEnabled ((textX.isEmpty() && gotY) || | |
312 | (textY.isEmpty() && gotX)); | |
313 | ||
314 | } else { | |
315 | ||
316 | // Check for not empty (which allows single minus sign) and for valid number (which prevents single minus sign) | |
317 | m_btnOk->setEnabled (!textX.isEmpty () && | |
318 | !textY.isEmpty () && | |
319 | (m_validatorGraphX->validate(textX, posX) == QValidator::Acceptable) && | |
320 | (m_validatorGraphY->validate(textY, posY) == QValidator::Acceptable)); | |
321 | ||
322 | } | |
323 | } |
0 | /****************************************************************************************************** | |
1 | * (C) 2014 markummitchell@github.com. This file is part of Engauge Digitizer, which is released * | |
2 | * under GNU General Public License version 2 (GPLv2) or (at your option) any later version. See file * | |
3 | * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. * | |
4 | ******************************************************************************************************/ | |
5 | ||
6 | #ifndef DLG_EDIT_POINT_H | |
7 | #define DLG_EDIT_POINT_H | |
8 | ||
9 | #include "CoordUnitsDate.h" | |
10 | #include "CoordUnitsNonPolarTheta.h" | |
11 | #include "CoordUnitsPolarTheta.h" | |
12 | #include "CoordUnitsTime.h" | |
13 | #include "DocumentAxesPointsRequired.h" | |
14 | #include <QCursor> | |
15 | #include <QDialog> | |
16 | #include <QLineEdit> | |
17 | #include <QPushButton> | |
18 | ||
19 | class DigitizeStateAbstractBase; | |
20 | class DlgValidatorAbstract; | |
21 | class DocumentModelCoords; | |
22 | class MainWindow; | |
23 | class MainWindowModel; | |
24 | class QDoubleValidator; | |
25 | class QVBoxLayout; | |
26 | class Transformation; | |
27 | ||
28 | /// Dialog box for editing the information of one axis point. | |
29 | class DlgEditPoint : public QDialog | |
30 | { | |
31 | Q_OBJECT; | |
32 | ||
33 | public: | |
34 | /// Constructor for existing point which already has graph coordinates (which may be changed using this dialog). | |
35 | /// If initial values are unspecified then the value fields will be initially empty | |
36 | DlgEditPoint (MainWindow &mainWindow, | |
37 | DigitizeStateAbstractBase &digitizeState, | |
38 | const DocumentModelCoords &modelCoords, | |
39 | const MainWindowModel &modelMainWindow, | |
40 | const QCursor &cursorShape, | |
41 | const Transformation &transformation, | |
42 | DocumentAxesPointsRequired documentAxesPointsRequired, | |
43 | bool isXOnly = false, | |
44 | const double *xInitialValue = 0, | |
45 | const double *yInitialValue = 0); | |
46 | ~DlgEditPoint (); | |
47 | ||
48 | /// Return the graph coordinates position specified by the user. Only applies if dialog was accepted | |
49 | QPointF posGraph (bool &isXOnly) const; | |
50 | ||
51 | signals: | |
52 | /// Send a signal to trigger the setting of the override cursor. | |
53 | void signalSetOverrideCursor (QCursor); | |
54 | ||
55 | private slots: | |
56 | void slotTextChanged (const QString &); | |
57 | ||
58 | private: | |
59 | void createCoords (QVBoxLayout *layoutOuter); | |
60 | void createHint (QVBoxLayout *layoutOuter); | |
61 | void createOkCancel (QVBoxLayout *layoutOuter); | |
62 | void initializeGraphCoordinates (const double *xInitialValue, | |
63 | const double *yInitialValue, | |
64 | const Transformation &transformation, | |
65 | bool isX, | |
66 | bool isY); | |
67 | bool isCartesian () const; | |
68 | QChar nameXTheta () const; | |
69 | QChar nameYRadius () const; | |
70 | QString unitsType (bool isXTheta) const; | |
71 | void updateControls (); | |
72 | ||
73 | QCursor m_cursorShape; | |
74 | QLineEdit *m_editGraphX; | |
75 | DlgValidatorAbstract *m_validatorGraphX; | |
76 | QLineEdit *m_editGraphY; | |
77 | DlgValidatorAbstract *m_validatorGraphY; | |
78 | QPushButton *m_btnOk; | |
79 | QPushButton *m_btnCancel; | |
80 | ||
81 | DocumentAxesPointsRequired m_documentAxesPointsRequired; | |
82 | ||
83 | const DocumentModelCoords &m_modelCoords; | |
84 | const MainWindowModel &m_modelMainWindow; | |
85 | }; | |
86 | ||
87 | #endif // DLG_EDIT_POINT_H |
0 | /****************************************************************************************************** | |
1 | * (C) 2014 markummitchell@github.com. This file is part of Engauge Digitizer, which is released * | |
2 | * under GNU General Public License version 2 (GPLv2) or (at your option) any later version. See file * | |
3 | * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. * | |
4 | ******************************************************************************************************/ | |
5 | ||
6 | #include "DlgEditPointAxis.h" | |
7 | #include "DlgValidatorAbstract.h" | |
8 | #include "DlgValidatorFactory.h" | |
9 | #include "DocumentAxesPointsRequired.h" | |
10 | #include "DocumentModelCoords.h" | |
11 | #include "EngaugeAssert.h" | |
12 | #include "FormatCoordsUnits.h" | |
13 | #include "FormatDateTime.h" | |
14 | #include "FormatDegreesMinutesSecondsNonPolarTheta.h" | |
15 | #include "FormatDegreesMinutesSecondsPolarTheta.h" | |
16 | #include "Logger.h" | |
17 | #include "MainWindow.h" | |
18 | #include "MainWindowModel.h" | |
19 | #include <QDoubleValidator> | |
20 | #include <QGridLayout> | |
21 | #include <QGroupBox> | |
22 | #include <QHBoxLayout> | |
23 | #include <QLabel> | |
24 | #include <QRect> | |
25 | #include "QtToString.h" | |
26 | #include <QVBoxLayout> | |
27 | #include "Transformation.h" | |
28 | ||
29 | const Qt::Alignment ALIGNMENT = Qt::AlignCenter; | |
30 | ||
31 | const int MIN_WIDTH_TO_FIT_STRANGE_UNITS = 200; | |
32 | ||
33 | const bool IS_X_THETA = true; | |
34 | const bool IS_NOT_X_THETA = false; | |
35 | ||
36 | DlgEditPointAxis::DlgEditPointAxis (MainWindow &mainWindow, | |
37 | const DocumentModelCoords &modelCoords, | |
38 | const MainWindowModel &modelMainWindow, | |
39 | const Transformation &transformation, | |
40 | DocumentAxesPointsRequired documentAxesPointsRequired, | |
41 | bool isXOnly, | |
42 | const double *xInitialValue, | |
43 | const double *yInitialValue) : | |
44 | QDialog (&mainWindow), | |
45 | m_documentAxesPointsRequired (documentAxesPointsRequired), | |
46 | m_modelCoords (modelCoords), | |
47 | m_modelMainWindow (modelMainWindow) | |
48 | { | |
49 | LOG4CPP_INFO_S ((*mainCat)) << "DlgEditPointAxis::DlgEditPointAxis"; | |
50 | ||
51 | // Either one or two coordinates are desired | |
52 | bool isX = (documentAxesPointsRequired == DOCUMENT_AXES_POINTS_REQUIRED_3) || isXOnly; | |
53 | bool isY = (documentAxesPointsRequired == DOCUMENT_AXES_POINTS_REQUIRED_3) || !isXOnly; | |
54 | ||
55 | QVBoxLayout *layout = new QVBoxLayout; | |
56 | setLayout (layout); | |
57 | ||
58 | setCursor (QCursor (Qt::ArrowCursor)); | |
59 | setModal(true); | |
60 | setWindowTitle (tr ("Edit Axis Point")); | |
61 | ||
62 | createCoords (layout); | |
63 | createHint (layout); | |
64 | createOkCancel (layout); | |
65 | ||
66 | initializeGraphCoordinates (xInitialValue, | |
67 | yInitialValue, | |
68 | transformation, | |
69 | isX, | |
70 | isY); | |
71 | ||
72 | updateControls (); | |
73 | } | |
74 | ||
75 | DlgEditPointAxis::~DlgEditPointAxis() | |
76 | { | |
77 | LOG4CPP_INFO_S ((*mainCat)) << "DlgEditPointAxis::~DlgEditPointAxis"; | |
78 | } | |
79 | ||
80 | void DlgEditPointAxis::createCoords (QVBoxLayout *layoutOuter) | |
81 | { | |
82 | // Constraints on x and y are needed for log scaling | |
83 | bool isConstraintX = (m_modelCoords.coordScaleXTheta() == COORD_SCALE_LOG); | |
84 | bool isConstraintY = (m_modelCoords.coordScaleYRadius() == COORD_SCALE_LOG); | |
85 | DlgValidatorFactory dlgValidatorFactory; | |
86 | m_validatorGraphX = dlgValidatorFactory.createCartesianOrPolarWithPolarPolar (m_modelCoords.coordScaleXTheta(), | |
87 | isCartesian (), | |
88 | m_modelCoords.coordUnitsX(), | |
89 | m_modelCoords.coordUnitsTheta(), | |
90 | m_modelCoords.coordUnitsDate(), | |
91 | m_modelCoords.coordUnitsTime(), | |
92 | m_modelMainWindow.locale()); | |
93 | m_validatorGraphY = dlgValidatorFactory.createCartesianOrPolarWithNonPolarPolar (m_modelCoords.coordScaleYRadius(), | |
94 | isCartesian (), | |
95 | m_modelCoords.coordUnitsY(), | |
96 | m_modelCoords.coordUnitsRadius(), | |
97 | m_modelCoords.coordUnitsDate(), | |
98 | m_modelCoords.coordUnitsTime(), | |
99 | m_modelMainWindow.locale()); | |
100 | ||
101 | // Label, with guidance in terms of legal ranges and units | |
102 | QString description = QString ("%1 (%2, %3)%4%5%6%7%8%9 %10 (%11, %12):") | |
103 | .arg (tr ("Graph Coordinates")) | |
104 | .arg (nameXTheta ()) | |
105 | .arg (nameYRadius ()) | |
106 | .arg (isConstraintX || isConstraintY ? " with " : "") | |
107 | .arg (isConstraintX ? QString (nameXTheta ()) : "") | |
108 | .arg (isConstraintX ? " > 0" : "") | |
109 | .arg (isConstraintX && isConstraintY ? " and " : "") | |
110 | .arg ( isConstraintY ? QString (nameYRadius ()) : "") | |
111 | .arg ( isConstraintY ? " > 0" : "") | |
112 | .arg (tr ("as")) | |
113 | .arg (unitsType (IS_X_THETA)) | |
114 | .arg (unitsType (IS_NOT_X_THETA)); | |
115 | QGroupBox *panel = new QGroupBox (description, this); | |
116 | layoutOuter->addWidget (panel); | |
117 | ||
118 | QHBoxLayout *layout = new QHBoxLayout (panel); | |
119 | panel->setLayout (layout); | |
120 | ||
121 | // Row | |
122 | QLabel *labelGraphParLeft = new QLabel (tr ("("), this); | |
123 | layout->addWidget(labelGraphParLeft, 0); | |
124 | ||
125 | m_editGraphX = new QLineEdit; | |
126 | m_editGraphX->setMinimumWidth(MIN_WIDTH_TO_FIT_STRANGE_UNITS); | |
127 | m_editGraphX->setAlignment (ALIGNMENT); | |
128 | m_editGraphX->setValidator (m_validatorGraphX); | |
129 | // setStatusTip does not work for modal dialogs | |
130 | m_editGraphX->setWhatsThis (tr ("Enter the first graph coordinate of the axis point.\n\n" | |
131 | "For cartesian plots this is X. For polar plots this is the radius R.\n\n" | |
132 | "The expected format of the coordinate value is determined by the locale setting. If " | |
133 | "typed values are not recognized as expected, check the locale setting in Settings / Main Window...")); | |
134 | layout->addWidget(m_editGraphX, 0); | |
135 | connect (m_editGraphX, SIGNAL (textChanged (const QString &)), this, SLOT (slotTextChanged (const QString &))); | |
136 | ||
137 | QLabel *labelGraphComma = new QLabel (tr (", "), this); | |
138 | layout->addWidget(labelGraphComma, 0); | |
139 | ||
140 | m_editGraphY = new QLineEdit; | |
141 | m_editGraphY->setMinimumWidth(MIN_WIDTH_TO_FIT_STRANGE_UNITS); | |
142 | m_editGraphY->setAlignment (ALIGNMENT); | |
143 | m_editGraphY->setValidator (m_validatorGraphY); | |
144 | // setStatusTip does not work for modal dialogs | |
145 | m_editGraphY->setWhatsThis (tr ("Enter the second graph coordinate of the axis point.\n\n" | |
146 | "For cartesian plots this is Y. For plot plots this is the angle Theta.\n\n" | |
147 | "The expected format of the coordinate value is determined by the locale setting. If " | |
148 | "typed values are not recognized as expected, check the locale setting in Settings / Main Window...")); | |
149 | layout->addWidget(m_editGraphY, 0); | |
150 | connect (m_editGraphY, SIGNAL (textChanged (const QString &)), this, SLOT (slotTextChanged (const QString &))); | |
151 | ||
152 | QLabel *labelGraphParRight = new QLabel (tr (")"), this); | |
153 | layout->addWidget(labelGraphParRight, 0); | |
154 | } | |
155 | ||
156 | void DlgEditPointAxis::createHint (QVBoxLayout *layoutOuter) | |
157 | { | |
158 | // Insert a hint explaining why decimal points may not be accepted. Very confusing for user to figure out the problem at first, and | |
159 | // then figure out which setting should change to fix it. The hint is centered so it is slightly less intrusive | |
160 | ||
161 | QWidget *widget = new QWidget; | |
162 | layoutOuter->addWidget (widget, 0, Qt::AlignCenter); | |
163 | ||
164 | QHBoxLayout *layout = new QHBoxLayout; | |
165 | widget->setLayout (layout); | |
166 | ||
167 | QString locale = QLocaleToString (m_modelMainWindow.locale ()); | |
168 | QString hint = QString ("%1: %2") | |
169 | .arg (tr ("Number format")) | |
170 | .arg (locale); | |
171 | QLabel *label = new QLabel (hint); | |
172 | layout->addWidget (label); | |
173 | } | |
174 | ||
175 | void DlgEditPointAxis::createOkCancel (QVBoxLayout *layoutOuter) | |
176 | { | |
177 | QWidget *panel = new QWidget (this); | |
178 | layoutOuter->addWidget (panel, 0, Qt::AlignCenter); | |
179 | ||
180 | QHBoxLayout *layout = new QHBoxLayout (panel); | |
181 | panel->setLayout (layout); | |
182 | ||
183 | m_btnOk = new QPushButton (tr ("Ok"), this); | |
184 | layout->addWidget(m_btnOk); | |
185 | connect (m_btnOk, SIGNAL (released ()), this, SLOT (accept ())); | |
186 | ||
187 | m_btnCancel = new QPushButton (tr ("Cancel"), this); | |
188 | layout->addWidget(m_btnCancel); | |
189 | connect (m_btnCancel, SIGNAL (released ()), this, SLOT (reject ())); | |
190 | } | |
191 | ||
192 | void DlgEditPointAxis::initializeGraphCoordinates (const double *xInitialValue, | |
193 | const double *yInitialValue, | |
194 | const Transformation &transformation, | |
195 | bool isX, | |
196 | bool isY) | |
197 | { | |
198 | LOG4CPP_INFO_S ((*mainCat)) << "DlgEditPointAxis::initializeGraphCoordinates"; | |
199 | ||
200 | QString xTheta, yRadius; | |
201 | if ((xInitialValue != 0) && | |
202 | (yInitialValue != 0)) { | |
203 | ||
204 | FormatCoordsUnits format; | |
205 | format.unformattedToFormatted (*xInitialValue, | |
206 | *yInitialValue, | |
207 | m_modelCoords, | |
208 | m_modelMainWindow, | |
209 | xTheta, | |
210 | yRadius, | |
211 | transformation); | |
212 | } | |
213 | ||
214 | if (isX) { | |
215 | m_editGraphX->setText (xTheta); | |
216 | } else { | |
217 | m_editGraphX->setText (""); | |
218 | } | |
219 | ||
220 | if (isY) { | |
221 | m_editGraphY->setText (yRadius); | |
222 | } else { | |
223 | m_editGraphY->setText (""); | |
224 | } | |
225 | } | |
226 | ||
227 | bool DlgEditPointAxis::isCartesian () const | |
228 | { | |
229 | return (m_modelCoords.coordsType() == COORDS_TYPE_CARTESIAN); | |
230 | } | |
231 | ||
232 | QChar DlgEditPointAxis::nameXTheta () const | |
233 | { | |
234 | return (isCartesian () ? QChar ('X') : THETA); | |
235 | } | |
236 | ||
237 | QChar DlgEditPointAxis::nameYRadius () const | |
238 | { | |
239 | return (isCartesian () ? QChar ('Y') : QChar ('R')); | |
240 | } | |
241 | ||
242 | QPointF DlgEditPointAxis::posGraph (bool &isXOnly) const | |
243 | { | |
244 | double xTheta, yRadius; | |
245 | ||
246 | FormatCoordsUnits format; | |
247 | ||
248 | format.formattedToUnformatted (m_editGraphX->text(), | |
249 | m_editGraphY->text(), | |
250 | m_modelCoords, | |
251 | m_modelMainWindow, | |
252 | xTheta, | |
253 | yRadius); | |
254 | ||
255 | // If yRadius value is empty then this is the xTheta value only | |
256 | isXOnly = m_editGraphY->text().isEmpty(); | |
257 | ||
258 | return QPointF (xTheta, | |
259 | yRadius); | |
260 | } | |
261 | ||
262 | void DlgEditPointAxis::slotTextChanged (const QString &) | |
263 | { | |
264 | updateControls (); | |
265 | } | |
266 | ||
267 | QString DlgEditPointAxis::unitsType (bool isXTheta) const | |
268 | { | |
269 | if (isCartesian ()) { | |
270 | if (isXTheta) { | |
271 | return coordUnitsNonPolarThetaToBriefType (m_modelCoords.coordUnitsX()); | |
272 | } else { | |
273 | return coordUnitsNonPolarThetaToBriefType (m_modelCoords.coordUnitsY()); | |
274 | } | |
275 | } else { | |
276 | if (isXTheta) { | |
277 | return coordUnitsPolarThetaToBriefType (m_modelCoords.coordUnitsTheta()); | |
278 | } else { | |
279 | return coordUnitsNonPolarThetaToBriefType (m_modelCoords.coordUnitsRadius()); | |
280 | } | |
281 | } | |
282 | } | |
283 | ||
284 | void DlgEditPointAxis::updateControls () | |
285 | { | |
286 | QString textX = m_editGraphX->text(); | |
287 | QString textY = m_editGraphY->text(); | |
288 | ||
289 | int posX, posY; | |
290 | ||
291 | if (m_documentAxesPointsRequired == DOCUMENT_AXES_POINTS_REQUIRED_4) { | |
292 | ||
293 | bool gotX = (!textX.isEmpty() && | |
294 | (m_validatorGraphX->validate(textX, posX) == QValidator::Acceptable)); | |
295 | bool gotY = (!textY.isEmpty() && | |
296 | (m_validatorGraphY->validate(textY, posY) == QValidator::Acceptable)); | |
297 | ||
298 | // Check for not empty in one coordinate and for valid number in the other coordinate | |
299 | m_btnOk->setEnabled ((textX.isEmpty() && gotY) || | |
300 | (textY.isEmpty() && gotX)); | |
301 | ||
302 | } else { | |
303 | ||
304 | // Check for not empty (which allows single minus sign) and for valid number (which prevents single minus sign) | |
305 | m_btnOk->setEnabled (!textX.isEmpty () && | |
306 | !textY.isEmpty () && | |
307 | (m_validatorGraphX->validate(textX, posX) == QValidator::Acceptable) && | |
308 | (m_validatorGraphY->validate(textY, posY) == QValidator::Acceptable)); | |
309 | ||
310 | } | |
311 | } |
0 | /****************************************************************************************************** | |
1 | * (C) 2014 markummitchell@github.com. This file is part of Engauge Digitizer, which is released * | |
2 | * under GNU General Public License version 2 (GPLv2) or (at your option) any later version. See file * | |
3 | * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. * | |
4 | ******************************************************************************************************/ | |
5 | ||
6 | #ifndef DLG_EDIT_POINT_AXIS_H | |
7 | #define DLG_EDIT_POINT_AXIS_H | |
8 | ||
9 | #include "DocumentAxesPointsRequired.h" | |
10 | #include <QDialog> | |
11 | #include <QLineEdit> | |
12 | #include <QPushButton> | |
13 | ||
14 | class DlgValidatorAbstract; | |
15 | class DocumentModelCoords; | |
16 | class MainWindow; | |
17 | class MainWindowModel; | |
18 | class QDoubleValidator; | |
19 | class QVBoxLayout; | |
20 | class Transformation; | |
21 | ||
22 | /// Dialog box for editing the information of one axis point. | |
23 | class DlgEditPointAxis : public QDialog | |
24 | { | |
25 | Q_OBJECT; | |
26 | ||
27 | public: | |
28 | /// Constructor for existing point which already has graph coordinates (which may be changed using this dialog). | |
29 | /// If initial values are unspecified then the value fields will be initially empty | |
30 | DlgEditPointAxis (MainWindow &mainWindow, | |
31 | const DocumentModelCoords &modelCoords, | |
32 | const MainWindowModel &modelMainWindow, | |
33 | const Transformation &transformation, | |
34 | DocumentAxesPointsRequired documentAxesPointsRequired, | |
35 | bool isXOnly = false, | |
36 | const double *xInitialValue = 0, | |
37 | const double *yInitialValue = 0); | |
38 | ~DlgEditPointAxis (); | |
39 | ||
40 | /// Return the graph coordinates position specified by the user. Only applies if dialog was accepted | |
41 | QPointF posGraph (bool &isXOnly) const; | |
42 | ||
43 | private slots: | |
44 | void slotTextChanged (const QString &); | |
45 | ||
46 | private: | |
47 | void createCoords (QVBoxLayout *layoutOuter); | |
48 | void createHint (QVBoxLayout *layoutOuter); | |
49 | void createOkCancel (QVBoxLayout *layoutOuter); | |
50 | void initializeGraphCoordinates (const double *xInitialValue, | |
51 | const double *yInitialValue, | |
52 | const Transformation &transformation, | |
53 | bool isX, | |
54 | bool isY); | |
55 | bool isCartesian () const; | |
56 | QChar nameXTheta () const; | |
57 | QChar nameYRadius () const; | |
58 | QString unitsType (bool isXTheta) const; | |
59 | void updateControls (); | |
60 | ||
61 | QLineEdit *m_editGraphX; | |
62 | DlgValidatorAbstract *m_validatorGraphX; | |
63 | QLineEdit *m_editGraphY; | |
64 | DlgValidatorAbstract *m_validatorGraphY; | |
65 | QPushButton *m_btnOk; | |
66 | QPushButton *m_btnCancel; | |
67 | ||
68 | DocumentAxesPointsRequired m_documentAxesPointsRequired; | |
69 | ||
70 | const DocumentModelCoords &m_modelCoords; | |
71 | const MainWindowModel &m_modelMainWindow; | |
72 | }; | |
73 | ||
74 | #endif // DLG_EDIT_POINT_AXIS_H |
0 | /****************************************************************************************************** | |
1 | * (C) 2016 markummitchell@github.com. This file is part of Engauge Digitizer, which is released * | |
2 | * under GNU General Public License version 2 (GPLv2) or (at your option) any later version. See file * | |
3 | * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. * | |
4 | ******************************************************************************************************/ | |
5 | ||
6 | #include "DlgEditPointGraph.h" | |
7 | #include "DlgEditPointGraphLineEdit.h" | |
8 | #include "DlgValidatorAbstract.h" | |
9 | #include "DlgValidatorFactory.h" | |
10 | #include "DocumentModelCoords.h" | |
11 | #include "FormatCoordsUnits.h" | |
12 | #include "Logger.h" | |
13 | #include "MainWindow.h" | |
14 | #include "MainWindowModel.h" | |
15 | #include <QGroupBox> | |
16 | #include <QLabel> | |
17 | #include <QPushButton> | |
18 | #include "QtToString.h" | |
19 | #include <QVBoxLayout> | |
20 | #include "Transformation.h" | |
21 | ||
22 | const Qt::Alignment ALIGNMENT = Qt::AlignCenter; | |
23 | ||
24 | const int MIN_WIDTH_TO_FIT_STRANGE_UNITS = 200; | |
25 | ||
26 | DlgEditPointGraph::DlgEditPointGraph (MainWindow &mainWindow, | |
27 | const DocumentModelCoords &modelCoords, | |
28 | const MainWindowModel &modelMainWindow, | |
29 | const Transformation &transformation, | |
30 | const double *xInitialValue, | |
31 | const double *yInitialValue) : | |
32 | QDialog (&mainWindow), | |
33 | m_changed (false), | |
34 | m_modelCoords (modelCoords), | |
35 | m_modelMainWindow (modelMainWindow) | |
36 | { | |
37 | LOG4CPP_INFO_S ((*mainCat)) << "DlgEditPointGraph::DlgEditPointGraph"; | |
38 | ||
39 | QVBoxLayout *layout = new QVBoxLayout; | |
40 | setLayout (layout); | |
41 | ||
42 | setCursor (QCursor (Qt::ArrowCursor)); | |
43 | setModal(true); | |
44 | setWindowTitle (tr ("Edit Curve Point(s)")); | |
45 | ||
46 | createCoords (layout); | |
47 | createHint (layout); | |
48 | createOkCancel (layout); | |
49 | ||
50 | initializeGraphCoordinates (xInitialValue, | |
51 | yInitialValue, | |
52 | transformation); | |
53 | ||
54 | m_changed = false; // Initialization of coordinate vaues changed this flag so we reset it and update the controls | |
55 | updateControls (); | |
56 | } | |
57 | ||
58 | DlgEditPointGraph::~DlgEditPointGraph() | |
59 | { | |
60 | LOG4CPP_INFO_S ((*mainCat)) << "DlgEditPointGraph::~DlgEditPointGraph"; | |
61 | } | |
62 | ||
63 | void DlgEditPointGraph::createCoords (QVBoxLayout *layoutOuter) | |
64 | { | |
65 | // Constraints on x and y are needed for log scaling | |
66 | bool isConstraintX = (m_modelCoords.coordScaleXTheta() == COORD_SCALE_LOG); | |
67 | bool isConstraintY = (m_modelCoords.coordScaleYRadius() == COORD_SCALE_LOG); | |
68 | DlgValidatorFactory dlgValidatorFactory; | |
69 | m_validatorGraphX = dlgValidatorFactory.createCartesianOrPolarWithPolarPolar (m_modelCoords.coordScaleXTheta(), | |
70 | isCartesian (), | |
71 | m_modelCoords.coordUnitsX(), | |
72 | m_modelCoords.coordUnitsTheta(), | |
73 | m_modelCoords.coordUnitsDate(), | |
74 | m_modelCoords.coordUnitsTime(), | |
75 | m_modelMainWindow.locale()); | |
76 | m_validatorGraphY = dlgValidatorFactory.createCartesianOrPolarWithNonPolarPolar (m_modelCoords.coordScaleYRadius(), | |
77 | isCartesian (), | |
78 | m_modelCoords.coordUnitsY(), | |
79 | m_modelCoords.coordUnitsRadius(), | |
80 | m_modelCoords.coordUnitsDate(), | |
81 | m_modelCoords.coordUnitsTime(), | |
82 | m_modelMainWindow.locale()); | |
83 | ||
84 | // Label, with guidance in terms of legal ranges and units | |
85 | QString description = QString ("%1 (%2, %3)%4%5%6%7%8%9 %10:") | |
86 | .arg (tr ("Graph Coordinates")) | |
87 | .arg (nameXTheta ()) | |
88 | .arg (nameYRadius ()) | |
89 | .arg (isConstraintX || isConstraintY ? " with " : "") | |
90 | .arg (isConstraintX ? QString (nameXTheta ()) : "") | |
91 | .arg (isConstraintX ? " > 0" : "") | |
92 | .arg (isConstraintX && isConstraintY ? " and " : "") | |
93 | .arg ( isConstraintY ? QString (nameYRadius ()) : "") | |
94 | .arg ( isConstraintY ? " > 0" : "") | |
95 | .arg (tr ("as")); | |
96 | QGroupBox *panel = new QGroupBox (description, this); | |
97 | layoutOuter->addWidget (panel); | |
98 | ||
99 | QHBoxLayout *layout = new QHBoxLayout (panel); | |
100 | panel->setLayout (layout); | |
101 | ||
102 | // Row | |
103 | QLabel *labelGraphParLeft = new QLabel (tr ("("), this); | |
104 | layout->addWidget(labelGraphParLeft, 0); | |
105 | ||
106 | m_editGraphX = new DlgEditPointGraphLineEdit; | |
107 | m_editGraphX->setMinimumWidth(MIN_WIDTH_TO_FIT_STRANGE_UNITS); | |
108 | m_editGraphX->setAlignment (ALIGNMENT); | |
109 | m_editGraphX->setValidator (m_validatorGraphX); | |
110 | // setStatusTip does not work for modal dialogs | |
111 | m_editGraphX->setWhatsThis (tr ("Enter the first graph coordinate value to be applied to the graph points.\n\n" | |
112 | "Leave this field empty if no value is to be applied to the graph points.\n\n" | |
113 | "For cartesian plots this is the X coordinate. For polar plots this is the radius R.\n\n" | |
114 | "The expected format of the coordinate value is determined by the locale setting. If " | |
115 | "typed values are not recognized as expected, check the locale setting in Settings / Main Window...")); | |
116 | layout->addWidget(m_editGraphX, 0); | |
117 | connect (m_editGraphX, SIGNAL (textChanged (const QString &)), this, SLOT (slotTextChanged (const QString &))); | |
118 | ||
119 | QLabel *labelGraphComma = new QLabel (tr (", "), this); | |
120 | layout->addWidget(labelGraphComma, 0); | |
121 | ||
122 | m_editGraphY = new DlgEditPointGraphLineEdit; | |
123 | m_editGraphY->setMinimumWidth(MIN_WIDTH_TO_FIT_STRANGE_UNITS); | |
124 | m_editGraphY->setAlignment (ALIGNMENT); | |
125 | m_editGraphY->setValidator (m_validatorGraphY); | |
126 | // setStatusTip does not work for modal dialogs | |
127 | m_editGraphY->setWhatsThis (tr ("Enter the second graph coordinate value to be applied to the graph points.\n\n" | |
128 | "Leave this field empty if no value is to be applied to the graph points.\n\n" | |
129 | "For cartesian plots this is the Y coordinate. For plot plots this is the angle Theta.\n\n" | |
130 | "The expected format of the coordinate value is determined by the locale setting. If " | |
131 | "typed values are not recognized as expected, check the locale setting in Settings / Main Window...")); | |
132 | layout->addWidget(m_editGraphY, 0); | |
133 | connect (m_editGraphY, SIGNAL (textChanged (const QString &)), this, SLOT (slotTextChanged (const QString &))); | |
134 | ||
135 | QLabel *labelGraphParRight = new QLabel (tr (")"), this); | |
136 | layout->addWidget(labelGraphParRight, 0); | |
137 | } | |
138 | ||
139 | void DlgEditPointGraph::createHint (QVBoxLayout *layoutOuter) | |
140 | { | |
141 | // Insert a hint explaining why decimal points may not be accepted. Very confusing for user to figure out the problem at first, and | |
142 | // then figure out which setting should change to fix it. The hint is centered so it is slightly less intrusive | |
143 | ||
144 | QWidget *widget = new QWidget; | |
145 | layoutOuter->addWidget (widget, 0, Qt::AlignCenter); | |
146 | ||
147 | QHBoxLayout *layout = new QHBoxLayout; | |
148 | widget->setLayout (layout); | |
149 | ||
150 | QString locale = QLocaleToString (m_modelMainWindow.locale ()); | |
151 | QString hint = QString ("%1: %2") | |
152 | .arg (tr ("Number format")) | |
153 | .arg (locale); | |
154 | QLabel *label = new QLabel (hint); | |
155 | layout->addWidget (label); | |
156 | } | |
157 | ||
158 | void DlgEditPointGraph::createOkCancel (QVBoxLayout *layoutOuter) | |
159 | { | |
160 | QWidget *panel = new QWidget (this); | |
161 | layoutOuter->addWidget (panel, 0, Qt::AlignCenter); | |
162 | ||
163 | QHBoxLayout *layout = new QHBoxLayout (panel); | |
164 | panel->setLayout (layout); | |
165 | ||
166 | m_btnOk = new QPushButton (tr ("Ok"), this); | |
167 | layout->addWidget(m_btnOk); | |
168 | connect (m_btnOk, SIGNAL (released ()), this, SLOT (accept ())); | |
169 | ||
170 | m_btnCancel = new QPushButton (tr ("Cancel"), this); | |
171 | layout->addWidget(m_btnCancel); | |
172 | connect (m_btnCancel, SIGNAL (released ()), this, SLOT (reject ())); | |
173 | } | |
174 | ||
175 | void DlgEditPointGraph::initializeGraphCoordinates (const double *xInitialValue, | |
176 | const double *yInitialValue, | |
177 | const Transformation &transformation) | |
178 | { | |
179 | LOG4CPP_INFO_S ((*mainCat)) << "DlgEditPointGraph::initializeGraphCoordinates"; | |
180 | ||
181 | QString xTheta, yRadius; | |
182 | if ((xInitialValue != 0) && | |
183 | (yInitialValue != 0)) { | |
184 | ||
185 | FormatCoordsUnits format; | |
186 | format.unformattedToFormatted (*xInitialValue, | |
187 | *yInitialValue, | |
188 | m_modelCoords, | |
189 | m_modelMainWindow, | |
190 | xTheta, | |
191 | yRadius, | |
192 | transformation); | |
193 | } | |
194 | ||
195 | m_editGraphX->setText (xTheta); | |
196 | m_editGraphY->setText (yRadius); | |
197 | } | |
198 | ||
199 | bool DlgEditPointGraph::isCartesian () const | |
200 | { | |
201 | return (m_modelCoords.coordsType() == COORDS_TYPE_CARTESIAN); | |
202 | } | |
203 | ||
204 | QChar DlgEditPointGraph::nameXTheta () const | |
205 | { | |
206 | return (isCartesian () ? QChar ('X') : THETA); | |
207 | } | |
208 | ||
209 | QChar DlgEditPointGraph::nameYRadius () const | |
210 | { | |
211 | return (isCartesian () ? QChar ('Y') : QChar ('R')); | |
212 | } | |
213 | ||
214 | void DlgEditPointGraph::posGraph (bool &isX, | |
215 | double &x, | |
216 | bool &isY, | |
217 | double &y) const | |
218 | { | |
219 | FormatCoordsUnits format; | |
220 | ||
221 | // Use zero for any empty coordinate | |
222 | QString xTextNotEmpty = QString ("%1").arg (m_editGraphX->text().isEmpty () ? "0" : m_editGraphX->text()); | |
223 | QString yTextNotEmpty = QString ("%1").arg (m_editGraphY->text().isEmpty () ? "0" : m_editGraphY->text()); | |
224 | ||
225 | format.formattedToUnformatted (xTextNotEmpty, | |
226 | yTextNotEmpty, | |
227 | m_modelCoords, | |
228 | m_modelMainWindow, | |
229 | x, | |
230 | y); | |
231 | ||
232 | isX = !m_editGraphX->text().isEmpty(); | |
233 | isY = !m_editGraphY->text().isEmpty(); | |
234 | } | |
235 | ||
236 | void DlgEditPointGraph::slotTextChanged (const QString &) | |
237 | { | |
238 | m_changed = true; | |
239 | updateControls (); | |
240 | } | |
241 | ||
242 | QString DlgEditPointGraph::unitsType (bool isXTheta) const | |
243 | { | |
244 | if (isCartesian ()) { | |
245 | if (isXTheta) { | |
246 | return coordUnitsNonPolarThetaToBriefType (m_modelCoords.coordUnitsX()); | |
247 | } else { | |
248 | return coordUnitsNonPolarThetaToBriefType (m_modelCoords.coordUnitsY()); | |
249 | } | |
250 | } else { | |
251 | if (isXTheta) { | |
252 | return coordUnitsPolarThetaToBriefType (m_modelCoords.coordUnitsTheta()); | |
253 | } else { | |
254 | return coordUnitsNonPolarThetaToBriefType (m_modelCoords.coordUnitsRadius()); | |
255 | } | |
256 | } | |
257 | } | |
258 | ||
259 | void DlgEditPointGraph::updateControls () | |
260 | { | |
261 | QString textX = m_editGraphX->text(); | |
262 | QString textY = m_editGraphY->text(); | |
263 | ||
264 | // Feedback indicating that empty coordinate will be skipped rather than applied to the selected points | |
265 | m_editGraphX->updateBackground (); | |
266 | m_editGraphY->updateBackground (); | |
267 | ||
268 | // Tests that all have to be true | |
269 | // 1) At least one value has been changed | |
270 | // 2) At least one value is not empty | |
271 | // 3) The values that are not empty are properly formatted. This is done remembering that we need to | |
272 | // check for not empty (which allows single minus sign) and for valid number (which prevents single | |
273 | // minus sign) | |
274 | bool test2 = (!textX.isEmpty() || !textY.isEmpty()); | |
275 | ||
276 | int posX, posY; | |
277 | bool test3 = true; | |
278 | if (!textX.isEmpty()) { | |
279 | test3 &= (m_validatorGraphX->validate(textX, posX) == QValidator::Acceptable); | |
280 | } | |
281 | if (!textY.isEmpty()) { | |
282 | test3 &= (m_validatorGraphY->validate(textY, posY) == QValidator::Acceptable); | |
283 | } | |
284 | ||
285 | m_btnOk->setEnabled (m_changed && test2 && test3); | |
286 | } |
0 | /****************************************************************************************************** | |
1 | * (C) 2016 markummitchell@github.com. This file is part of Engauge Digitizer, which is released * | |
2 | * under GNU General Public License version 2 (GPLv2) or (at your option) any later version. See file * | |
3 | * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. * | |
4 | ******************************************************************************************************/ | |
5 | ||
6 | #ifndef DLG_EDIT_POINT_GRAPH_H | |
7 | #define DLG_EDIT_POINT_GRAPH_H | |
8 | ||
9 | #include <QDialog> | |
10 | #include <QPointF> | |
11 | #include <QString> | |
12 | ||
13 | class DlgEditPointGraphLineEdit; | |
14 | class DlgValidatorAbstract; | |
15 | class DocumentModelCoords; | |
16 | class MainWindow; | |
17 | class MainWindowModel; | |
18 | class QPushButton; | |
19 | class QVBoxLayout; | |
20 | class Transformation; | |
21 | ||
22 | /// Dialog box for editing the information of one or more points. | |
23 | class DlgEditPointGraph : public QDialog | |
24 | { | |
25 | Q_OBJECT; | |
26 | ||
27 | public: | |
28 | /// Constructor for existing point which already has graph coordinates (which may be changed using this dialog). | |
29 | /// If initial values are unspecified then the value fields will be initially empty | |
30 | DlgEditPointGraph (MainWindow &mainWindow, | |
31 | const DocumentModelCoords &modelCoords, | |
32 | const MainWindowModel &modelMainWindow, | |
33 | const Transformation &transformation, | |
34 | const double *xInitialValue = 0, | |
35 | const double *yInitialValue = 0); | |
36 | ~DlgEditPointGraph (); | |
37 | ||
38 | /// Return one or both coordinates. Only applies if dialog was accepted | |
39 | void posGraph (bool &isX, double &x, bool &isY, double &y) const; | |
40 | ||
41 | private slots: | |
42 | void slotTextChanged (const QString &); | |
43 | ||
44 | private: | |
45 | DlgEditPointGraph (); | |
46 | ||
47 | void createCoords (QVBoxLayout *layoutOuter); | |
48 | void createHint (QVBoxLayout *layoutOuter); | |
49 | void createOkCancel (QVBoxLayout *layoutOuter); | |
50 | void initializeGraphCoordinates (const double *xInitialValue, | |
51 | const double *yInitialValue, | |
52 | const Transformation &transformation); | |
53 | bool isCartesian () const; | |
54 | QChar nameXTheta () const; | |
55 | QChar nameYRadius () const; | |
56 | QString unitsType (bool isXTheta) const; | |
57 | void updateControls (); | |
58 | ||
59 | DlgValidatorAbstract *m_validatorGraphX; | |
60 | DlgEditPointGraphLineEdit *m_editGraphX; | |
61 | DlgValidatorAbstract *m_validatorGraphY; | |
62 | DlgEditPointGraphLineEdit *m_editGraphY; | |
63 | QPushButton *m_btnOk; | |
64 | QPushButton *m_btnCancel; | |
65 | ||
66 | // Enable Ok button once text has changed. For simplicity, this is true even when original text is restored | |
67 | bool m_changed; | |
68 | ||
69 | const DocumentModelCoords &m_modelCoords; | |
70 | const MainWindowModel &m_modelMainWindow; | |
71 | }; | |
72 | ||
73 | #endif // DLG_EDIT_POINT_GRAPH_H |
0 | /****************************************************************************************************** | |
1 | * (C) 2016 markummitchell@github.com. This file is part of Engauge Digitizer, which is released * | |
2 | * under GNU General Public License version 2 (GPLv2) or (at your option) any later version. See file * | |
3 | * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. * | |
4 | ******************************************************************************************************/ | |
5 | ||
6 | #include "DlgEditPointGraphLineEdit.h" | |
7 | #include "Logger.h" | |
8 | #include <QWidget> | |
9 | ||
10 | DlgEditPointGraphLineEdit::DlgEditPointGraphLineEdit (QWidget *widget) : | |
11 | QLineEdit (widget), | |
12 | m_hover (false) | |
13 | { | |
14 | LOG4CPP_INFO_S ((*mainCat)) << "DlgEditPointGraphLineEdit::DlgEditPointGraphLineEdit"; | |
15 | } | |
16 | ||
17 | DlgEditPointGraphLineEdit::~DlgEditPointGraphLineEdit() | |
18 | { | |
19 | LOG4CPP_INFO_S ((*mainCat)) << "DlgEditPointGraphLineEdit::~DlgEditPointGraphLineEdit"; | |
20 | } | |
21 | ||
22 | void DlgEditPointGraphLineEdit::enterEvent(QEvent *) | |
23 | { | |
24 | m_hover = true; | |
25 | updateBackground (); | |
26 | } | |
27 | ||
28 | void DlgEditPointGraphLineEdit::leaveEvent (QEvent *) | |
29 | { | |
30 | m_hover = false; | |
31 | updateBackground (); | |
32 | } | |
33 | ||
34 | void DlgEditPointGraphLineEdit::updateBackground () | |
35 | { | |
36 | QString color = (m_hover || !text().isEmpty() ? QString ("white") : QString ("#d3d3d3")); | |
37 | QString style = QString ("QLineEdit { background-color: %1; }").arg (color); | |
38 | setStyleSheet (style); | |
39 | } |
0 | /****************************************************************************************************** | |
1 | * (C) 2016 markummitchell@github.com. This file is part of Engauge Digitizer, which is released * | |
2 | * under GNU General Public License version 2 (GPLv2) or (at your option) any later version. See file * | |
3 | * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. * | |
4 | ******************************************************************************************************/ | |
5 | ||
6 | #ifndef DLG_EDIT_POINT_GRAPH_LINE_EDIT_H | |
7 | #define DLG_EDIT_POINT_GRAPH_LINE_EDIT_H | |
8 | ||
9 | #include <QLineEdit> | |
10 | ||
11 | class QWidget; | |
12 | ||
13 | /// Adds hover highlighting to QLineEdit | |
14 | class DlgEditPointGraphLineEdit : public QLineEdit | |
15 | { | |
16 | Q_OBJECT; | |
17 | ||
18 | public: | |
19 | /// Single constructor | |
20 | DlgEditPointGraphLineEdit (QWidget *widget = 0); | |
21 | ~DlgEditPointGraphLineEdit (); | |
22 | ||
23 | /// Hover entry triggers clearing of the background color so user does not think of widget as disabled and is encouraged to enter text | |
24 | virtual void enterEvent(QEvent *); | |
25 | ||
26 | /// Hover exit triggers restoration of the background color | |
27 | virtual void leaveEvent (QEvent *); | |
28 | ||
29 | /// Update background given the current state | |
30 | void updateBackground (); | |
31 | ||
32 | private: | |
33 | ||
34 | bool m_hover; | |
35 | }; | |
36 | ||
37 | #endif // DLG_EDIT_POINT_GRAPH_LINE_EDIT_H |
0 | /****************************************************************************************************** | |
1 | * (C) 2014 markummitchell@github.com. This file is part of Engauge Digitizer, which is released * | |
2 | * under GNU General Public License version 2 (GPLv2) or (at your option) any later version. See file * | |
3 | * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. * | |
4 | ******************************************************************************************************/ | |
5 | ||
6 | #include "DlgImportCroppingNonPdf.h" | |
7 | #include "EngaugeAssert.h" | |
8 | #include "Logger.h" | |
9 | #include "MainWindow.h" | |
10 | #include "NonPdfCropping.h" | |
11 | #include <QApplication> | |
12 | #include <QGraphicsPixmapItem> | |
13 | #include <QGraphicsScene> | |
14 | #include <QImage> | |
15 | #include <QLabel> | |
16 | #include <QLayout> | |
17 | #include <QPushButton> | |
18 | #include <QSettings> | |
19 | #include <QSpinBox> | |
20 | #include <QTimer> | |
21 | #include "Settings.h" | |
22 | #include "ViewPreview.h" | |
23 | ||
24 | int DlgImportCroppingNonPdf::MINIMUM_DIALOG_WIDTH = 350; | |
25 | int DlgImportCroppingNonPdf::MINIMUM_PREVIEW_HEIGHT = 200; | |
26 | ||
27 | DlgImportCroppingNonPdf::DlgImportCroppingNonPdf(const QString &fileName) : | |
28 | m_fileName (fileName), | |
29 | m_pixmap (0) | |
30 | { | |
31 | LOG4CPP_INFO_S ((*mainCat)) << "DlgImportCroppingNonPdf::DlgImportCroppingNonPdf"; | |
32 | ||
33 | setWindowTitle (tr ("Image File Import Cropping")); | |
34 | setModal (true); | |
35 | ||
36 | QWidget *subPanel = new QWidget (); | |
37 | QGridLayout *layout = new QGridLayout (subPanel); | |
38 | subPanel->setLayout (layout); | |
39 | ||
40 | int row = 0; | |
41 | ||
42 | createPreview (layout, row); | |
43 | finishPanel (subPanel); | |
44 | updatePreview (); | |
45 | ||
46 | // Bring the two middle columns together | |
47 | layout->setColumnStretch (0, 1); | |
48 | layout->setColumnStretch (1, 0); | |
49 | layout->setColumnStretch (2, 0); | |
50 | layout->setColumnStretch (3, 1); | |
51 | } | |
52 | ||
53 | DlgImportCroppingNonPdf::~DlgImportCroppingNonPdf() | |
54 | { | |
55 | LOG4CPP_INFO_S ((*mainCat)) << "DlgImportCroppingNonPdf::~DlgImportCroppingNonPdf"; | |
56 | } | |
57 | ||
58 | void DlgImportCroppingNonPdf::createNonPdfCropping () | |
59 | { | |
60 | // Create frame that shows what will be included, and what will be excluded, during the import | |
61 | m_nonPdfCropping = new NonPdfCropping (*m_scenePreview, | |
62 | *m_viewPreview); | |
63 | } | |
64 | ||
65 | void DlgImportCroppingNonPdf::createPreview (QGridLayout *layout, | |
66 | int &row) | |
67 | { | |
68 | LOG4CPP_INFO_S ((*mainCat)) << "DlgImportCroppingNonPdf::createPreview"; | |
69 | ||
70 | QLabel *labelPreview = new QLabel (tr ("Preview")); | |
71 | layout->addWidget (labelPreview, row++, 0, 1, 1, Qt::AlignLeft); | |
72 | ||
73 | m_scenePreview = new QGraphicsScene (this); | |
74 | m_viewPreview = new ViewPreview (m_scenePreview, | |
75 | ViewPreview::VIEW_ASPECT_RATIO_ONE_TO_ONE, | |
76 | this); | |
77 | m_viewPreview->setWhatsThis (tr ("Preview window that shows what part of the image will be imported. " | |
78 | "The image portion inside the rectangular frame will be imported from the currently selected page. " | |
79 | "The frame can be moved and resized by dragging the corner handles.")); | |
80 | m_viewPreview->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); | |
81 | m_viewPreview->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); | |
82 | m_viewPreview->setMinimumHeight (MINIMUM_PREVIEW_HEIGHT); | |
83 | layout->addWidget (m_viewPreview, row++, 0, 1, 4); | |
84 | ||
85 | // More preview initialization | |
86 | initializeFrameGeometryAndPixmap (); // Before first call to updatePreview | |
87 | createNonPdfCropping (); | |
88 | } | |
89 | ||
90 | void DlgImportCroppingNonPdf::finishPanel (QWidget *subPanel) | |
91 | { | |
92 | const int STRETCH_OFF = 0, STRETCH_ON = 1; | |
93 | ||
94 | QVBoxLayout *panelLayout = new QVBoxLayout (this); | |
95 | ||
96 | setMinimumWidth (MINIMUM_DIALOG_WIDTH); | |
97 | setLayout (panelLayout); | |
98 | ||
99 | panelLayout->addWidget (subPanel); | |
100 | panelLayout->setStretch (panelLayout->count () - 1, STRETCH_ON); | |
101 | ||
102 | QWidget *panelButtons = new QWidget (this); | |
103 | QHBoxLayout *buttonLayout = new QHBoxLayout (panelButtons); | |
104 | ||
105 | QHBoxLayout *layoutRightSide = new QHBoxLayout; | |
106 | ||
107 | QWidget *widgetRightSide = new QWidget; | |
108 | widgetRightSide->setLayout (layoutRightSide); | |
109 | buttonLayout->addWidget (widgetRightSide); | |
110 | ||
111 | QSpacerItem *spacerExpanding = new QSpacerItem (40, 5, QSizePolicy::Expanding, QSizePolicy::Expanding); | |
112 | layoutRightSide->addItem (spacerExpanding); | |
113 | ||
114 | m_btnOk = new QPushButton (tr ("Ok")); | |
115 | layoutRightSide->addWidget (m_btnOk, 0, Qt::AlignRight); | |
116 | connect (m_btnOk, SIGNAL (released ()), this, SLOT (slotOk ())); | |
117 | ||
118 | QSpacerItem *spacerFixed = new QSpacerItem (40, 5, QSizePolicy::Fixed, QSizePolicy::Fixed); | |
119 | layoutRightSide->addItem (spacerFixed); | |
120 | ||
121 | m_btnCancel = new QPushButton (tr ("Cancel")); | |
122 | layoutRightSide->addWidget (m_btnCancel, 0, Qt::AlignRight); | |
123 | connect (m_btnCancel, SIGNAL (released ()), this, SLOT (slotCancel ())); | |
124 | ||
125 | panelLayout->addWidget (panelButtons, STRETCH_ON); | |
126 | panelLayout->setStretch (panelLayout->count () - 1, STRETCH_OFF); | |
127 | } | |
128 | ||
129 | QImage DlgImportCroppingNonPdf::image () const | |
130 | { | |
131 | // If the entire page was to be returned, then this method would simply return m_image. However, only the framed | |
132 | // portion is to be returned | |
133 | ENGAUGE_ASSERT (m_nonPdfCropping != 0); | |
134 | QRectF rectFramePixels = m_nonPdfCropping->frameRect (); | |
135 | ||
136 | return m_image.copy (rectFramePixels.toRect ()); | |
137 | } | |
138 | ||
139 | void DlgImportCroppingNonPdf::initializeFrameGeometryAndPixmap () | |
140 | { | |
141 | m_image = loadImage (); | |
142 | QGraphicsPixmapItem *pixmap = new QGraphicsPixmapItem (QPixmap::fromImage (m_image)); | |
143 | m_scenePreview->addItem (pixmap); | |
144 | ||
145 | // Force resize so image fills preview area. We do this only once initially for speed | |
146 | m_viewPreview->setSceneRect (pixmap->boundingRect ()); | |
147 | } | |
148 | ||
149 | QImage DlgImportCroppingNonPdf::loadImage () const | |
150 | { | |
151 | QImage image; | |
152 | image.load (m_fileName); | |
153 | ||
154 | return image; | |
155 | } | |
156 | ||
157 | void DlgImportCroppingNonPdf::saveGeometryToSettings() | |
158 | { | |
159 | // Store the settings for use by showEvent | |
160 | QSettings settings; | |
161 | settings.beginGroup (SETTINGS_GROUP_IMPORT_CROPPING); | |
162 | settings.setValue (SETTINGS_IMPORT_CROPPING_POS, saveGeometry ()); | |
163 | settings.endGroup(); | |
164 | } | |
165 | ||
166 | void DlgImportCroppingNonPdf::showEvent (QShowEvent * /* event */) | |
167 | { | |
168 | QSettings settings; | |
169 | settings.beginGroup (SETTINGS_GROUP_IMPORT_CROPPING); | |
170 | if (settings.contains (SETTINGS_IMPORT_CROPPING_POS)) { | |
171 | ||
172 | // Restore the settings that were stored by the last call to saveGeometryToSettings | |
173 | restoreGeometry (settings.value (SETTINGS_IMPORT_CROPPING_POS).toByteArray ()); | |
174 | } | |
175 | } | |
176 | ||
177 | void DlgImportCroppingNonPdf::slotCancel () | |
178 | { | |
179 | LOG4CPP_INFO_S ((*mainCat)) << "DlgImportCroppingNonPdf::slotCancel"; | |
180 | ||
181 | // Restore cursor in case updatePreview has not already completed and then restored it | |
182 | QApplication::restoreOverrideCursor (); | |
183 | ||
184 | setResult (QDialog::Rejected); | |
185 | saveGeometryToSettings(); | |
186 | hide(); | |
187 | } | |
188 | ||
189 | void DlgImportCroppingNonPdf::slotOk () | |
190 | { | |
191 | LOG4CPP_INFO_S ((*mainCat)) << "DlgImportCroppingNonPdf::slotOk"; | |
192 | ||
193 | // Restore cursor in case updatePreview has not already completed and then restored it | |
194 | QApplication::restoreOverrideCursor (); | |
195 | ||
196 | setResult (QDialog::Accepted); | |
197 | saveGeometryToSettings(); | |
198 | hide(); | |
199 | } | |
200 | ||
201 | void DlgImportCroppingNonPdf::updatePreview () | |
202 | { | |
203 | LOG4CPP_INFO_S ((*mainCat)) << "DlgImportCroppingNonPdf::updatePreview"; | |
204 | ||
205 | if (m_pixmap != 0) { | |
206 | m_scenePreview->removeItem (m_pixmap); | |
207 | } | |
208 | ||
209 | m_image = loadImage (); | |
210 | m_pixmap = new QGraphicsPixmapItem (QPixmap::fromImage (m_image)); | |
211 | m_scenePreview->addItem (m_pixmap); | |
212 | ||
213 | // Calculations for preview updating are now over | |
214 | QApplication::restoreOverrideCursor (); | |
215 | } |
0 | /****************************************************************************************************** | |
1 | * (C) 2014 markummitchell@github.com. This file is part of Engauge Digitizer, which is released * | |
2 | * under GNU General Public License version 2 (GPLv2) or (at your option) any later version. See file * | |
3 | * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. * | |
4 | ******************************************************************************************************/ | |
5 | ||
6 | #ifndef DLG_IMPORT_CROPPING_NON_PDF_H | |
7 | #define DLG_IMPORT_CROPPING_NON_PDF_H | |
8 | ||
9 | #include <QDialog> | |
10 | #include <QImage> | |
11 | #include <QObject> | |
12 | ||
13 | class NonPdfCropping; | |
14 | class QGraphicsPixmapItem; | |
15 | class QGridLayout; | |
16 | class QGraphicsScene; | |
17 | class QRectF; | |
18 | class QSpinBox; | |
19 | class QString; | |
20 | class ViewPreview; | |
21 | ||
22 | /// Dialog for selecting a page and frame on that page when importing an image from a non-pdf file | |
23 | class DlgImportCroppingNonPdf : public QDialog | |
24 | { | |
25 | Q_OBJECT; | |
26 | ||
27 | public: | |
28 | /// Single constructor. | |
29 | DlgImportCroppingNonPdf (const QString &fileName); | |
30 | virtual ~DlgImportCroppingNonPdf (); | |
31 | ||
32 | /// Image that was selected. Value is null if loading failed | |
33 | QImage image () const; | |
34 | ||
35 | /// Do preparation before dialog is displayed. | |
36 | virtual void showEvent (QShowEvent *event); | |
37 | ||
38 | private slots: | |
39 | ||
40 | /// Hide dialog. | |
41 | void slotCancel(); | |
42 | ||
43 | /// Save changes entered in dialog. | |
44 | void slotOk (); | |
45 | ||
46 | private: | |
47 | DlgImportCroppingNonPdf (); | |
48 | ||
49 | void createNonPdfCropping(); | |
50 | void createPreview (QGridLayout *layout, | |
51 | int &row); | |
52 | void finishPanel (QWidget *subPanel); | |
53 | void initializeFrameGeometryAndPixmap (); | |
54 | QImage loadImage () const; | |
55 | ||
56 | /// Dialog layout constant that guarantees every widget has sufficient room | |
57 | static int MINIMUM_DIALOG_WIDTH; | |
58 | ||
59 | /// Dialog layout constant that guarantees preview has sufficent room | |
60 | static int MINIMUM_PREVIEW_HEIGHT; | |
61 | ||
62 | void saveGeometryToSettings (); | |
63 | void updatePreview (); | |
64 | ||
65 | QPushButton *m_btnCancel; | |
66 | QPushButton *m_btnOk; | |
67 | ||
68 | const QString &m_fileName; | |
69 | QImage m_image; // Needed so it can be passed to external code when this dialog has finished successfully | |
70 | QGraphicsPixmapItem *m_pixmap; // Needed so old image can be removed just before new one gets added | |
71 | ||
72 | QGraphicsScene *m_scenePreview; | |
73 | ViewPreview *m_viewPreview; | |
74 | ||
75 | NonPdfCropping *m_nonPdfCropping; | |
76 | }; | |
77 | ||
78 | #endif // DLG_IMPORT_CROPPING_NON_PDF_H |
0 | /****************************************************************************************************** | |
1 | * (C) 2014 markummitchell@github.com. This file is part of Engauge Digitizer, which is released * | |
2 | * under GNU General Public License version 2 (GPLv2) or (at your option) any later version. See file * | |
3 | * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. * | |
4 | ******************************************************************************************************/ | |
5 | ||
6 | #include "DlgImportCroppingPdf.h" | |
7 | #include "EngaugeAssert.h" | |
8 | #include "Logger.h" | |
9 | #include "MainWindow.h" | |
10 | #include "PdfCropping.h" | |
11 | #include "poppler-qt5.h" | |
12 | #include <QApplication> | |
13 | #include <QGraphicsPixmapItem> | |
14 | #include <QGraphicsScene> | |
15 | #include <QImage> | |
16 | #include <QLabel> | |
17 | #include <QLayout> | |
18 | #include <QPushButton> | |
19 | #include <QSettings> | |
20 | #include <QSpinBox> | |
21 | #include <QTimer> | |
22 | #include "Settings.h" | |
23 | #include "ViewPreview.h" | |
24 | ||
25 | using namespace Poppler; | |
26 | ||
27 | int DlgImportCroppingPdf::MINIMUM_DIALOG_WIDTH = 350; | |
28 | int DlgImportCroppingPdf::MINIMUM_PREVIEW_HEIGHT = 200; | |
29 | const int X_TOP_LEFT = 0, Y_TOP_LEFT = 0; | |
30 | const int WIDTH = -1, HEIGHT = -1; // Negative values give full page | |
31 | const int FIRST_PAGE_1_BASED = 1; | |
32 | const int SMALLEST_DELAY_MS = 500; // Below 500 triggers "double jump" bug in linux | |
33 | ||
34 | DlgImportCroppingPdf::DlgImportCroppingPdf(const Poppler::Document &document, | |
35 | int resolution) : | |
36 | m_document (document), | |
37 | m_resolution (resolution), | |
38 | m_pixmap (0) | |
39 | { | |
40 | LOG4CPP_INFO_S ((*mainCat)) << "DlgImportCroppingPdf::DlgImportCroppingPdf"; | |
41 | ||
42 | setWindowTitle (tr ("PDF File Import Cropping")); | |
43 | setModal (true); | |
44 | ||
45 | QWidget *subPanel = new QWidget (); | |
46 | QGridLayout *layout = new QGridLayout (subPanel); | |
47 | subPanel->setLayout (layout); | |
48 | ||
49 | int row = 0; | |
50 | ||
51 | createTimer (); | |
52 | createPageSpinner (layout, row); | |
53 | createPreview (layout, row); | |
54 | finishPanel (subPanel); | |
55 | updatePreview (); | |
56 | ||
57 | // Bring the two middle columns together | |
58 | layout->setColumnStretch (0, 1); | |
59 | layout->setColumnStretch (1, 0); | |
60 | layout->setColumnStretch (2, 0); | |
61 | layout->setColumnStretch (3, 1); | |
62 | } | |
63 | ||
64 | DlgImportCroppingPdf::~DlgImportCroppingPdf() | |
65 | { | |
66 | LOG4CPP_INFO_S ((*mainCat)) << "DlgImportCroppingPdf::~DlgImportCroppingPdf"; | |
67 | } | |
68 | ||
69 | void DlgImportCroppingPdf::createPageSpinner (QGridLayout *layout, | |
70 | int &row) | |
71 | { | |
72 | LOG4CPP_INFO_S ((*mainCat)) << "DlgImportCroppingPdf::createPageSpinner"; | |
73 | ||
74 | const int MIN_WIDTH_SPINNER = 90; | |
75 | ||
76 | QLabel *labelPage = new QLabel (tr ("Page:")); | |
77 | layout->addWidget (labelPage, row, 1, 1, 1); | |
78 | ||
79 | m_spinPage = new QSpinBox; | |
80 | m_spinPage->setMinimumWidth (MIN_WIDTH_SPINNER); | |
81 | m_spinPage->setWhatsThis (tr ("Page number that will be imported")); | |
82 | m_spinPage->setRange (1, m_document.numPages()); | |
83 | layout->addWidget (m_spinPage, row++, 2, 1, 1); | |
84 | connect (m_spinPage, SIGNAL (valueChanged (int)), this, SLOT (slotPage (int))); | |
85 | } | |
86 | ||
87 | void DlgImportCroppingPdf::createPdfCropping () | |
88 | { | |
89 | // Create frame that shows what will be included, and what will be excluded, during the import | |
90 | m_pdfCropping = new PdfCropping (*m_scenePreview, | |
91 | *m_viewPreview); | |
92 | } | |
93 | ||
94 | void DlgImportCroppingPdf::createPreview (QGridLayout *layout, | |
95 | int &row) | |
96 | { | |
97 | LOG4CPP_INFO_S ((*mainCat)) << "DlgImportCroppingPdf::createPreview"; | |
98 | ||
99 | QLabel *labelPreview = new QLabel (tr ("Preview")); | |
100 | layout->addWidget (labelPreview, row++, 0, 1, 1, Qt::AlignLeft); | |
101 | ||
102 | m_scenePreview = new QGraphicsScene (this); | |
103 | m_viewPreview = new ViewPreview (m_scenePreview, | |
104 | ViewPreview::VIEW_ASPECT_RATIO_ONE_TO_ONE, | |
105 | this); | |
106 | m_viewPreview->setWhatsThis (tr ("Preview window that shows what part of the image will be imported. " | |
107 | "The image portion inside the rectangular frame will be imported from the currently selected page. " | |
108 | "The frame can be moved and resized by dragging the corner handles.")); | |
109 | m_viewPreview->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); | |
110 | m_viewPreview->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); | |
111 | m_viewPreview->setMinimumHeight (MINIMUM_PREVIEW_HEIGHT); | |
112 | layout->addWidget (m_viewPreview, row++, 0, 1, 4); | |
113 | ||
114 | // More preview initialization | |
115 | initializeFrameGeometryAndPixmap (); // Before first call to updatePreview | |
116 | createPdfCropping (); | |
117 | } | |
118 | ||
119 | void DlgImportCroppingPdf::createTimer () | |
120 | { | |
121 | m_timer = new QTimer; | |
122 | m_timer->setSingleShot (true); | |
123 | connect (m_timer, SIGNAL (timeout ()), this, SLOT (slotTimeout ())); | |
124 | } | |
125 | ||
126 | void DlgImportCroppingPdf::finishPanel (QWidget *subPanel) | |
127 | { | |
128 | const int STRETCH_OFF = 0, STRETCH_ON = 1; | |
129 | ||
130 | QVBoxLayout *panelLayout = new QVBoxLayout (this); | |
131 | ||
132 | setMinimumWidth (MINIMUM_DIALOG_WIDTH); | |
133 | setLayout (panelLayout); | |
134 | ||
135 | panelLayout->addWidget (subPanel); | |
136 | panelLayout->setStretch (panelLayout->count () - 1, STRETCH_ON); | |
137 | ||
138 | QWidget *panelButtons = new QWidget (this); | |
139 | QHBoxLayout *buttonLayout = new QHBoxLayout (panelButtons); | |
140 | ||
141 | QHBoxLayout *layoutRightSide = new QHBoxLayout; | |
142 | ||
143 | QWidget *widgetRightSide = new QWidget; | |
144 | widgetRightSide->setLayout (layoutRightSide); | |
145 | buttonLayout->addWidget (widgetRightSide); | |
146 | ||
147 | QSpacerItem *spacerExpanding = new QSpacerItem (40, 5, QSizePolicy::Expanding, QSizePolicy::Expanding); | |
148 | layoutRightSide->addItem (spacerExpanding); | |
149 | ||
150 | m_btnOk = new QPushButton (tr ("Ok")); | |
151 | layoutRightSide->addWidget (m_btnOk, 0, Qt::AlignRight); | |
152 | connect (m_btnOk, SIGNAL (released ()), this, SLOT (slotOk ())); | |
153 | ||
154 | QSpacerItem *spacerFixed = new QSpacerItem (40, 5, QSizePolicy::Fixed, QSizePolicy::Fixed); | |
155 | layoutRightSide->addItem (spacerFixed); | |
156 | ||
157 | m_btnCancel = new QPushButton (tr ("Cancel")); | |
158 | layoutRightSide->addWidget (m_btnCancel, 0, Qt::AlignRight); | |
159 | connect (m_btnCancel, SIGNAL (released ()), this, SLOT (slotCancel ())); | |
160 | ||
161 | panelLayout->addWidget (panelButtons, STRETCH_ON); | |
162 | panelLayout->setStretch (panelLayout->count () - 1, STRETCH_OFF); | |
163 | } | |
164 | ||
165 | QImage DlgImportCroppingPdf::image () const | |
166 | { | |
167 | // If the entire page was to be returned, then this method would simply return m_image. However, only the framed | |
168 | // portion is to be returned | |
169 | ENGAUGE_ASSERT (m_pdfCropping != 0); | |
170 | QRectF rectFramePixels = m_pdfCropping->frameRect (); | |
171 | ||
172 | return m_image.copy (rectFramePixels.toRect ()); | |
173 | } | |
174 | ||
175 | void DlgImportCroppingPdf::initializeFrameGeometryAndPixmap () | |
176 | { | |
177 | m_image = loadImage (FIRST_PAGE_1_BASED); | |
178 | QGraphicsPixmapItem *pixmap = new QGraphicsPixmapItem (QPixmap::fromImage (m_image)); | |
179 | m_scenePreview->addItem (pixmap); | |
180 | ||
181 | // Force resize so image fills preview area. We do this only once initially for speed | |
182 | m_viewPreview->setSceneRect (pixmap->boundingRect ()); | |
183 | } | |
184 | ||
185 | QImage DlgImportCroppingPdf::loadImage (int page1Based) const | |
186 | { | |
187 | QImage image; | |
188 | ||
189 | int page0Based = page1Based - 1; | |
190 | Page *page = m_document.page (page0Based); | |
191 | if (page != 0) { | |
192 | ||
193 | image = page->renderToImage (m_resolution, | |
194 | m_resolution, | |
195 | X_TOP_LEFT, | |
196 | Y_TOP_LEFT, | |
197 | WIDTH, | |
198 | HEIGHT); | |
199 | ||
200 | delete page; | |
201 | } | |
202 | ||
203 | return image; | |
204 | } | |
205 | ||
206 | void DlgImportCroppingPdf::saveGeometryToSettings() | |
207 | { | |
208 | // Store the settings for use by showEvent | |
209 | QSettings settings; | |
210 | settings.beginGroup (SETTINGS_GROUP_IMPORT_CROPPING); | |
211 | settings.setValue (SETTINGS_IMPORT_CROPPING_POS, saveGeometry ()); | |
212 | settings.endGroup(); | |
213 | } | |
214 | ||
215 | void DlgImportCroppingPdf::showEvent (QShowEvent * /* event */) | |
216 | { | |
217 | QSettings settings; | |
218 | settings.beginGroup (SETTINGS_GROUP_IMPORT_CROPPING); | |
219 | if (settings.contains (SETTINGS_IMPORT_CROPPING_POS)) { | |
220 | ||
221 | // Restore the settings that were stored by the last call to saveGeometryToSettings | |
222 | restoreGeometry (settings.value (SETTINGS_IMPORT_CROPPING_POS).toByteArray ()); | |
223 | } | |
224 | } | |
225 | ||
226 | void DlgImportCroppingPdf::slotCancel () | |
227 | { | |
228 | LOG4CPP_INFO_S ((*mainCat)) << "DlgImportCroppingPdf::slotCancel"; | |
229 | ||
230 | // Restore cursor in case updatePreview has not already completed and then restored it | |
231 | QApplication::restoreOverrideCursor (); | |
232 | ||
233 | setResult (QDialog::Rejected); | |
234 | saveGeometryToSettings(); | |
235 | hide(); | |
236 | } | |
237 | ||
238 | void DlgImportCroppingPdf::slotOk () | |
239 | { | |
240 | LOG4CPP_INFO_S ((*mainCat)) << "DlgImportCroppingPdf::slotOk"; | |
241 | ||
242 | // Restore cursor in case updatePreview has not already completed and then restored it | |
243 | QApplication::restoreOverrideCursor (); | |
244 | ||
245 | setResult (QDialog::Accepted); | |
246 | saveGeometryToSettings(); | |
247 | hide(); | |
248 | } | |
249 | ||
250 | void DlgImportCroppingPdf::slotPage (int page) | |
251 | { | |
252 | LOG4CPP_INFO_S ((*mainCat)) << "DlgImportCroppingPdf::slotPage" | |
253 | << " page=" << page | |
254 | << " stepBy=" << m_spinPage->singleStep (); | |
255 | ||
256 | // Show wait cursor until slow calculations are over | |
257 | QApplication::setOverrideCursor (Qt::WaitCursor); | |
258 | ||
259 | m_timer->start (SMALLEST_DELAY_MS); | |
260 | } | |
261 | ||
262 | void DlgImportCroppingPdf::slotTimeout () | |
263 | { | |
264 | LOG4CPP_INFO_S ((*mainCat)) << "DlgImportCroppingPdf::slotTimeout"; | |
265 | ||
266 | updatePreview (); | |
267 | } | |
268 | ||
269 | void DlgImportCroppingPdf::updatePreview () | |
270 | { | |
271 | LOG4CPP_INFO_S ((*mainCat)) << "DlgImportCroppingPdf::updatePreview"; | |
272 | ||
273 | if (m_pixmap != 0) { | |
274 | m_scenePreview->removeItem (m_pixmap); | |
275 | } | |
276 | ||
277 | m_image = loadImage (m_spinPage->value ()); | |
278 | m_pixmap = new QGraphicsPixmapItem (QPixmap::fromImage (m_image)); | |
279 | m_scenePreview->addItem (m_pixmap); | |
280 | ||
281 | // Calculations for preview updating are now over | |
282 | QApplication::restoreOverrideCursor (); | |
283 | } |
0 | /****************************************************************************************************** | |
1 | * (C) 2014 markummitchell@github.com. This file is part of Engauge Digitizer, which is released * | |
2 | * under GNU General Public License version 2 (GPLv2) or (at your option) any later version. See file * | |
3 | * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. * | |
4 | ******************************************************************************************************/ | |
5 | ||
6 | #ifndef DLG_IMPORT_CROPPING_PDF_H | |
7 | #define DLG_IMPORT_CROPPING_PDF_H | |
8 | ||
9 | #include <QDialog> | |
10 | #include <QImage> | |
11 | #include <QObject> | |
12 | ||
13 | namespace Poppler { | |
14 | class Document; | |
15 | } | |
16 | class PdfCropping; | |
17 | class QGraphicsPixmapItem; | |
18 | class QGridLayout; | |
19 | class QGraphicsScene; | |
20 | class QRectF; | |
21 | class QSpinBox; | |
22 | class QString; | |
23 | class QTimer; | |
24 | class ViewPreview; | |
25 | ||
26 | /// Dialog for selecting a page and frame on that page when importing an image from a pdf file | |
27 | class DlgImportCroppingPdf : public QDialog | |
28 | { | |
29 | Q_OBJECT; | |
30 | ||
31 | public: | |
32 | /// Single constructor. | |
33 | DlgImportCroppingPdf (const Poppler::Document &document, | |
34 | int resolution); | |
35 | virtual ~DlgImportCroppingPdf (); | |
36 | ||
37 | /// Image that was selected. Value is null if loading failed | |
38 | QImage image () const; | |
39 | ||
40 | /// Do preparation before dialog is displayed. | |
41 | virtual void showEvent (QShowEvent *event); | |
42 | ||
43 | private slots: | |
44 | ||
45 | /// Hide dialog. | |
46 | void slotCancel(); | |
47 | ||
48 | /// Save changes entered in dialog. | |
49 | void slotOk (); | |
50 | ||
51 | /// Page number has changed | |
52 | void slotPage (int); | |
53 | ||
54 | /// Slow processing of pdf is performed asynchronously using a timer so event handlers are not slowed down | |
55 | void slotTimeout (); | |
56 | ||
57 | private: | |
58 | DlgImportCroppingPdf(); | |
59 | ||
60 | void createPageSpinner (QGridLayout *layout, | |
61 | int &row); | |
62 | void createPdfCropping (); | |
63 | void createPreview (QGridLayout *layout, | |
64 | int &row); | |
65 | void createTimer (); | |
66 | void finishPanel (QWidget *subPanel); | |
67 | void initializeFrameGeometryAndPixmap (); | |
68 | QImage loadImage (int page1Based) const; | |
69 | ||
70 | /// Dialog layout constant that guarantees every widget has sufficient room | |
71 | static int MINIMUM_DIALOG_WIDTH; | |
72 | ||
73 | /// Dialog layout constant that guarantees preview has sufficent room | |
74 | static int MINIMUM_PREVIEW_HEIGHT; | |
75 | ||
76 | void saveGeometryToSettings (); | |
77 | void updatePreview (); | |
78 | ||
79 | QSpinBox *m_spinPage; | |
80 | QPushButton *m_btnCancel; | |
81 | QPushButton *m_btnOk; | |
82 | ||
83 | QTimer *m_timer; | |
84 | const Poppler::Document &m_document; | |
85 | int m_resolution; | |
86 | QImage m_image; // Needed so it can be passed to external code when this dialog has finished successfully | |
87 | QGraphicsPixmapItem *m_pixmap; // Needed so old image can be removed just before new one gets added | |
88 | ||
89 | QGraphicsScene *m_scenePreview; | |
90 | ViewPreview *m_viewPreview; | |
91 | ||
92 | PdfCropping *m_pdfCropping; | |
93 | }; | |
94 | ||
95 | #endif // DLG_IMPORT_CROPPING_PDF_H |
0 | /****************************************************************************************************** | |
1 | * (C) 2014 markummitchell@github.com. This file is part of Engauge Digitizer, which is released * | |
2 | * under GNU General Public License version 2 (GPLv2) or (at your option) any later version. See file * | |
3 | * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. * | |
4 | ******************************************************************************************************/ | |
5 | ||
6 | #include "DlgPdfFrame.h" | |
7 | #include "EngaugeAssert.h" | |
8 | #include "Logger.h" | |
9 | #include "MainWindow.h" | |
10 | #include "PdfFrame.h" | |
11 | #include "poppler-qt5.h" | |
12 | #include <QApplication> | |
13 | #include <QGraphicsPixmapItem> | |
14 | #include <QGraphicsScene> | |
15 | #include <QImage> | |
16 | #include <QLabel> | |
17 | #include <QLayout> | |
18 | #include <QPushButton> | |
19 | #include <QSettings> | |
20 | #include <QSpinBox> | |
21 | #include <QTimer> | |
22 | #include "Settings.h" | |
23 | #include "ViewPreview.h" | |
24 | ||
25 | using namespace Poppler; | |
26 | ||
27 | int DlgPdfFrame::MINIMUM_DIALOG_WIDTH = 350; | |
28 | int DlgPdfFrame::MINIMUM_PREVIEW_HEIGHT = 200; | |
29 | const int X_TOP_LEFT = 0, Y_TOP_LEFT = 0; | |
30 | const int WIDTH = -1, HEIGHT = -1; // Negative values give full page | |
31 | const int FIRST_PAGE_1_BASED = 1; | |
32 | const int SMALLEST_DELAY_MS = 500; // Below 500 triggers "double jump" bug in linux | |
33 | ||
34 | DlgPdfFrame::DlgPdfFrame(const Poppler::Document &document, | |
35 | int resolution) : | |
36 | m_document (document), | |
37 | m_resolution (resolution), | |
38 | m_pixmap (0) | |
39 | { | |
40 | LOG4CPP_INFO_S ((*mainCat)) << "DlgPdfFrame::DlgPdfFrame"; | |
41 | ||
42 | setWindowTitle (tr ("PDF Frame")); | |
43 | setModal (true); | |
44 | ||
45 | QWidget *subPanel = new QWidget (); | |
46 | QGridLayout *layout = new QGridLayout (subPanel); | |
47 | subPanel->setLayout (layout); | |
48 | ||
49 | int row = 0; | |
50 | ||
51 | createTimer (); | |
52 | createPageSpinner (layout, row); | |
53 | createPreview (layout, row); | |
54 | finishPanel (subPanel); | |
55 | updatePreview (); | |
56 | ||
57 | // Bring the two middle columns together | |
58 | layout->setColumnStretch (0, 1); | |
59 | layout->setColumnStretch (1, 0); | |
60 | layout->setColumnStretch (2, 0); | |
61 | layout->setColumnStretch (3, 1); | |
62 | } | |
63 | ||
64 | DlgPdfFrame::~DlgPdfFrame() | |
65 | { | |
66 | LOG4CPP_INFO_S ((*mainCat)) << "DlgPdfFrame::~DlgPdfFrame"; | |
67 | } | |
68 | ||
69 | void DlgPdfFrame::createPageSpinner (QGridLayout *layout, | |
70 | int &row) | |
71 | { | |
72 | LOG4CPP_INFO_S ((*mainCat)) << "DlgPdfFrame::createPageSpinner"; | |
73 | ||
74 | const int MIN_WIDTH_SPINNER = 90; | |
75 | ||
76 | QLabel *labelPage = new QLabel (tr ("Page:")); | |
77 | layout->addWidget (labelPage, row, 1, 1, 1); | |
78 | ||
79 | m_spinPage = new QSpinBox; | |
80 | m_spinPage->setMinimumWidth (MIN_WIDTH_SPINNER); | |
81 | m_spinPage->setWhatsThis (tr ("Page number that will be imported")); | |
82 | m_spinPage->setRange (1, m_document.numPages()); | |
83 | layout->addWidget (m_spinPage, row++, 2, 1, 1); | |
84 | connect (m_spinPage, SIGNAL (valueChanged (int)), this, SLOT (slotPage (int))); | |
85 | } | |
86 | ||
87 | void DlgPdfFrame::createPreview (QGridLayout *layout, | |
88 | int &row) | |
89 | { | |
90 | LOG4CPP_INFO_S ((*mainCat)) << "DlgPdfFrame::createPreview"; | |
91 | ||
92 | QLabel *labelPreview = new QLabel (tr ("Preview")); | |
93 | layout->addWidget (labelPreview, row++, 0, 1, 1, Qt::AlignLeft); | |
94 | ||
95 | m_scenePreview = new QGraphicsScene (this); | |
96 | m_viewPreview = new ViewPreview (m_scenePreview, | |
97 | ViewPreview::VIEW_ASPECT_RATIO_ONE_TO_ONE, | |
98 | this); | |
99 | m_viewPreview->setWhatsThis (tr ("Preview window that shows what part of the image will be imported. " | |
100 | "The image portion inside the rectangular frame will be imported from the currently selected page. " | |
101 | "The frame can be moved and resized by dragging the corner handles.")); | |
102 | m_viewPreview->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); | |
103 | m_viewPreview->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); | |
104 | m_viewPreview->setMinimumHeight (MINIMUM_PREVIEW_HEIGHT); | |
105 | layout->addWidget (m_viewPreview, row++, 0, 1, 4); | |
106 | ||
107 | // More preview initialization | |
108 | initializeFrameGeometryAndPixmap (); // Before first call to updatePreview | |
109 | createPdfFrame (); | |
110 | } | |
111 | ||
112 | void DlgPdfFrame::createPdfFrame () | |
113 | { | |
114 | // Create frame that shows what will be included, and what will be excluded, during the import | |
115 | m_pdfFrame = new PdfFrame (*m_scenePreview, | |
116 | *m_viewPreview); | |
117 | } | |
118 | ||
119 | void DlgPdfFrame::createTimer () | |
120 | { | |
121 | m_timer = new QTimer; | |
122 | m_timer->setSingleShot (true); | |
123 | connect (m_timer, SIGNAL (timeout ()), this, SLOT (slotTimeout ())); | |
124 | } | |
125 | ||
126 | void DlgPdfFrame::finishPanel (QWidget *subPanel) | |
127 | { | |
128 | const int STRETCH_OFF = 0, STRETCH_ON = 1; | |
129 | ||
130 | QVBoxLayout *panelLayout = new QVBoxLayout (this); | |
131 | ||
132 | setMinimumWidth (MINIMUM_DIALOG_WIDTH); | |
133 | setLayout (panelLayout); | |
134 | ||
135 | panelLayout->addWidget (subPanel); | |
136 | panelLayout->setStretch (panelLayout->count () - 1, STRETCH_ON); | |
137 | ||
138 | QWidget *panelButtons = new QWidget (this); | |
139 | QHBoxLayout *buttonLayout = new QHBoxLayout (panelButtons); | |
140 | ||
141 | QHBoxLayout *layoutRightSide = new QHBoxLayout; | |
142 | ||
143 | QWidget *widgetRightSide = new QWidget; | |
144 | widgetRightSide->setLayout (layoutRightSide); | |
145 | buttonLayout->addWidget (widgetRightSide); | |
146 | ||
147 | QSpacerItem *spacerExpanding = new QSpacerItem (40, 5, QSizePolicy::Expanding, QSizePolicy::Expanding); | |
148 | layoutRightSide->addItem (spacerExpanding); | |
149 | ||
150 | m_btnOk = new QPushButton (tr ("Ok")); | |
151 | layoutRightSide->addWidget (m_btnOk, 0, Qt::AlignRight); | |
152 | connect (m_btnOk, SIGNAL (released ()), this, SLOT (slotOk ())); | |
153 | ||
154 | QSpacerItem *spacerFixed = new QSpacerItem (40, 5, QSizePolicy::Fixed, QSizePolicy::Fixed); | |
155 | layoutRightSide->addItem (spacerFixed); | |
156 | ||
157 | m_btnCancel = new QPushButton (tr ("Cancel")); | |
158 | layoutRightSide->addWidget (m_btnCancel, 0, Qt::AlignRight); | |
159 | connect (m_btnCancel, SIGNAL (released ()), this, SLOT (slotCancel ())); | |
160 | ||
161 | panelLayout->addWidget (panelButtons, STRETCH_ON); | |
162 | panelLayout->setStretch (panelLayout->count () - 1, STRETCH_OFF); | |
163 | } | |
164 | ||
165 | QImage DlgPdfFrame::image () const | |
166 | { | |
167 | // If the entire page was to be returned, then this method would simply return m_image. However, only the framed | |
168 | // portion is to be returned | |
169 | ENGAUGE_ASSERT (m_pdfFrame != 0); | |
170 | QRectF rectFramePixels = m_pdfFrame->frameRect (); | |
171 | ||
172 | return m_image.copy (rectFramePixels.toRect ()); | |
173 | } | |
174 | ||
175 | void DlgPdfFrame::initializeFrameGeometryAndPixmap () | |
176 | { | |
177 | m_image = loadImage (FIRST_PAGE_1_BASED); | |
178 | QGraphicsPixmapItem *pixmap = new QGraphicsPixmapItem (QPixmap::fromImage (m_image)); | |
179 | m_scenePreview->addItem (pixmap); | |
180 | ||
181 | // Force resize so image fills preview area. We do this only once initially for speed | |
182 | m_viewPreview->setSceneRect (pixmap->boundingRect ()); | |
183 | } | |
184 | ||
185 | QImage DlgPdfFrame::loadImage (int page1Based) const | |
186 | { | |
187 | QImage image; | |
188 | ||
189 | int page0Based = page1Based - 1; | |
190 | Page *page = m_document.page (page0Based); | |
191 | if (page != 0) { | |
192 | ||
193 | image = page->renderToImage (m_resolution, | |
194 | m_resolution, | |
195 | X_TOP_LEFT, | |
196 | Y_TOP_LEFT, | |
197 | WIDTH, | |
198 | HEIGHT); | |
199 | ||
200 | delete page; | |
201 | } | |
202 | ||
203 | return image; | |
204 | } | |
205 | ||
206 | void DlgPdfFrame::saveGeometryToSettings() | |
207 | { | |
208 | // Store the settings for use by showEvent | |
209 | QSettings settings; | |
210 | settings.beginGroup (SETTINGS_GROUP_PDF); | |
211 | settings.setValue (SETTINGS_PDF_POS, saveGeometry ()); | |
212 | settings.endGroup(); | |
213 | } | |
214 | ||
215 | void DlgPdfFrame::showEvent (QShowEvent * /* event */) | |
216 | { | |
217 | QSettings settings; | |
218 | settings.beginGroup (SETTINGS_GROUP_PDF); | |
219 | if (settings.contains (SETTINGS_PDF_POS)) { | |
220 | ||
221 | // Restore the settings that were stored by the last call to saveGeometryToSettings | |
222 | restoreGeometry (settings.value (SETTINGS_PDF_POS).toByteArray ()); | |
223 | } | |
224 | } | |
225 | ||
226 | void DlgPdfFrame::slotCancel () | |
227 | { | |
228 | LOG4CPP_INFO_S ((*mainCat)) << "DlgPdfFrame::slotCancel"; | |
229 | ||
230 | // Restore cursor in case updatePreview has not already completed and then restored it | |
231 | QApplication::restoreOverrideCursor (); | |
232 | ||
233 | setResult (QDialog::Rejected); | |
234 | saveGeometryToSettings(); | |
235 | hide(); | |
236 | } | |
237 | ||
238 | void DlgPdfFrame::slotOk () | |
239 | { | |
240 | LOG4CPP_INFO_S ((*mainCat)) << "DlgPdfFrame::slotOk"; | |
241 | ||
242 | // Restore cursor in case updatePreview has not already completed and then restored it | |
243 | QApplication::restoreOverrideCursor (); | |
244 | ||
245 | setResult (QDialog::Accepted); | |
246 | saveGeometryToSettings(); | |
247 | hide(); | |
248 | } | |
249 | ||
250 | void DlgPdfFrame::slotPage (int page) | |
251 | { | |
252 | LOG4CPP_INFO_S ((*mainCat)) << "DlgPdfFrame::slotPage" | |
253 | << " page=" << page | |
254 | << " stepBy=" << m_spinPage->singleStep (); | |
255 | ||
256 | // Show wait cursor until slow calculations are over | |
257 | QApplication::setOverrideCursor (Qt::WaitCursor); | |
258 | ||
259 | m_timer->start (SMALLEST_DELAY_MS); | |
260 | } | |
261 | ||
262 | void DlgPdfFrame::slotTimeout () | |
263 | { | |
264 | LOG4CPP_INFO_S ((*mainCat)) << "DlgPdfFrame::slotTimeout"; | |
265 | ||
266 | updatePreview (); | |
267 | } | |
268 | ||
269 | void DlgPdfFrame::updatePreview () | |
270 | { | |
271 | LOG4CPP_INFO_S ((*mainCat)) << "DlgPdfFrame::updatePreview"; | |
272 | ||
273 | if (m_pixmap != 0) { | |
274 | m_scenePreview->removeItem (m_pixmap); | |
275 | } | |
276 | ||
277 | m_image = loadImage (m_spinPage->value ()); | |
278 | m_pixmap = new QGraphicsPixmapItem (QPixmap::fromImage (m_image)); | |
279 | m_scenePreview->addItem (m_pixmap); | |
280 | ||
281 | // Calculations for preview updating are now over | |
282 | QApplication::restoreOverrideCursor (); | |
283 | } |
0 | /****************************************************************************************************** | |
1 | * (C) 2014 markummitchell@github.com. This file is part of Engauge Digitizer, which is released * | |
2 | * under GNU General Public License version 2 (GPLv2) or (at your option) any later version. See file * | |
3 | * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. * | |
4 | ******************************************************************************************************/ | |
5 | ||
6 | #ifndef DLG_PDF_FRAME_H | |
7 | #define DLG_PDF_FRAME_H | |
8 | ||
9 | #include <QDialog> | |
10 | #include <QImage> | |
11 | #include <QObject> | |
12 | ||
13 | class PdfFrame; | |
14 | namespace Poppler { | |
15 | class Document; | |
16 | } | |
17 | class QGraphicsPixmapItem; | |
18 | class QGridLayout; | |
19 | class QGraphicsScene; | |
20 | class QRectF; | |
21 | class QSpinBox; | |
22 | class QString; | |
23 | class QTimer; | |
24 | class ViewPreview; | |
25 | ||
26 | /// Dialog for selecting a page and frame on that page when importing an image from a pdf file | |
27 | class DlgPdfFrame : public QDialog | |
28 | { | |
29 | Q_OBJECT; | |
30 | ||
31 | public: | |
32 | /// Single constructor. | |
33 | DlgPdfFrame(const Poppler::Document &document, | |
34 | int resolution); | |
35 | virtual ~DlgPdfFrame(); | |
36 | ||
37 | /// Image that was selected. Value is null if loading failed | |
38 | QImage image () const; | |
39 | ||
40 | /// Do preparation before dialog is displayed. | |
41 | virtual void showEvent (QShowEvent *event); | |
42 | ||
43 | private slots: | |
44 | ||
45 | /// Hide dialog. | |
46 | void slotCancel(); | |
47 | ||
48 | /// Save changes entered in dialog. | |
49 | void slotOk (); | |
50 | ||
51 | /// Page number has changed | |
52 | void slotPage (int); | |
53 | ||
54 | /// Slow processing of pdf is performed asynchronously using a timer so event handlers are not slowed down | |
55 | void slotTimeout (); | |
56 | ||
57 | private: | |
58 | DlgPdfFrame(); | |
59 | ||
60 | void createPageSpinner (QGridLayout *layout, | |
61 | int &row); | |
62 | void createPdfFrame (); | |
63 | void createPreview (QGridLayout *layout, | |
64 | int &row); | |
65 | void createTimer (); | |
66 | void finishPanel (QWidget *subPanel); | |
67 | void initializeFrameGeometryAndPixmap (); | |
68 | QImage loadImage (int page1Based) const; | |
69 | ||
70 | /// Dialog layout constant that guarantees every widget has sufficient room | |
71 | static int MINIMUM_DIALOG_WIDTH; | |
72 | ||
73 | /// Dialog layout constant that guarantees preview has sufficent room | |
74 | static int MINIMUM_PREVIEW_HEIGHT; | |
75 | ||
76 | void saveGeometryToSettings (); | |
77 | void updatePreview (); | |
78 | ||
79 | QSpinBox *m_spinPage; | |
80 | QPushButton *m_btnCancel; | |
81 | QPushButton *m_btnOk; | |
82 | ||
83 | QTimer *m_timer; | |
84 | const Poppler::Document &m_document; | |
85 | int m_resolution; | |
86 | QImage m_image; // Needed so it can be passed to external code when this dialog has finished successfully | |
87 | QGraphicsPixmapItem *m_pixmap; // Needed so old image can be removed just before new one gets added | |
88 | ||
89 | QGraphicsScene *m_scenePreview; | |
90 | ViewPreview *m_viewPreview; | |
91 | ||
92 | PdfFrame *m_pdfFrame; | |
93 | }; | |
94 | ||
95 | #endif // DLG_PDF_FRAME_H |
9 | 9 | #include "DlgSettingsCurveProperties.h" |
10 | 10 | #include "EngaugeAssert.h" |
11 | 11 | #include "EnumsToQt.h" |
12 | #include "GeometryWindow.h" | |
12 | 13 | #include "GraphicsPoint.h" |
13 | 14 | #include "GraphicsPointFactory.h" |
14 | 15 | #include "GraphicsView.h" |
58 | 59 | DlgSettingsAbstractBase (tr ("Curve Properties"), |
59 | 60 | "DlgSettingsCurveProperties", |
60 | 61 | mainWindow), |
62 | m_modelMainWindow (mainWindow.modelMainWindow()), | |
61 | 63 | m_scenePreview (0), |
62 | 64 | m_viewPreview (0), |
63 | 65 | m_modelCurveStylesBefore (0), |
325 | 327 | void DlgSettingsCurveProperties::drawPoints (const PointStyle &pointStyle) |
326 | 328 | { |
327 | 329 | const QString NULL_IDENTIFIER; |
330 | GeometryWindow *NULL_GEOMETRY_WINDOW = 0; | |
328 | 331 | |
329 | 332 | GraphicsPointFactory pointFactory; |
330 | 333 | |
332 | 335 | GraphicsPoint *pointLeft = pointFactory.createPoint (*m_scenePreview, |
333 | 336 | NULL_IDENTIFIER, |
334 | 337 | POS_LEFT, |
335 | pointStyle); | |
338 | pointStyle, | |
339 | NULL_GEOMETRY_WINDOW); | |
336 | 340 | pointLeft->setPointStyle (pointStyle); |
337 | 341 | |
338 | 342 | // Center point |
339 | 343 | GraphicsPoint *pointCenter = pointFactory.createPoint (*m_scenePreview, |
340 | 344 | NULL_IDENTIFIER, |
341 | 345 | POS_CENTER, |
342 | pointStyle); | |
346 | pointStyle, | |
347 | NULL_GEOMETRY_WINDOW); | |
343 | 348 | pointCenter->setPointStyle (pointStyle); |
344 | 349 | |
345 | 350 | // Right point |
346 | 351 | GraphicsPoint *pointRight = pointFactory.createPoint (*m_scenePreview, |
347 | 352 | NULL_IDENTIFIER, |
348 | 353 | POS_RIGHT, |
349 | pointStyle); | |
354 | pointStyle, | |
355 | NULL_GEOMETRY_WINDOW); | |
350 | 356 | pointRight->setPointStyle (pointStyle); |
351 | 357 | } |
352 | 358 |
8 | 8 | |
9 | 9 | #include "CurveStyles.h" |
10 | 10 | #include "DlgSettingsAbstractBase.h" |
11 | #include "MainWindowModel.h" | |
11 | 12 | |
12 | 13 | class GraphicsPoint; |
13 | 14 | class QComboBox; |
62 | 63 | void updateControls(); |
63 | 64 | void updatePreview(); |
64 | 65 | |
66 | MainWindowModel m_modelMainWindow; | |
67 | ||
65 | 68 | QComboBox *m_cmbCurveName; |
66 | 69 | |
67 | 70 | QGroupBox *m_groupPoint; |
72 | 72 | layout->addWidget (labelExcluded, row++, 2); |
73 | 73 | |
74 | 74 | m_listIncluded = new QListWidget; |
75 | m_listIncluded->setSortingEnabled (false); // Preserve order from Document | |
75 | 76 | m_listIncluded->setWhatsThis (tr ("List of curves to be included in the exported file.\n\n" |
76 | 77 | "The order of the curves here does not affect the order in the exported file. That " |
77 | 78 | "order is determined by the Curves settings.")); |
80 | 81 | connect (m_listIncluded, SIGNAL (itemSelectionChanged ()), this, SLOT (slotListIncluded())); |
81 | 82 | |
82 | 83 | m_listExcluded = new QListWidget; |
84 | m_listExcluded->setSortingEnabled (false); // Preserve order from Document | |
83 | 85 | m_listExcluded->setWhatsThis (tr ("List of curves to be excluded from the exported file")); |
84 | 86 | m_listExcluded->setSelectionMode (QAbstractItemView::MultiSelection); |
85 | 87 | layout->addWidget (m_listExcluded, row++, 2, 4, 1); |
125 | 127 | m_btnDelimitersTabs->setWhatsThis (tr ("Exported file will have tabs between adjacent values, unless overridden by commas in CSV files.")); |
126 | 128 | layoutDelimiters->addWidget (m_btnDelimitersTabs); |
127 | 129 | connect (m_btnDelimitersTabs, SIGNAL (released ()), this, SLOT (slotDelimitersTabs())); |
130 | ||
131 | m_btnDelimitersSemicolons = new QRadioButton (exportDelimiterToString (EXPORT_DELIMITER_SEMICOLON)); | |
132 | m_btnDelimitersSemicolons->setWhatsThis (tr ("Exported file will have semicolons between adjacent values, unless overridden by commas in CSV files.")); | |
133 | layoutDelimiters->addWidget (m_btnDelimitersSemicolons); | |
134 | connect (m_btnDelimitersSemicolons, SIGNAL (released ()), this, SLOT (slotDelimitersSemicolons())); | |
128 | 135 | |
129 | 136 | m_chkOverrideCsvTsv = new QCheckBox (tr ("Override in CSV/TSV files")); |
130 | 137 | m_chkOverrideCsvTsv->setWhatsThis (tr ("Comma-separated value (CSV) files and tab-separated value (TSV) files will use commas and tabs " |
554 | 561 | m_btnDelimitersCommas->setChecked (delimiter == EXPORT_DELIMITER_COMMA); |
555 | 562 | m_btnDelimitersSpaces->setChecked (delimiter == EXPORT_DELIMITER_SPACE); |
556 | 563 | m_btnDelimitersTabs->setChecked (delimiter == EXPORT_DELIMITER_TAB); |
564 | m_btnDelimitersSemicolons->setChecked (delimiter == EXPORT_DELIMITER_SEMICOLON); | |
557 | 565 | |
558 | 566 | m_chkOverrideCsvTsv->setChecked (m_modelExportAfter->overrideCsvTsv()); |
559 | 567 | |
587 | 595 | LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsExportFormat::slotDelimitersCommas"; |
588 | 596 | |
589 | 597 | m_modelExportAfter->setDelimiter(EXPORT_DELIMITER_COMMA); |
598 | updateControls(); | |
599 | updatePreview(); | |
600 | } | |
601 | ||
602 | void DlgSettingsExportFormat::slotDelimitersSemicolons() | |
603 | { | |
604 | LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsExportFormat::slotDelimitersSemicolons"; | |
605 | ||
606 | m_modelExportAfter->setDelimiter(EXPORT_DELIMITER_SEMICOLON); | |
590 | 607 | updateControls(); |
591 | 608 | updatePreview(); |
592 | 609 | } |
906 | 923 | goodIntervalRelations(); |
907 | 924 | enableOk (isGoodState); |
908 | 925 | |
909 | m_listIncluded->sortItems (Qt::AscendingOrder); | |
910 | m_listExcluded->sortItems (Qt::AscendingOrder); | |
911 | ||
912 | 926 | int selectedForInclude = m_listExcluded->selectedItems().count(); |
913 | 927 | int selectedForExclude = m_listIncluded->selectedItems().count(); |
914 | 928 | int inInclude = m_listIncluded->count(); |
39 | 39 | |
40 | 40 | private slots: |
41 | 41 | void slotDelimitersCommas(); |
42 | void slotDelimitersSemicolons(); | |
42 | 43 | void slotDelimitersSpaces(); |
43 | 44 | void slotDelimitersTabs(); |
44 | 45 | void slotExclude(); |
114 | 115 | QRadioButton *m_btnRelationsPointsRaw; |
115 | 116 | |
116 | 117 | QRadioButton *m_btnDelimitersCommas; |
118 | QRadioButton *m_btnDelimitersSemicolons; | |
117 | 119 | QRadioButton *m_btnDelimitersSpaces; |
118 | 120 | QRadioButton *m_btnDelimitersTabs; |
119 | 121 | QCheckBox *m_chkOverrideCsvTsv; |
594 | 594 | if (textItemsAreValid ()) { |
595 | 595 | |
596 | 596 | GridLineFactory factory (*m_scenePreview, |
597 | cmdMediator ().document ().modelCoords(), | |
598 | mainWindow ().transformation()); | |
597 | cmdMediator ().document ().modelCoords()); | |
599 | 598 | |
600 | 599 | factory.createGridLinesForEvenlySpacedGrid (*m_modelGridDisplayAfter, |
600 | mainWindow ().modelMainWindow(), | |
601 | mainWindow ().transformation(), | |
601 | 602 | m_gridLines); |
602 | 603 | } |
603 | 604 | } |
5 | 5 | |
6 | 6 | #include "DlgSettingsMainWindow.h" |
7 | 7 | #include "EngaugeAssert.h" |
8 | #include "ImportCropping.h" | |
9 | #include "ImportCroppingUtilBase.h" | |
8 | 10 | #include "Logger.h" |
9 | 11 | #include "MainWindow.h" |
10 | 12 | #include "MainWindowModel.h" |
11 | 13 | #include <QCheckBox> |
12 | 14 | #include <QComboBox> |
15 | #include <QDoubleSpinBox> | |
13 | 16 | #include <QGraphicsScene> |
14 | 17 | #include <QGridLayout> |
15 | 18 | #include <QGroupBox> |
108 | 111 | connect (m_cmbLocale, SIGNAL (currentIndexChanged (int)), this, SLOT (slotLocale (int))); |
109 | 112 | layout->addWidget (m_cmbLocale, row++, 2); |
110 | 113 | |
114 | QLabel *labelImportCropping = new QLabel (tr ("Import cropping:")); | |
115 | layout->addWidget (labelImportCropping, row, 1); | |
116 | ||
117 | m_cmbImportCropping = new QComboBox; | |
118 | m_cmbImportCropping->setWhatsThis (tr ("Import Cropping\n\n" | |
119 | "Enables or disables cropping of the imported image when importing. Cropping the image is useful " | |
120 | "for removing unimportant information around a graph, but less useful when the graph already fills " | |
121 | "the entire image.")); | |
122 | ImportCroppingUtilBase importCroppingUtil; | |
123 | m_cmbImportCropping->addItem (importCroppingUtil.importCroppingToString (IMPORT_CROPPING_NEVER), IMPORT_CROPPING_NEVER); | |
124 | m_cmbImportCropping->addItem (importCroppingUtil.importCroppingToString (IMPORT_CROPPING_MULTIPAGE_PDFS), IMPORT_CROPPING_MULTIPAGE_PDFS); | |
125 | m_cmbImportCropping->addItem (importCroppingUtil.importCroppingToString (IMPORT_CROPPING_ALWAYS), IMPORT_CROPPING_ALWAYS); | |
126 | connect (m_cmbImportCropping, SIGNAL (currentIndexChanged (int)), this, SLOT (slotImportCropping (int))); | |
127 | layout->addWidget (m_cmbImportCropping, row++, 2); | |
128 | ||
111 | 129 | #ifdef ENGAUGE_PDF |
112 | 130 | QLabel *labelPdfResolution = new QLabel (tr ("Import PDF resolution (dots per inch):")); |
113 | 131 | layout->addWidget (labelPdfResolution, row, 1); |
128 | 146 | layout->addWidget (m_cmbPdfResolution, row++, 2); |
129 | 147 | #endif |
130 | 148 | |
149 | QLabel *labelMaximumGridLines = new QLabel (tr ("Maximum grid lines:")); | |
150 | layout->addWidget (labelMaximumGridLines, row, 1); | |
151 | ||
152 | m_spinMaximumGridLines = new QSpinBox; | |
153 | m_spinMaximumGridLines->setMinimum (2); | |
154 | m_spinMaximumGridLines->setWhatsThis (tr ("Maximum Grid Lines\n\n" | |
155 | "Maximum number of grid lines to be processed. This limit is applied when the step value is too " | |
156 | "small for the start and stop values, which would result in too many grid lines visually and " | |
157 | "possibly extremely long processing time (since each grid line would have to be processed)")); | |
158 | connect (m_spinMaximumGridLines, SIGNAL (valueChanged (int)), this, (SLOT (slotMaximumGridLines (int)))); | |
159 | layout->addWidget (m_spinMaximumGridLines, row++, 2); | |
160 | ||
161 | QLabel *labelHighlightOpacity = new QLabel (tr ("Highlight opacity:")); | |
162 | layout->addWidget (labelHighlightOpacity, row, 1); | |
163 | ||
164 | m_spinHighlightOpacity = new QDoubleSpinBox; | |
165 | m_spinHighlightOpacity->setRange (0, 1); | |
166 | m_spinHighlightOpacity->setSingleStep (0.1); | |
167 | m_spinHighlightOpacity->setWhatsThis (tr ("Highligh Opacity\n\n" | |
168 | "Opacity to be applied when the cursor is over a curve or axis point in Select mode. The change in " | |
169 | "appearance shows when the point can be selected.")); | |
170 | connect (m_spinHighlightOpacity, SIGNAL (valueChanged (double)), this, SLOT (slotHighlightOpacity(double))); | |
171 | layout->addWidget (m_spinHighlightOpacity, row++, 2); | |
172 | ||
131 | 173 | QLabel *labelRecent = new QLabel (tr ("Recent file list:")); |
132 | 174 | layout->addWidget (labelRecent, row, 1); |
133 | 175 | |
216 | 258 | QString locLabel = QLocaleToString (m_modelMainWindowAfter->locale()); |
217 | 259 | index = m_cmbLocale->findText (locLabel); |
218 | 260 | m_cmbLocale->setCurrentIndex(index); |
261 | index = m_cmbImportCropping->findData (m_modelMainWindowAfter->importCropping()); | |
262 | m_cmbImportCropping->setCurrentIndex (index); | |
219 | 263 | m_chkTitleBarFormat->setChecked (m_modelMainWindowAfter->mainTitleBarFormat() == MAIN_TITLE_BAR_FORMAT_PATH); |
220 | 264 | index = m_cmbPdfResolution->findData (m_modelMainWindowAfter->pdfResolution()); |
221 | 265 | m_cmbPdfResolution->setCurrentIndex(index); |
266 | m_spinMaximumGridLines->setValue (m_modelMainWindowAfter->maximumGridLines()); | |
267 | m_spinHighlightOpacity->setValue (m_modelMainWindowAfter->highlightOpacity()); | |
222 | 268 | |
223 | 269 | updateControls (); |
224 | 270 | enableOk (false); // Disable Ok button since there not yet any changes |
225 | 271 | } |
226 | 272 | |
273 | void DlgSettingsMainWindow::slotHighlightOpacity(double) | |
274 | { | |
275 | LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsMainWindow::slotHighlightOpacity"; | |
276 | ||
277 | m_modelMainWindowAfter->setHighlightOpacity (m_spinHighlightOpacity->value()); | |
278 | updateControls(); | |
279 | } | |
280 | ||
281 | void DlgSettingsMainWindow::slotImportCropping (int index) | |
282 | { | |
283 | LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsMainWindow::slotImportCropping"; | |
284 | ||
285 | m_modelMainWindowAfter->setImportCropping ((ImportCropping) m_cmbImportCropping->itemData (index).toInt ()); | |
286 | updateControls(); | |
287 | } | |
288 | ||
227 | 289 | void DlgSettingsMainWindow::slotLocale (int index) |
228 | 290 | { |
229 | 291 | LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsMainWindow::slotLocale"; |
230 | 292 | |
231 | 293 | m_modelMainWindowAfter->setLocale (m_cmbLocale->itemData (index).toLocale()); |
232 | 294 | updateControls(); |
295 | } | |
296 | ||
297 | void DlgSettingsMainWindow::slotMaximumGridLines (int limit) | |
298 | { | |
299 | LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsMainWIndow::slotMaximumGridLines"; | |
300 | ||
301 | m_modelMainWindowAfter->setMaximumGridLines (limit); | |
302 | updateControls (); | |
233 | 303 | } |
234 | 304 | |
235 | 305 | void DlgSettingsMainWindow::slotPdfResolution(const QString) |
11 | 11 | |
12 | 12 | class QCheckBox; |
13 | 13 | class QComboBox; |
14 | class QDoubleSpinBox; | |
14 | 15 | class QGridLayout; |
15 | 16 | class QPushButton; |
16 | 17 | class QSpinBox; |
35 | 36 | const MainWindowModel &modelMainWindow); |
36 | 37 | |
37 | 38 | private slots: |
38 | void slotTitleBarFormat(bool); | |
39 | void slotHighlightOpacity (double); | |
40 | void slotImportCropping (int index); | |
39 | 41 | void slotLocale (int index); |
42 | void slotMaximumGridLines (int limit); | |
40 | 43 | void slotPdfResolution (const QString); |
41 | 44 | void slotRecentFileClear (); |
45 | void slotTitleBarFormat(bool); | |
42 | 46 | void slotZoomControl (const QString); |
43 | 47 | void slotZoomFactor (const QString); |
44 | 48 | |
54 | 58 | QComboBox *m_cmbZoomFactor; |
55 | 59 | QComboBox *m_cmbZoomControl; |
56 | 60 | QComboBox *m_cmbLocale; |
61 | QComboBox *m_cmbImportCropping; | |
57 | 62 | QPushButton *m_btnRecentClear; |
58 | 63 | QCheckBox *m_chkTitleBarFormat; |
59 | 64 | QComboBox *m_cmbPdfResolution; |
65 | QSpinBox *m_spinMaximumGridLines; | |
66 | QDoubleSpinBox *m_spinHighlightOpacity; | |
60 | 67 | |
61 | 68 | MainWindowModel *m_modelMainWindowBefore; |
62 | 69 | MainWindowModel *m_modelMainWindowAfter; |
7 | 7 | #include "CmdSettingsSegments.h" |
8 | 8 | #include "DlgSettingsSegments.h" |
9 | 9 | #include "EngaugeAssert.h" |
10 | #include "GeometryWindow.h" | |
10 | 11 | #include "Logger.h" |
11 | 12 | #include "MainWindow.h" |
12 | 13 | #include "PointStyle.h" |
347 | 348 | const QString ARBITRARY_IDENTIFIER (""); |
348 | 349 | const QColor COLOR (Qt::blue); |
349 | 350 | const int RADIUS = 5; |
351 | GeometryWindow *NULL_GEOMETRY_WINDOW = 0; | |
350 | 352 | |
351 | 353 | if (!m_loading) { |
352 | 354 | |
384 | 386 | pos, |
385 | 387 | COLOR, |
386 | 388 | polygon, |
387 | BRUSH_WIDTH); | |
389 | BRUSH_WIDTH, | |
390 | NULL_GEOMETRY_WINDOW); | |
391 | ||
388 | 392 | m_points.push_back (graphicsPoint); |
389 | 393 | } |
390 | 394 | } |
42 | 42 | const int VERSION_6 = 6; |
43 | 43 | const int VERSION_7 = 7; |
44 | 44 | const int VERSION_8 = 8; |
45 | const int VERSION_9 = 9; | |
45 | 46 | |
46 | 47 | Document::Document (const QImage &image) : |
47 | 48 | m_name ("untitled"), |
104 | 105 | |
105 | 106 | case VERSION_7: |
106 | 107 | case VERSION_8: |
108 | case VERSION_9: | |
107 | 109 | loadVersions7AndUp (file); |
108 | 110 | break; |
109 | 111 | |
339 | 341 | |
340 | 342 | m_coordSystemContext.editPointAxis(posGraph, |
341 | 343 | identifier); |
344 | } | |
345 | ||
346 | void Document::editPointGraph (bool isX, | |
347 | bool isY, | |
348 | double x, | |
349 | double y, | |
350 | const QStringList &identifiers, | |
351 | const Transformation &transformation) | |
352 | { | |
353 | LOG4CPP_INFO_S ((*mainCat)) << "Document::editPointCurve"; | |
354 | ||
355 | m_coordSystemContext.editPointGraph (isX, | |
356 | isY, | |
357 | x, | |
358 | y, | |
359 | identifiers, | |
360 | transformation); | |
342 | 361 | } |
343 | 362 | |
344 | 363 | void Document::generateEmptyPixmap(const QXmlStreamAttributes &attributes) |
137 | 137 | void editPointAxis (const QPointF &posGraph, |
138 | 138 | const QString &identifier); |
139 | 139 | |
140 | /// Edit the graph coordinates of one or more graph points | |
141 | void editPointGraph (bool isX, | |
142 | bool isY, | |
143 | double x, | |
144 | double y, | |
145 | const QStringList &identifiers, | |
146 | const Transformation &transformation); | |
147 | ||
140 | 148 | /// Initialize grid display. This is called immediately after the transformation has been defined for the first time |
141 | 149 | void initializeGridDisplay (const Transformation &transformation); |
142 | 150 |
23 | 23 | const QString DOCUMENT_SERIALIZE_CMD_DELETE ("CmdDelete"); |
24 | 24 | const QString DOCUMENT_SERIALIZE_CMD_DESCRIPTION ("Description"); |
25 | 25 | const QString DOCUMENT_SERIALIZE_CMD_EDIT_POINT_AXIS ("CmdEditPointAxis"); |
26 | const QString DOCUMENT_SERIALIZE_CMD_EDIT_POINT_GRAPH ("CmdEditPointGraph"); | |
26 | 27 | const QString DOCUMENT_SERIALIZE_CMD_MEDIATOR ("CmdMediator"); |
27 | 28 | const QString DOCUMENT_SERIALIZE_CMD_MOVE_BY ("CmdMoveBy"); |
28 | 29 | const QString DOCUMENT_SERIALIZE_CMD_PASTE ("CmdPaste"); |
95 | 96 | const QString DOCUMENT_SERIALIZE_DIGITIZE_CURVE_CURSOR_SIZE ("CursorSize"); |
96 | 97 | const QString DOCUMENT_SERIALIZE_DIGITIZE_CURVE_CURSOR_STANDARD_CROSS ("CursorStandardCross"); |
97 | 98 | const QString DOCUMENT_SERIALIZE_DOCUMENT ("Document"); |
99 | const QString DOCUMENT_SERIALIZE_EDIT_GRAPH_IDENTIFIERS ("Identifiers"); | |
100 | const QString DOCUMENT_SERIALIZE_EDIT_GRAPH_IS_X ("IsX"); | |
101 | const QString DOCUMENT_SERIALIZE_EDIT_GRAPH_IS_Y ("IsY"); | |
102 | const QString DOCUMENT_SERIALIZE_EDIT_GRAPH_X ("X"); | |
103 | const QString DOCUMENT_SERIALIZE_EDIT_GRAPH_Y ("Y"); | |
98 | 104 | const QString DOCUMENT_SERIALIZE_ERROR ("Error"); |
99 | 105 | const QString DOCUMENT_SERIALIZE_ERROR_COMMENT ("Comment"); |
100 | 106 | const QString DOCUMENT_SERIALIZE_ERROR_CONTEXT ("Context"); |
27 | 27 | extern const QString DOCUMENT_SERIALIZE_CMD_DELETE; |
28 | 28 | extern const QString DOCUMENT_SERIALIZE_CMD_DESCRIPTION; |
29 | 29 | extern const QString DOCUMENT_SERIALIZE_CMD_EDIT_POINT_AXIS; |
30 | extern const QString DOCUMENT_SERIALIZE_CMD_EDIT_POINT_GRAPH; | |
30 | 31 | extern const QString DOCUMENT_SERIALIZE_CMD_MEDIATOR; |
31 | 32 | extern const QString DOCUMENT_SERIALIZE_CMD_MOVE_BY; |
32 | 33 | extern const QString DOCUMENT_SERIALIZE_CMD_PASTE; |
98 | 99 | extern const QString DOCUMENT_SERIALIZE_DIGITIZE_CURVE_CURSOR_SIZE; |
99 | 100 | extern const QString DOCUMENT_SERIALIZE_DIGITIZE_CURVE_CURSOR_STANDARD_CROSS; |
100 | 101 | extern const QString DOCUMENT_SERIALIZE_DOCUMENT; |
102 | extern const QString DOCUMENT_SERIALIZE_EDIT_GRAPH_IDENTIFIERS; | |
103 | extern const QString DOCUMENT_SERIALIZE_EDIT_GRAPH_IS_X; | |
104 | extern const QString DOCUMENT_SERIALIZE_EDIT_GRAPH_IS_Y; | |
105 | extern const QString DOCUMENT_SERIALIZE_EDIT_GRAPH_X; | |
106 | extern const QString DOCUMENT_SERIALIZE_EDIT_GRAPH_Y; | |
101 | 107 | extern const QString DOCUMENT_SERIALIZE_ERROR; |
102 | 108 | extern const QString DOCUMENT_SERIALIZE_ERROR_COMMENT; |
103 | 109 | extern const QString DOCUMENT_SERIALIZE_ERROR_CONTEXT; |
11 | 11 | switch (exportDelimiter) { |
12 | 12 | case EXPORT_DELIMITER_COMMA: |
13 | 13 | return QObject::tr ("Commas"); |
14 | ||
15 | case EXPORT_DELIMITER_SEMICOLON: | |
16 | return QObject::tr ("Semicolons"); | |
14 | 17 | |
15 | 18 | case EXPORT_DELIMITER_SPACE: |
16 | 19 | return QObject::tr ("Spaces"); |
34 | 37 | return ","; |
35 | 38 | } |
36 | 39 | |
40 | case EXPORT_DELIMITER_SEMICOLON: | |
41 | return ";"; | |
42 | ||
37 | 43 | case EXPORT_DELIMITER_SPACE: |
38 | 44 | return " "; |
39 | 45 |
9 | 9 | #include <QString> |
10 | 10 | |
11 | 11 | /// Delimiter values that may or may not be overridden by DOCUMENT_SERIALIZE_EXPORT_DELIMITER_OVERRIDE_CSV_TSV |
12 | /// for CSV and TSV files | |
12 | /// for CSV and TSV files. EXPORT_DELIMITER_SEMICOLON is not in alphabetical order since it was added after the code was released | |
13 | 13 | enum ExportDelimiter { |
14 | 14 | EXPORT_DELIMITER_COMMA, |
15 | 15 | EXPORT_DELIMITER_SPACE, |
16 | EXPORT_DELIMITER_TAB | |
16 | EXPORT_DELIMITER_TAB, | |
17 | EXPORT_DELIMITER_SEMICOLON | |
17 | 18 | }; |
18 | 19 | |
19 | 20 | extern QString exportDelimiterToString (ExportDelimiter exportDelimiter); // Text appearing in logging/debugging |
0 | /****************************************************************************************************** | |
1 | * (C) 2016 markummitchell@github.com. This file is part of Engauge Digitizer, which is released * | |
2 | * under GNU General Public License version 2 (GPLv2) or (at your option) any later version. See file * | |
3 | * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. * | |
4 | ******************************************************************************************************/ | |
5 | ||
6 | #include "GeometryModel.h" | |
7 | #include "GeometryWindow.h" | |
8 | #include "Logger.h" | |
9 | ||
10 | const int NO_HIGHLIGHTED_ROW = -1; | |
11 | ||
12 | GeometryModel::GeometryModel () : | |
13 | m_rowToBeHighlighted (NO_HIGHLIGHTED_ROW) | |
14 | { | |
15 | } | |
16 | ||
17 | GeometryModel::~GeometryModel() | |
18 | { | |
19 | } | |
20 | ||
21 | QVariant GeometryModel::data(const QModelIndex &index, int role) const | |
22 | { | |
23 | // LOG4CPP_DEBUG_S ((*mainCat)) << "GeometryModel::data" | |
24 | // << " rowHighlighted=" << m_rowToBeHighlighted | |
25 | // << " index=(row=" << index.row() << ",col=" << index.column() << ",role=" << role << ")=" | |
26 | // << " rows=" << rowCount() | |
27 | // << " cols=" << columnCount(); | |
28 | ||
29 | if ((role == Qt::BackgroundRole) && | |
30 | !m_pointIdentifier.isEmpty () && | |
31 | (index.row () == m_rowToBeHighlighted)) { | |
32 | ||
33 | // This row is to be highlighted | |
34 | return QVariant (QColor (230, 230, 230)); | |
35 | } | |
36 | ||
37 | // Standard behavior | |
38 | return QStandardItemModel::data (index, role); | |
39 | } | |
40 | ||
41 | int GeometryModel::rowToBeHighlighted () const | |
42 | { | |
43 | LOG4CPP_INFO_S ((*mainCat)) << "GeometryModel::rowToBeHighlighted" | |
44 | << " rows=" << rowCount() | |
45 | << " cols=" << columnCount(); | |
46 | ||
47 | for (int row = 0; row < rowCount(); row++) { | |
48 | ||
49 | // Look at the point identifier in the hidden column | |
50 | QModelIndex indexPointIdentifier = index (row, | |
51 | GeometryWindow::columnBodyPointIdentifiers ()); | |
52 | QVariant var = QStandardItemModel::data (indexPointIdentifier, Qt::DisplayRole); | |
53 | if (var.isValid()) { | |
54 | QString pointIdentifierGot = var.toString(); | |
55 | if (pointIdentifierGot == m_pointIdentifier) { | |
56 | ||
57 | // Found it | |
58 | return row; | |
59 | } | |
60 | } | |
61 | } | |
62 | ||
63 | // Fail | |
64 | return NO_HIGHLIGHTED_ROW; | |
65 | } | |
66 | ||
67 | void GeometryModel::setCurrentPointIdentifier (const QString &pointIdentifier) | |
68 | { | |
69 | LOG4CPP_INFO_S ((*mainCat)) << "GeometryModel::setCurrentPointIdentifier" | |
70 | << " rows=" << rowCount() | |
71 | << " cols=" << columnCount() | |
72 | << " identifier=" << pointIdentifier.toLatin1().data(); | |
73 | ||
74 | m_pointIdentifier = pointIdentifier; | |
75 | ||
76 | int rowTransitioned; | |
77 | if (!m_pointIdentifier.isEmpty ()) { | |
78 | ||
79 | // Get new row. It will transition from unhighlighted to highlighted | |
80 | m_rowToBeHighlighted = rowToBeHighlighted(); | |
81 | rowTransitioned = m_rowToBeHighlighted; | |
82 | ||
83 | } else { | |
84 | ||
85 | // Old row will transition from highlighted to unhighlighted | |
86 | rowTransitioned = m_rowToBeHighlighted; | |
87 | m_rowToBeHighlighted = NO_HIGHLIGHTED_ROW; | |
88 | ||
89 | } | |
90 | ||
91 | QModelIndex indexTopLeft = createIndex (rowTransitioned, 0); | |
92 | QModelIndex indexBottomRight = createIndex (rowTransitioned, columnCount() - 1); | |
93 | ||
94 | QVector<int> roles; | |
95 | roles << Qt::BackgroundRole; | |
96 | ||
97 | emit dataChanged (indexTopLeft, | |
98 | indexBottomRight, | |
99 | roles); | |
100 | } |
0 | /****************************************************************************************************** | |
1 | * (C) 2016 markummitchell@github.com. This file is part of Engauge Digitizer, which is released * | |
2 | * under GNU General Public License version 2 (GPLv2) or (at your option) any later version. See file * | |
3 | * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. * | |
4 | ******************************************************************************************************/ | |
5 | ||
6 | #ifndef GEOMETRY_MODEL_H | |
7 | #define GEOMETRY_MODEL_H | |
8 | ||
9 | #include <QStandardItemModel> | |
10 | #include <QString> | |
11 | ||
12 | /// Model that adds row highlighting according to the currently select point identifier | |
13 | class GeometryModel : public QStandardItemModel | |
14 | { | |
15 | public: | |
16 | /// Single constructor | |
17 | GeometryModel (); | |
18 | virtual ~GeometryModel (); | |
19 | ||
20 | /// Override for special processing | |
21 | virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; | |
22 | ||
23 | /// Set the point identifier to be highlighted. Value is empty for no highlighting | |
24 | void setCurrentPointIdentifier (const QString &pointIdentifier); | |
25 | ||
26 | private: | |
27 | ||
28 | int rowToBeHighlighted () const; | |
29 | ||
30 | int m_rowToBeHighlighted; | |
31 | QString m_pointIdentifier; // Point to be higlighted. Empty if none | |
32 | }; | |
33 | ||
34 | #endif // GEOMETRY_MODEL_H |
0 | /****************************************************************************************************** | |
1 | * (C) 2016 markummitchell@github.com. This file is part of Engauge Digitizer, which is released * | |
2 | * under GNU General Public License version 2 (GPLv2) or (at your option) any later version. See file * | |
3 | * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. * | |
4 | ******************************************************************************************************/ | |
5 | ||
6 | #include "EngaugeAssert.h" | |
7 | #include "FormatCoordsUnits.h" | |
8 | #include "GeometryStrategyAbstractBase.h" | |
9 | #include <qmath.h> | |
10 | #include <QPointF> | |
11 | #include "Spline.h" | |
12 | #include "SplinePair.h" | |
13 | #include "Transformation.h" | |
14 | #include <vector> | |
15 | ||
16 | using namespace std; | |
17 | ||
18 | GeometryStrategyAbstractBase::GeometryStrategyAbstractBase() | |
19 | { | |
20 | } | |
21 | ||
22 | GeometryStrategyAbstractBase::~GeometryStrategyAbstractBase() | |
23 | { | |
24 | } | |
25 | ||
26 | void GeometryStrategyAbstractBase::calculatePositionsGraph (const Points &points, | |
27 | const Transformation &transformation, | |
28 | QVector<QPointF> &positionsGraph) const | |
29 | { | |
30 | positionsGraph.clear(); | |
31 | ||
32 | for (int i = 0; i < points.size(); i++) { | |
33 | const Point &pointScreen = points [i]; | |
34 | QPointF posScreen = pointScreen.posScreen (); | |
35 | QPointF posGraph; | |
36 | ||
37 | transformation.transformScreenToRawGraph (posScreen, | |
38 | posGraph); | |
39 | ||
40 | positionsGraph.push_back (posGraph); | |
41 | } | |
42 | } | |
43 | ||
44 | double GeometryStrategyAbstractBase::functionArea (const QVector<QPointF> &positionsGraph) const | |
45 | { | |
46 | // Integrate using trapezoidal approximation to get the area under the function | |
47 | double sum = 0, xLast = 0, yLast = 0; | |
48 | for (int i = 1; i < positionsGraph.size (); i++) { | |
49 | double x = positionsGraph [i].x(); | |
50 | double y = positionsGraph [i].y(); | |
51 | double area = 0.5 * (y + yLast) * (x - xLast); | |
52 | sum += area; | |
53 | xLast = x; | |
54 | yLast = y; | |
55 | } | |
56 | ||
57 | return sum; | |
58 | } | |
59 | ||
60 | void GeometryStrategyAbstractBase::insertSubintervalsAndLoadDistances (int subintervalsPerInterval, | |
61 | const QVector<QPointF> &positionsGraph, | |
62 | QVector<QPointF> &positionsGraphWithSubintervals, | |
63 | QVector<QString> &distanceGraphForward, | |
64 | QVector<QString> &distancePercentForward, | |
65 | QVector<QString> &distanceGraphBackward, | |
66 | QVector<QString> &distancePercentBackward) const | |
67 | { | |
68 | if (positionsGraph.size () > 0) { | |
69 | ||
70 | int i; | |
71 | ||
72 | // Fit splines to the points | |
73 | vector<double> t; | |
74 | vector<SplinePair> xy; | |
75 | for (int i = 0; i < positionsGraph.size (); i++) { | |
76 | t.push_back ((double) i); | |
77 | xy.push_back (SplinePair (positionsGraph [i].x(), | |
78 | positionsGraph [i].y())); | |
79 | } | |
80 | ||
81 | Spline spline (t, | |
82 | xy); | |
83 | ||
84 | // Loop over the original points, with one original point per original interval | |
85 | QVector<double> distanceGraphDouble; | |
86 | double xLast = 0, yLast = 0, distance = 0; | |
87 | for (i = 0; i < positionsGraph.size(); i++) { | |
88 | ||
89 | // In the interval i-1 to i we insert points to create smaller subintervals | |
90 | for (int subinterval = 0; subinterval < subintervalsPerInterval; subinterval++) { | |
91 | ||
92 | // Go from i-1 (exclusive) to i (inclusive) | |
93 | double t = (double) (i - 1.0) + (double) (subinterval + 1) / (double) (subintervalsPerInterval); | |
94 | ||
95 | SplinePair splinePair = spline.interpolateCoeff (t); | |
96 | ||
97 | double x = splinePair.x (); | |
98 | double y = splinePair.y (); | |
99 | ||
100 | // All points from intervals where i>0, and last point from interval i=0 | |
101 | if (i > 0 || subinterval == subintervalsPerInterval - 1) { | |
102 | ||
103 | // Insert one of several new points for each original point | |
104 | positionsGraphWithSubintervals.push_back (QPointF (x, y)); | |
105 | ||
106 | } | |
107 | ||
108 | if (i > 0) { | |
109 | ||
110 | // Add to cumulative distance | |
111 | distance += qSqrt ((x - xLast) * (x - xLast) + (y - yLast) * (y - yLast)); | |
112 | ||
113 | } | |
114 | ||
115 | xLast = x; | |
116 | yLast = y; | |
117 | } | |
118 | ||
119 | // Insert one distance entry for each original point | |
120 | distanceGraphDouble.push_back (distance); | |
121 | } | |
122 | ||
123 | // Compute distance columns | |
124 | double dTotal = qMax (1.0, distanceGraphDouble [distanceGraphDouble.size() - 1]); // qMax prevents divide by zero | |
125 | for (i = 0; i < distanceGraphDouble.size (); i++) { | |
126 | double d = distanceGraphDouble [i]; | |
127 | distanceGraphForward.push_back (QString::number (d)); | |
128 | distancePercentForward.push_back (QString::number (100.0 * d / dTotal)); | |
129 | distanceGraphBackward.push_back (QString::number (dTotal - d)); | |
130 | distancePercentBackward.push_back (QString::number (100.0 * (dTotal - d) / dTotal)); | |
131 | } | |
132 | } | |
133 | } | |
134 | ||
135 | void GeometryStrategyAbstractBase::loadXY (const QVector<QPointF> &positionsGraph, | |
136 | const DocumentModelCoords &modelCoords, | |
137 | const MainWindowModel &modelMainWindow, | |
138 | const Transformation &transformation, | |
139 | QVector<QString> &x, | |
140 | QVector<QString> &y) const | |
141 | { | |
142 | FormatCoordsUnits formatCoordsUnits; | |
143 | ||
144 | for (int i = 0; i < positionsGraph.size(); i++) { | |
145 | ||
146 | double xI = positionsGraph [i].x(); | |
147 | double yI = positionsGraph [i].y(); | |
148 | ||
149 | QString xFormatted, yFormatted; | |
150 | formatCoordsUnits.unformattedToFormatted (xI, | |
151 | yI, | |
152 | modelCoords, | |
153 | modelMainWindow, | |
154 | xFormatted, | |
155 | yFormatted, | |
156 | transformation); | |
157 | x.push_back (xFormatted); | |
158 | y.push_back (yFormatted); | |
159 | ||
160 | } | |
161 | } | |
162 | ||
163 | double GeometryStrategyAbstractBase::polygonAreaForSimplyConnected (const QVector<QPointF> &points) const | |
164 | { | |
165 | // Shoelace formula | |
166 | int N = points.size (); | |
167 | ||
168 | double sum = 0.0; | |
169 | if (N > 0) { | |
170 | ||
171 | ||
172 | for (int i = 0; i < N - 1; i++) { | |
173 | sum += points [i].x() * points [i + 1].y() - points [i + 1].x() * points [i].y(); | |
174 | } | |
175 | ||
176 | sum += points [N - 1].x() * points [0].y() - points [0].x() * points [N - 1].y (); | |
177 | } | |
178 | ||
179 | return qAbs (sum) / 2.0; | |
180 | } |
0 | /****************************************************************************************************** | |
1 | * (C) 2016 markummitchell@github.com. This file is part of Engauge Digitizer, which is released * | |
2 | * under GNU General Public License version 2 (GPLv2) or (at your option) any later version. See file * | |
3 | * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. * | |
4 | ******************************************************************************************************/ | |
5 | ||
6 | #ifndef GEOMETRY_STRATEGY_ABSTRACT_BASE_H | |
7 | #define GEOMETRY_STRATEGY_ABSTRACT_BASE_H | |
8 | ||
9 | #include "Points.h" | |
10 | #include <QPolygonF> | |
11 | #include <QVector> | |
12 | ||
13 | class DocumentModelCoords; | |
14 | class MainWindowModel; | |
15 | class QPointF; | |
16 | class Transformation; | |
17 | ||
18 | /// Base class for all geometry strategies. Each strategy computes geometry parameters according to the curve's settings. | |
19 | /// | |
20 | /// The numbering for the strategies is specified as the CurveConnectAs enumeration | |
21 | class GeometryStrategyAbstractBase | |
22 | { | |
23 | public: | |
24 | /// Single constructor. | |
25 | GeometryStrategyAbstractBase(); | |
26 | virtual ~GeometryStrategyAbstractBase (); | |
27 | ||
28 | /// Calculate geometry parameters | |
29 | virtual void calculateGeometry (const Points &points, | |
30 | const DocumentModelCoords &modelCoords, | |
31 | const MainWindowModel &modelMainWindow, | |
32 | const Transformation &transformation, | |
33 | QString &funcArea, | |
34 | QString &polyArea, | |
35 | QVector<QString> &x, | |
36 | QVector<QString> &y, | |
37 | QVector<QString> &distanceGraphForward, | |
38 | QVector<QString> &distancePercentForward, | |
39 | QVector<QString> &distanceGraphBackward, | |
40 | QVector<QString> &distancePercentBackward) const = 0; | |
41 | ||
42 | protected: | |
43 | ||
44 | /// Convert screen positions to graph positions | |
45 | void calculatePositionsGraph (const Points &points, | |
46 | const Transformation &transformation, | |
47 | QVector<QPointF> &positionsGraph) const; | |
48 | ||
49 | /// Use trapezoidal approximation to compute area under the function. Does not apply to relation | |
50 | double functionArea (const QVector<QPointF> &positionsGraph) const; | |
51 | ||
52 | /// Insert the specified number of subintervals into each interval. For straight curves subintervalsPerInterval=1 so the | |
53 | /// linearity is maintained, and for smooth curves subintervalsPerInterval>1 so the geometry calculations take into account | |
54 | /// the curvature(s) of the line | |
55 | void insertSubintervalsAndLoadDistances (int subintervalsPerInterval, | |
56 | const QVector<QPointF> &positionsGraph, | |
57 | QVector<QPointF> &positionsGraphWithSubintervals, | |
58 | QVector<QString> &distanceGraphForward, | |
59 | QVector<QString> &distancePercentForward, | |
60 | QVector<QString> &distanceGraphBackward, | |
61 | QVector<QString> &distancePercentBackward) const; | |
62 | ||
63 | /// Load x and y coordinate vectors | |
64 | void loadXY (const QVector<QPointF> &positionsGraph, | |
65 | const DocumentModelCoords &modelCoords, | |
66 | const MainWindowModel &modelMainWindow, | |
67 | const Transformation &transformation, | |
68 | QVector<QString> &x, | |
69 | QVector<QString> &y) const; | |
70 | ||
71 | /// Area in polygon using Shoelace formula, which only works if polygon is simply connected. We do not | |
72 | /// check to see if the polygon is simply connected since that would be (1) slow and (2) much work | |
73 | double polygonAreaForSimplyConnected (const QVector<QPointF> &points) const; | |
74 | ||
75 | }; | |
76 | ||
77 | #endif // GEOMETRY_STRATEGY_ABSTRACT_BASE_H |
0 | /****************************************************************************************************** | |
1 | * (C) 2016 markummitchell@github.com. This file is part of Engauge Digitizer, which is released * | |
2 | * under GNU General Public License version 2 (GPLv2) or (at your option) any later version. See file * | |
3 | * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. * | |
4 | ******************************************************************************************************/ | |
5 | ||
6 | #include "CurveConnectAs.h" | |
7 | #include "GeometryStrategyContext.h" | |
8 | #include "GeometryStrategyFunctionSmooth.h" | |
9 | #include "GeometryStrategyFunctionStraight.h" | |
10 | #include "GeometryStrategyRelationSmooth.h" | |
11 | #include "GeometryStrategyRelationStraight.h" | |
12 | #include "Transformation.h" | |
13 | ||
14 | GeometryStrategyContext::GeometryStrategyContext() | |
15 | { | |
16 | m_strategies.insert (CONNECT_AS_FUNCTION_SMOOTH , new GeometryStrategyFunctionSmooth ()); | |
17 | m_strategies.insert (CONNECT_AS_FUNCTION_STRAIGHT, new GeometryStrategyFunctionStraight ()); | |
18 | m_strategies.insert (CONNECT_AS_RELATION_SMOOTH , new GeometryStrategyRelationSmooth ()); | |
19 | m_strategies.insert (CONNECT_AS_RELATION_STRAIGHT, new GeometryStrategyRelationStraight ()); | |
20 | } | |
21 | ||
22 | GeometryStrategyContext::~GeometryStrategyContext() | |
23 | { | |
24 | } | |
25 | ||
26 | void GeometryStrategyContext::calculateGeometry (const Points &points, | |
27 | const DocumentModelCoords &modelCoords, | |
28 | const MainWindowModel &modelMainWindow, | |
29 | const Transformation &transformation, | |
30 | CurveConnectAs connectAs, | |
31 | QString &funcArea, | |
32 | QString &polyArea, | |
33 | QVector<QString> &x, | |
34 | QVector<QString> &y, | |
35 | QVector<QString> &distanceGraphForward, | |
36 | QVector<QString> &distancePercentForward, | |
37 | QVector<QString> &distanceGraphBackward, | |
38 | QVector<QString> &distancePercentBackward) const | |
39 | { | |
40 | m_strategies [connectAs]->calculateGeometry (points, | |
41 | modelCoords, | |
42 | modelMainWindow, | |
43 | transformation, | |
44 | funcArea, | |
45 | polyArea, | |
46 | x, | |
47 | y, | |
48 | distanceGraphForward, | |
49 | distancePercentForward, | |
50 | distanceGraphBackward, | |
51 | distancePercentBackward); | |
52 | } | |
53 |
0 | /****************************************************************************************************** | |
1 | * (C) 2016 markummitchell@github.com. This file is part of Engauge Digitizer, which is released * | |
2 | * under GNU General Public License version 2 (GPLv2) or (at your option) any later version. See file * | |
3 | * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. * | |
4 | ******************************************************************************************************/ | |
5 | ||
6 | #ifndef GEOMETRY_STRATEGY_CONTEXT_H | |
7 | #define GEOMETRY_STRATEGY_CONTEXT_H | |
8 | ||
9 | #include "CurveConnectAs.h" | |
10 | #include "MainWindowModel.h" | |
11 | #include "Points.h" | |
12 | #include <QVector> | |
13 | ||
14 | class DocumentModelCoords; | |
15 | class GeometryStrategyAbstractBase; | |
16 | class Transformation; | |
17 | ||
18 | /// Class for that manages geometry strategies | |
19 | class GeometryStrategyContext | |
20 | { | |
21 | public: | |
22 | /// Single constructor. | |
23 | GeometryStrategyContext(); | |
24 | virtual ~GeometryStrategyContext (); | |
25 | ||
26 | /// Calculate geometry parameters | |
27 | void calculateGeometry (const Points &points, | |
28 | const DocumentModelCoords &modelCoords, | |
29 | const MainWindowModel &modelMainWindow, | |
30 | const Transformation &transformation, | |
31 | CurveConnectAs connectAs, | |
32 | QString &funcArea, | |
33 | QString &polyArea, | |
34 | QVector<QString> &x, | |
35 | QVector<QString> &y, | |
36 | QVector<QString> &distanceGraphForward, | |
37 | QVector<QString> &distancePercentForward, | |
38 | QVector<QString> &distanceGraphBackward, | |
39 | QVector<QString> &distancePercentBackward) const; | |
40 | ||
41 | private: | |
42 | ||
43 | QVector<GeometryStrategyAbstractBase*> m_strategies; | |
44 | ||
45 | }; | |
46 | ||
47 | #endif // GEOMETRY_STRATEGY_CONTEXT_H |
0 | /****************************************************************************************************** | |
1 | * (C) 2016 markummitchell@github.com. This file is part of Engauge Digitizer, which is released * | |
2 | * under GNU General Public License version 2 (GPLv2) or (at your option) any later version. See file * | |
3 | * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. * | |
4 | ******************************************************************************************************/ | |
5 | ||
6 | #include "GeometryStrategyFunctionSmooth.h" | |
7 | #include "Transformation.h" | |
8 | ||
9 | GeometryStrategyFunctionSmooth::GeometryStrategyFunctionSmooth() | |
10 | { | |
11 | } | |
12 | ||
13 | GeometryStrategyFunctionSmooth::~GeometryStrategyFunctionSmooth() | |
14 | { | |
15 | } | |
16 | ||
17 | void GeometryStrategyFunctionSmooth::calculateGeometry (const Points &points, | |
18 | const DocumentModelCoords &modelCoords, | |
19 | const MainWindowModel &modelMainWindow, | |
20 | const Transformation &transformation, | |
21 | QString &funcArea, | |
22 | QString &polyArea, | |
23 | QVector<QString> &x, | |
24 | QVector<QString> &y, | |
25 | QVector<QString> &distanceGraphForward, | |
26 | QVector<QString> &distancePercentForward, | |
27 | QVector<QString> &distanceGraphBackward, | |
28 | QVector<QString> &distancePercentBackward) const | |
29 | { | |
30 | const int NUM_SUB_INTERVALS_SMOOTH = 10; // One input point becomes NUM_SUB_INTERVALS points to account for smoothing | |
31 | ||
32 | QVector<QPointF> positionsGraph, positionsGraphWithSubintervals; | |
33 | calculatePositionsGraph (points, | |
34 | transformation, | |
35 | positionsGraph); | |
36 | ||
37 | insertSubintervalsAndLoadDistances (NUM_SUB_INTERVALS_SMOOTH, | |
38 | positionsGraph, | |
39 | positionsGraphWithSubintervals, | |
40 | distanceGraphForward, | |
41 | distancePercentForward, | |
42 | distanceGraphBackward, | |
43 | distancePercentBackward); | |
44 | double fArea = functionArea (positionsGraphWithSubintervals); | |
45 | ||
46 | loadXY (positionsGraph, | |
47 | modelCoords, | |
48 | modelMainWindow, | |
49 | transformation, | |
50 | x, | |
51 | y); | |
52 | ||
53 | // Set header values | |
54 | funcArea = QString::number (fArea); | |
55 | polyArea = ""; | |
56 | } |
0 | /****************************************************************************************************** | |
1 | * (C) 2016 markummitchell@github.com. This file is part of Engauge Digitizer, which is released * | |
2 | * under GNU General Public License version 2 (GPLv2) or (at your option) any later version. See file * | |
3 | * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. * | |
4 | ******************************************************************************************************/ | |
5 | ||
6 | #ifndef GEOMETRY_STRATEGY_FUNCTION_SMOOTH_H | |
7 | #define GEOMETRY_STRATEGY_FUNCTION_SMOOTH_H | |
8 | ||
9 | #include "GeometryStrategyAbstractBase.h" | |
10 | #include <QVector> | |
11 | ||
12 | class Transformation; | |
13 | ||
14 | /// Calculate for line through the points that is smoothly connected as a function | |
15 | class GeometryStrategyFunctionSmooth : public GeometryStrategyAbstractBase | |
16 | { | |
17 | public: | |
18 | /// Single constructor. | |
19 | GeometryStrategyFunctionSmooth(); | |
20 | virtual ~GeometryStrategyFunctionSmooth (); | |
21 | ||
22 | /// Calculate geometry parameters | |
23 | virtual void calculateGeometry (const Points &points, | |
24 | const DocumentModelCoords &modelCoords, | |
25 | const MainWindowModel &modelMainWindow, | |
26 | const Transformation &transformation, | |
27 | QString &funcArea, | |
28 | QString &polyArea, | |
29 | QVector<QString> &x, | |
30 | QVector<QString> &y, | |
31 | QVector<QString> &distanceGraphForward, | |
32 | QVector<QString> &distancePercentForward, | |
33 | QVector<QString> &distanceGraphBackward, | |
34 | QVector<QString> &distancePercentBackward) const; | |
35 | ||
36 | }; | |
37 | ||
38 | #endif // GEOMETRY_STRATEGY_FUNCTION_SMOOTH_H |
0 | /****************************************************************************************************** | |
1 | * (C) 2016 markummitchell@github.com. This file is part of Engauge Digitizer, which is released * | |
2 | * under GNU General Public License version 2 (GPLv2) or (at your option) any later version. See file * | |
3 | * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. * | |
4 | ******************************************************************************************************/ | |
5 | ||
6 | #include "GeometryStrategyFunctionStraight.h" | |
7 | #include "Transformation.h" | |
8 | ||
9 | GeometryStrategyFunctionStraight::GeometryStrategyFunctionStraight() | |
10 | { | |
11 | } | |
12 | ||
13 | GeometryStrategyFunctionStraight::~GeometryStrategyFunctionStraight() | |
14 | { | |
15 | } | |
16 | ||
17 | void GeometryStrategyFunctionStraight::calculateGeometry (const Points &points, | |
18 | const DocumentModelCoords &modelCoords, | |
19 | const MainWindowModel &modelMainWindow, | |
20 | const Transformation &transformation, | |
21 | QString &funcArea, | |
22 | QString &polyArea, | |
23 | QVector<QString> &x, | |
24 | QVector<QString> &y, | |
25 | QVector<QString> &distanceGraphForward, | |
26 | QVector<QString> &distancePercentForward, | |
27 | QVector<QString> &distanceGraphBackward, | |
28 | QVector<QString> &distancePercentBackward) const | |
29 | { | |
30 | const int NUM_SUB_INTERVALS_STRAIGHT = 1; // Value of one with trapezoidal integration results in calculations using straight lines between points | |
31 | ||
32 | QVector<QPointF> positionsGraph, positionsGraphWithSubintervals; | |
33 | calculatePositionsGraph (points, | |
34 | transformation, | |
35 | positionsGraph); | |
36 | ||
37 | insertSubintervalsAndLoadDistances (NUM_SUB_INTERVALS_STRAIGHT, | |
38 | positionsGraph, | |
39 | positionsGraphWithSubintervals, | |
40 | distanceGraphForward, | |
41 | distancePercentForward, | |
42 | distanceGraphBackward, | |
43 | distancePercentBackward); | |
44 | double fArea = functionArea (positionsGraphWithSubintervals); | |
45 | ||
46 | loadXY (positionsGraph, | |
47 | modelCoords, | |
48 | modelMainWindow, | |
49 | transformation, | |
50 | x, | |
51 | y); | |
52 | ||
53 | // Set header values | |
54 | funcArea = QString::number (fArea); | |
55 | polyArea = ""; | |
56 | } |
0 | /****************************************************************************************************** | |
1 | * (C) 2016 markummitchell@github.com. This file is part of Engauge Digitizer, which is released * | |
2 | * under GNU General Public License version 2 (GPLv2) or (at your option) any later version. See file * | |
3 | * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. * | |
4 | ******************************************************************************************************/ | |
5 | ||
6 | #ifndef GEOMETRY_STRATEGY_FUNCTION_STRAIGHT_H | |
7 | #define GEOMETRY_STRATEGY_FUNCTION_STRAIGHT_H | |
8 | ||
9 | #include "GeometryStrategyAbstractBase.h" | |
10 | #include <QVector> | |
11 | ||
12 | class Transformation; | |
13 | ||
14 | /// Calculate for line through the points that is straightly connected as a function | |
15 | class GeometryStrategyFunctionStraight : public GeometryStrategyAbstractBase | |
16 | { | |
17 | public: | |
18 | /// Single constructor. | |
19 | GeometryStrategyFunctionStraight(); | |
20 | virtual ~GeometryStrategyFunctionStraight (); | |
21 | ||
22 | /// Calculate geometry parameters | |
23 | virtual void calculateGeometry (const Points &points, | |
24 | const DocumentModelCoords &modelCoords, | |
25 | const MainWindowModel &modelMainWindow, | |
26 | const Transformation &transformation, | |
27 | QString &funcArea, | |
28 | QString &polyArea, | |
29 | QVector<QString> &x, | |
30 | QVector<QString> &y, | |
31 | QVector<QString> &distanceGraphForward, | |
32 | QVector<QString> &distancePercentForward, | |
33 | QVector<QString> &distanceGraphBackward, | |
34 | QVector<QString> &distancePercentBackward) const; | |
35 | ||
36 | }; | |
37 | ||
38 | #endif // GEOMETRY_STRATEGY_FUNCTION_STRAIGHT_H |
0 | /****************************************************************************************************** | |
1 | * (C) 2016 markummitchell@github.com. This file is part of Engauge Digitizer, which is released * | |
2 | * under GNU General Public License version 2 (GPLv2) or (at your option) any later version. See file * | |
3 | * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. * | |
4 | ******************************************************************************************************/ | |
5 | ||
6 | #include "GeometryStrategyRelationSmooth.h" | |
7 | #include "Transformation.h" | |
8 | ||
9 | GeometryStrategyRelationSmooth::GeometryStrategyRelationSmooth() | |
10 | { | |
11 | } | |
12 | ||
13 | GeometryStrategyRelationSmooth::~GeometryStrategyRelationSmooth() | |
14 | { | |
15 | } | |
16 | ||
17 | void GeometryStrategyRelationSmooth::calculateGeometry (const Points &points, | |
18 | const DocumentModelCoords &modelCoords, | |
19 | const MainWindowModel &modelMainWindow, | |
20 | const Transformation &transformation, | |
21 | QString &funcArea, | |
22 | QString &polyArea, | |
23 | QVector<QString> &x, | |
24 | QVector<QString> &y, | |
25 | QVector<QString> &distanceGraphForward, | |
26 | QVector<QString> &distancePercentForward, | |
27 | QVector<QString> &distanceGraphBackward, | |
28 | QVector<QString> &distancePercentBackward) const | |
29 | { | |
30 | const int NUM_SUB_INTERVALS_SMOOTH = 10; // One input point becomes NUM_SUB_INTERVALS points to account for smoothing | |
31 | ||
32 | QVector<QPointF> positionsGraph, positionsGraphWithSubintervals; | |
33 | calculatePositionsGraph (points, | |
34 | transformation, | |
35 | positionsGraph); | |
36 | ||
37 | insertSubintervalsAndLoadDistances (NUM_SUB_INTERVALS_SMOOTH, | |
38 | positionsGraph, | |
39 | positionsGraphWithSubintervals, | |
40 | distanceGraphForward, | |
41 | distancePercentForward, | |
42 | distanceGraphBackward, | |
43 | distancePercentBackward); | |
44 | double pArea = polygonAreaForSimplyConnected (positionsGraphWithSubintervals); | |
45 | ||
46 | loadXY (positionsGraph, | |
47 | modelCoords, | |
48 | modelMainWindow, | |
49 | transformation, | |
50 | x, | |
51 | y); | |
52 | ||
53 | // Set header values | |
54 | funcArea = ""; | |
55 | polyArea = QString::number (pArea); | |
56 | } |
0 | /****************************************************************************************************** | |
1 | * (C) 2016 markummitchell@github.com. This file is part of Engauge Digitizer, which is released * | |
2 | * under GNU General Public License version 2 (GPLv2) or (at your option) any later version. See file * | |
3 | * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. * | |
4 | ******************************************************************************************************/ | |
5 | ||
6 | #ifndef GEOMETRY_STRATEGY_RELATION_SMOOTH_H | |
7 | #define GEOMETRY_STRATEGY_RELATION_SMOOTH_H | |
8 | ||
9 | #include "GeometryStrategyAbstractBase.h" | |
10 | #include <QVector> | |
11 | ||
12 | class Transformation; | |
13 | ||
14 | /// Calculate for line through the points that is smoothly connected as a relation | |
15 | class GeometryStrategyRelationSmooth : public GeometryStrategyAbstractBase | |
16 | { | |
17 | public: | |
18 | /// Single constructor. | |
19 | GeometryStrategyRelationSmooth(); | |
20 | virtual ~GeometryStrategyRelationSmooth (); | |
21 | ||
22 | /// Calculate geometry parameters | |
23 | virtual void calculateGeometry (const Points &points, | |
24 | const DocumentModelCoords &modelCoords, | |
25 | const MainWindowModel &modelMainWindow, | |
26 | const Transformation &transformation, | |
27 | QString &funcArea, | |
28 | QString &polyArea, | |
29 | QVector<QString> &x, | |
30 | QVector<QString> &y, | |
31 | QVector<QString> &distanceGraphForward, | |
32 | QVector<QString> &distancePercentForward, | |
33 | QVector<QString> &distanceGraphBackward, | |
34 | QVector<QString> &distancePercentBackward) const; | |
35 | ||
36 | }; | |
37 | ||
38 | #endif // GEOMETRY_STRATEGY_RELATION_SMOOTH_H |
0 | /****************************************************************************************************** | |
1 | * (C) 2016 markummitchell@github.com. This file is part of Engauge Digitizer, which is released * | |
2 | * under GNU General Public License version 2 (GPLv2) or (at your option) any later version. See file * | |
3 | * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. * | |
4 | ******************************************************************************************************/ | |
5 | ||
6 | #include "GeometryStrategyRelationStraight.h" | |
7 | #include "Transformation.h" | |
8 | ||
9 | GeometryStrategyRelationStraight::GeometryStrategyRelationStraight() | |
10 | { | |
11 | } | |
12 | ||
13 | GeometryStrategyRelationStraight::~GeometryStrategyRelationStraight() | |
14 | { | |
15 | } | |
16 | ||
17 | void GeometryStrategyRelationStraight::calculateGeometry (const Points &points, | |
18 | const DocumentModelCoords &modelCoords, | |
19 | const MainWindowModel &modelMainWindow, | |
20 | const Transformation &transformation, | |
21 | QString &funcArea, | |
22 | QString &polyArea, | |
23 | QVector<QString> &x, | |
24 | QVector<QString> &y, | |
25 | QVector<QString> &distanceGraphForward, | |
26 | QVector<QString> &distancePercentForward, | |
27 | QVector<QString> &distanceGraphBackward, | |
28 | QVector<QString> &distancePercentBackward) const | |
29 | { | |
30 | const int NUM_SUB_INTERVALS_STRAIGHT = 1; // Value of one with trapezoidal integration results in calculations using straight lines between points | |
31 | ||
32 | QVector<QPointF> positionsGraph, positionsGraphWithSubintervals; | |
33 | calculatePositionsGraph (points, | |
34 | transformation, | |
35 | positionsGraph); | |
36 | ||
37 | insertSubintervalsAndLoadDistances (NUM_SUB_INTERVALS_STRAIGHT, | |
38 | positionsGraph, | |
39 | positionsGraphWithSubintervals, | |
40 | distanceGraphForward, | |
41 | distancePercentForward, | |
42 | distanceGraphBackward, | |
43 | distancePercentBackward); | |
44 | double pArea = polygonAreaForSimplyConnected (positionsGraphWithSubintervals); | |
45 | ||
46 | loadXY (positionsGraph, | |
47 | modelCoords, | |
48 | modelMainWindow, | |
49 | transformation, | |
50 | x, | |
51 | y); | |
52 | ||
53 | // Set header values | |
54 | funcArea = ""; | |
55 | polyArea = QString::number (pArea); | |
56 | } |
0 | /****************************************************************************************************** | |
1 | * (C) 2016 markummitchell@github.com. This file is part of Engauge Digitizer, which is released * | |
2 | * under GNU General Public License version 2 (GPLv2) or (at your option) any later version. See file * | |
3 | * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. * | |
4 | ******************************************************************************************************/ | |
5 | ||
6 | #ifndef GEOMETRY_STRATEGY_RELATION_STRAIGHT_H | |
7 | #define GEOMETRY_STRATEGY_RELATION_STRAIGHT_H | |
8 | ||
9 | #include "GeometryStrategyAbstractBase.h" | |
10 | #include <QVector> | |
11 | ||
12 | class Transformation; | |
13 | ||
14 | /// Calculate for line through the points that is straightly connected as a relation | |
15 | class GeometryStrategyRelationStraight : public GeometryStrategyAbstractBase | |
16 | { | |
17 | public: | |
18 | /// Single constructor. | |
19 | GeometryStrategyRelationStraight(); | |
20 | virtual ~GeometryStrategyRelationStraight (); | |
21 | ||
22 | /// Calculate geometry parameters | |
23 | virtual void calculateGeometry (const Points &points, | |
24 | const DocumentModelCoords &modelCoords, | |
25 | const MainWindowModel &modelMainWindow, | |
26 | const Transformation &transformation, | |
27 | QString &funcArea, | |
28 | QString &polyArea, | |
29 | QVector<QString> &x, | |
30 | QVector<QString> &y, | |
31 | QVector<QString> &distanceGraphForward, | |
32 | QVector<QString> &distancePercentForward, | |
33 | QVector<QString> &distanceGraphBackward, | |
34 | QVector<QString> &distancePercentBackward) const; | |
35 | ||
36 | }; | |
37 | ||
38 | #endif // GEOMETRY_STRATEGY_RELATION_STRAIGHT_H |
0 | /****************************************************************************************************** | |
1 | * (C) 2016 markummitchell@github.com. This file is part of Engauge Digitizer, which is released * | |
2 | * under GNU General Public License version 2 (GPLv2) or (at your option) any later version. See file * | |
3 | * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. * | |
4 | ******************************************************************************************************/ | |
5 | ||
6 | #include "CallbackGatherXThetaValuesFunctions.h" | |
7 | #include "CmdMediator.h" | |
8 | #include "Curve.h" | |
9 | #include "CurveConnectAs.h" | |
10 | #include "CurveStyle.h" | |
11 | #include "EngaugeAssert.h" | |
12 | #include "GeometryModel.h" | |
13 | #include "GeometryWindow.h" | |
14 | #include "Logger.h" | |
15 | #include <QApplication> | |
16 | #include <QClipboard> | |
17 | #include <QHeaderView> | |
18 | #include <QItemSelectionModel> | |
19 | #include <QTableView> | |
20 | #include <QTextStream> | |
21 | ||
22 | // Token constraints: | |
23 | // (1) should fit nicely into narrow columns. This eliminates details like Forward and Backward in the distance parameter tokens | |
24 | // (2) should not have any spaces. This simplifies copying and pasting into spreadsheet programs | |
25 | const QString TokenName (QObject::tr ("CurveName:")); | |
26 | const QString TokenFunctionArea (QObject::tr ("FunctionArea:")); | |
27 | const QString TokenPolygonArea (QObject::tr ("PolygonArea:")); | |
28 | const QString TokenX (QObject::tr ("X")); | |
29 | const QString TokenY (QObject::tr ("Y")); | |
30 | const QString TokenIndex (QObject::tr ("Index")); | |
31 | const QString TokenDistanceGraph (QObject::tr ("Distance")); | |
32 | const QString TokenDistancePercent (QObject::tr ("Percent")); | |
33 | ||
34 | GeometryWindow::GeometryWindow (QWidget *parent) : | |
35 | QDockWidget (parent) | |
36 | { | |
37 | setVisible (false); | |
38 | setAllowedAreas (Qt::AllDockWidgetAreas); | |
39 | setWindowTitle (tr ("Geometry Window")); // Appears in title bar when undocked | |
40 | setStatusTip (tr ("Geometry Window")); | |
41 | setWhatsThis (tr ("Geometry Window\n\n" | |
42 | "This table displays the following geometry data for the currently selected curve:\n\n" | |
43 | "Function area = Area under the curve if it is a function\n\n" | |
44 | "Polygon area = Area inside the curve if it is a relation. This value is only correct " | |
45 | "if none of the curve lines intersect each other\n\n" | |
46 | "X = X coordinate of each point\n\n" | |
47 | "Y = Y coordinate of each point\n\n" | |
48 | "Index = Point number\n\n" | |
49 | "Distance = Distance along the curve in forward or backward direction, in either graph units " | |
50 | "or as a percentage")); | |
51 | ||
52 | m_model = new GeometryModel; | |
53 | ||
54 | m_view = new QTableView; | |
55 | m_view->setModel (m_model); // Call before setSelectionModel since this also overrides the selection model | |
56 | m_view->horizontalHeader()->hide(); | |
57 | m_view->verticalHeader()->hide(); | |
58 | m_view->setEditTriggers(QAbstractItemView::NoEditTriggers); // Control is read only | |
59 | connect (m_view->selectionModel(), SIGNAL (selectionChanged (const QItemSelection &, const QItemSelection &)), | |
60 | this, SLOT (slotSelectionChanged (const QItemSelection &, const QItemSelection &))); | |
61 | ||
62 | setWidget (m_view); | |
63 | ||
64 | loadStrategies(); | |
65 | ||
66 | initializeHeader (); | |
67 | } | |
68 | ||
69 | GeometryWindow::~GeometryWindow() | |
70 | { | |
71 | } | |
72 | ||
73 | void GeometryWindow::clear () | |
74 | { | |
75 | // Resize table to remove stale body data | |
76 | resizeTable (NUM_HEADER_ROWS); | |
77 | ||
78 | // Clear stale header data values | |
79 | for (int row = 0; row < NUM_HEADER_ROWS - 1; row++) { | |
80 | m_model->setItem (row, COLUMN_HEADER_VALUE, new QStandardItem ("")); | |
81 | } | |
82 | } | |
83 | ||
84 | void GeometryWindow::closeEvent(QCloseEvent * /* event */) | |
85 | { | |
86 | LOG4CPP_INFO_S ((*mainCat)) << "GeometryWindow::closeEvent"; | |
87 | ||
88 | emit signalGeometryWindowClosed(); | |
89 | } | |
90 | ||
91 | int GeometryWindow::fold2dIndexes (int row, | |
92 | int col, | |
93 | int rowLow, | |
94 | int colLow, | |
95 | int colHigh) const | |
96 | { | |
97 | return (row - rowLow) * (colHigh - colLow + 1) + (col - colLow); | |
98 | } | |
99 | ||
100 | int GeometryWindow::columnBodyPointIdentifiers () | |
101 | { | |
102 | return COLUMN_BODY_POINT_IDENTIFIERS; | |
103 | } | |
104 | ||
105 | void GeometryWindow::initializeHeader () | |
106 | { | |
107 | LOG4CPP_INFO_S ((*mainCat)) << "GeometryWindow::initializeHeader"; | |
108 | ||
109 | resizeTable (NUM_HEADER_ROWS); | |
110 | ||
111 | m_model->setItem (HEADER_ROW_NAME, COLUMN_HEADER_LABEL, new QStandardItem (TokenName)); | |
112 | m_model->setItem (HEADER_ROW_FUNC_AREA, COLUMN_HEADER_LABEL, new QStandardItem (TokenFunctionArea)); | |
113 | m_model->setItem (HEADER_ROW_POLY_AREA, COLUMN_HEADER_LABEL, new QStandardItem (TokenPolygonArea)); | |
114 | m_model->setItem (HEADER_ROW_COLUMN_NAMES, COLUMN_BODY_X, new QStandardItem (TokenX)); | |
115 | m_model->setItem (HEADER_ROW_COLUMN_NAMES, COLUMN_BODY_Y, new QStandardItem (TokenY)); | |
116 | m_model->setItem (HEADER_ROW_COLUMN_NAMES, COLUMN_BODY_INDEX, new QStandardItem (TokenIndex)); | |
117 | m_model->setItem (HEADER_ROW_COLUMN_NAMES, COLUMN_BODY_DISTANCE_GRAPH_FORWARD, new QStandardItem (TokenDistanceGraph)); | |
118 | m_model->setItem (HEADER_ROW_COLUMN_NAMES, COLUMN_BODY_DISTANCE_PERCENT_FORWARD, new QStandardItem (TokenDistancePercent)); | |
119 | m_model->setItem (HEADER_ROW_COLUMN_NAMES, COLUMN_BODY_DISTANCE_GRAPH_BACKWARD, new QStandardItem (TokenDistanceGraph)); | |
120 | m_model->setItem (HEADER_ROW_COLUMN_NAMES, COLUMN_BODY_DISTANCE_PERCENT_BACKWARD, new QStandardItem (TokenDistancePercent)); | |
121 | } | |
122 | ||
123 | void GeometryWindow::loadStrategies () | |
124 | { | |
125 | LOG4CPP_INFO_S ((*mainCat)) << "GeometryWindow::loadStrategies"; | |
126 | } | |
127 | ||
128 | void GeometryWindow::resizeTable (int rowCount) | |
129 | { | |
130 | LOG4CPP_INFO_S ((*mainCat)) << "GeometryWindow::resizeTable"; | |
131 | ||
132 | unselectAll(); | |
133 | ||
134 | m_model->setRowCount (rowCount); | |
135 | m_model->setColumnCount (NUM_BODY_COLUMNS); | |
136 | ||
137 | } | |
138 | ||
139 | void GeometryWindow::slotPointHoverEnter (QString pointIdentifier) | |
140 | { | |
141 | m_model->setCurrentPointIdentifier (pointIdentifier); | |
142 | } | |
143 | ||
144 | void GeometryWindow::slotPointHoverLeave (QString /* pointIdentifier */) | |
145 | { | |
146 | m_model->setCurrentPointIdentifier (""); | |
147 | } | |
148 | ||
149 | void GeometryWindow::slotSelectionChanged (const QItemSelection & /* selected */, | |
150 | const QItemSelection & /* deselected */) | |
151 | { | |
152 | const bool NOT_GNUPLOT = false; | |
153 | ||
154 | QItemSelectionModel *selectionModel = m_view->selectionModel (); | |
155 | QModelIndexList selection = selectionModel->selectedIndexes (); | |
156 | ||
157 | if (selection.size () > 0) { | |
158 | ||
159 | // Gather input. A rectangular grid that encompasses all selected indexes will be copied | |
160 | int rowLow = 0, rowHigh = 0, colLow = 0, colHigh = 0; | |
161 | bool isFirst = true; | |
162 | for (QModelIndexList::const_iterator itr = selection.begin(); itr != selection.end(); itr++) { | |
163 | QModelIndex index = *itr; | |
164 | if (isFirst || index.row () < rowLow ) rowLow = index.row (); | |
165 | if (isFirst || index.row () > rowHigh) rowHigh = index.row (); | |
166 | if (isFirst || index.column () < colLow ) colLow = index.column (); | |
167 | if (isFirst || index.column () > colHigh) colHigh = index.column (); | |
168 | isFirst = false; | |
169 | } | |
170 | ||
171 | int numRows = rowHigh - rowLow + 1; | |
172 | int numCols = colHigh - colLow + 1; | |
173 | ||
174 | // Put data into two dimensional rowXcolumn table is handled as a flattened vector. Table is initialized | |
175 | // with empty strings | |
176 | QVector<QString> table (numRows * numCols); | |
177 | ||
178 | for (int i = 0; i < selection.size (); i++) { | |
179 | QModelIndex index = selection [i]; | |
180 | QVariant data = m_model->data (index); | |
181 | QString text = data.toString (); | |
182 | table [fold2dIndexes (index.row(), index.column(), rowLow, colLow, colHigh)] = text; | |
183 | } | |
184 | ||
185 | // Concatenate table into output string | |
186 | QString output; | |
187 | QTextStream str (&output); | |
188 | for (int row = rowLow; row <= rowHigh; row++) { | |
189 | QString delimiter; | |
190 | for (int col = colLow; col <= colHigh; col++) { | |
191 | str << delimiter << table [fold2dIndexes (row, col, rowLow, colLow, colHigh)]; | |
192 | delimiter = exportDelimiterToText (m_modelExport.delimiter(), | |
193 | NOT_GNUPLOT); | |
194 | } | |
195 | str << "\n"; | |
196 | } | |
197 | ||
198 | // Save to clipboard | |
199 | QApplication::clipboard ()->setText (output); | |
200 | } | |
201 | } | |
202 | ||
203 | void GeometryWindow::update (const CmdMediator &cmdMediator, | |
204 | const MainWindowModel &modelMainWindow, | |
205 | const QString &curveSelected, | |
206 | const Transformation &transformation) | |
207 | { | |
208 | LOG4CPP_INFO_S ((*mainCat)) << "GeometryWindow::update"; | |
209 | ||
210 | // Save export format | |
211 | m_modelExport = cmdMediator.document().modelExport(); | |
212 | ||
213 | // Gather and calculate geometry data | |
214 | const Curve *curve = cmdMediator.document().curveForCurveName (curveSelected); | |
215 | ||
216 | ENGAUGE_CHECK_PTR (curve); | |
217 | ||
218 | const Points points = curve->points(); | |
219 | ||
220 | QString funcArea, polyArea; | |
221 | QVector<QString> x, y, distanceGraphForward, distancePercentForward, distanceGraphBackward, distancePercentBackward; | |
222 | ||
223 | CurveStyle curveStyle = cmdMediator.document().modelCurveStyles().curveStyle (curveSelected); | |
224 | m_geometryStrategyContext.calculateGeometry (points, | |
225 | cmdMediator.document().modelCoords(), | |
226 | modelMainWindow, | |
227 | transformation, | |
228 | curveStyle.lineStyle().curveConnectAs(), | |
229 | funcArea, | |
230 | polyArea, | |
231 | x, | |
232 | y, | |
233 | distanceGraphForward, | |
234 | distancePercentForward, | |
235 | distanceGraphBackward, | |
236 | distancePercentBackward); | |
237 | ||
238 | // Output to table | |
239 | resizeTable (NUM_HEADER_ROWS + points.count()); | |
240 | ||
241 | m_model->setItem (HEADER_ROW_NAME, COLUMN_HEADER_VALUE, new QStandardItem (curveSelected)); | |
242 | m_model->setItem (HEADER_ROW_FUNC_AREA, COLUMN_HEADER_VALUE, new QStandardItem (funcArea)); | |
243 | m_model->setItem (HEADER_ROW_POLY_AREA, COLUMN_HEADER_VALUE, new QStandardItem (polyArea)); | |
244 | ||
245 | int row = NUM_HEADER_ROWS; | |
246 | int index = 0; | |
247 | for (; index < points.count(); row++, index++) { | |
248 | ||
249 | const Point &point = points.at (index); | |
250 | ||
251 | QPointF posGraph; | |
252 | transformation.transformScreenToRawGraph (point.posScreen (), | |
253 | posGraph); | |
254 | ||
255 | m_model->setItem (row, COLUMN_BODY_X, new QStandardItem (x [index])); | |
256 | m_model->setItem (row, COLUMN_BODY_Y, new QStandardItem (y [index])); | |
257 | m_model->setItem (row, COLUMN_BODY_INDEX, new QStandardItem (QString::number (index + 1))); | |
258 | m_model->setItem (row, COLUMN_BODY_DISTANCE_GRAPH_FORWARD, new QStandardItem (distanceGraphForward [index])); | |
259 | m_model->setItem (row, COLUMN_BODY_DISTANCE_PERCENT_FORWARD, new QStandardItem (distancePercentForward [index])); | |
260 | m_model->setItem (row, COLUMN_BODY_DISTANCE_GRAPH_BACKWARD, new QStandardItem (distanceGraphBackward [index])); | |
261 | m_model->setItem (row, COLUMN_BODY_DISTANCE_PERCENT_BACKWARD, new QStandardItem (distancePercentBackward [index])); | |
262 | m_model->setItem (row, COLUMN_BODY_POINT_IDENTIFIERS, new QStandardItem (point.identifier())); | |
263 | } | |
264 | ||
265 | // Unselect everything | |
266 | unselectAll (); | |
267 | ||
268 | // Make sure the hidden column stays hidden | |
269 | m_view->setColumnHidden (COLUMN_BODY_POINT_IDENTIFIERS, true); | |
270 | } | |
271 | ||
272 | void GeometryWindow::unselectAll () | |
273 | { | |
274 | QItemSelectionModel *selectionModel = m_view->selectionModel (); | |
275 | ||
276 | selectionModel->clearSelection (); | |
277 | } |
0 | /****************************************************************************************************** | |
1 | * (C) 2016 markummitchell@github.com. This file is part of Engauge Digitizer, which is released * | |
2 | * under GNU General Public License version 2 (GPLv2) or (at your option) any later version. See file * | |
3 | * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. * | |
4 | ******************************************************************************************************/ | |
5 | ||
6 | #ifndef GEOMETRY_WINDOW_H | |
7 | #define GEOMETRY_WINDOW_H | |
8 | ||
9 | #include "DocumentModelExportFormat.h" | |
10 | #include "GeometryStrategyContext.h" | |
11 | #include <QDockWidget> | |
12 | ||
13 | class CmdMediator; | |
14 | class Curve; | |
15 | class GeometryModel; | |
16 | class MainWindowModel; | |
17 | class QItemSelection; | |
18 | class QString; | |
19 | class QTableView; | |
20 | class Transformation; | |
21 | ||
22 | /// Window that displays the geometry information, as a table, for the current curve | |
23 | /// | |
24 | /// Column COLUMN_BODY_POINT_IDENTIFIERS is hidden. It contains the point identifiers so we can find | |
25 | /// the line associated with a point, and then highlight that line | |
26 | class GeometryWindow : public QDockWidget | |
27 | { | |
28 | Q_OBJECT; | |
29 | ||
30 | public: | |
31 | /// Single constructor. Parent is needed or else this widget cannot be redocked after being undocked | |
32 | GeometryWindow (QWidget *parent); | |
33 | virtual ~GeometryWindow (); | |
34 | ||
35 | /// Clear stale information | |
36 | void clear (); | |
37 | ||
38 | /// Catch close event so corresponding menu item in MainWindow can be updated accordingly | |
39 | virtual void closeEvent(QCloseEvent *event); | |
40 | ||
41 | /// Hidden column that has the point identifiers | |
42 | static int columnBodyPointIdentifiers (); | |
43 | ||
44 | /// Populate the table with the specified Curve | |
45 | void update (const CmdMediator &cmdMediator, | |
46 | const MainWindowModel &modelMainWindow, | |
47 | const QString &curveSelected, | |
48 | const Transformation &transformation); | |
49 | ||
50 | public slots: | |
51 | ||
52 | /// Highlight the row for the specified point | |
53 | void slotPointHoverEnter (QString); | |
54 | ||
55 | /// Unhighlight the row for the specified point | |
56 | void slotPointHoverLeave (QString); | |
57 | ||
58 | /// Prepare for copy after selection has changed | |
59 | void slotSelectionChanged (const QItemSelection &, const QItemSelection &); | |
60 | ||
61 | signals: | |
62 | /// Signal that this QDockWidget was just closed | |
63 | void signalGeometryWindowClosed(); | |
64 | ||
65 | private: | |
66 | GeometryWindow(); | |
67 | ||
68 | int fold2dIndexes (int row, | |
69 | int col, | |
70 | int rowLow, | |
71 | int colLow, | |
72 | int colHigh) const; | |
73 | void initializeHeader(); | |
74 | void loadStrategies (); | |
75 | void resizeTable (int rowCount); | |
76 | void unselectAll (); // Unselect all cells. This cleans up nicely when Document is closed | |
77 | ||
78 | enum ColumnsHeader { | |
79 | COLUMN_HEADER_LABEL, | |
80 | COLUMN_HEADER_VALUE, | |
81 | NUM_HEADER_COLUMNS | |
82 | }; | |
83 | ||
84 | enum ColumnsBody { | |
85 | COLUMN_BODY_X, | |
86 | COLUMN_BODY_Y, | |
87 | COLUMN_BODY_INDEX, | |
88 | COLUMN_BODY_DISTANCE_GRAPH_FORWARD, | |
89 | COLUMN_BODY_DISTANCE_PERCENT_FORWARD, | |
90 | COLUMN_BODY_DISTANCE_GRAPH_BACKWARD, | |
91 | COLUMN_BODY_DISTANCE_PERCENT_BACKWARD, | |
92 | COLUMN_BODY_POINT_IDENTIFIERS, | |
93 | NUM_BODY_COLUMNS | |
94 | }; | |
95 | ||
96 | enum HeaderRows { | |
97 | HEADER_ROW_NAME, | |
98 | HEADER_ROW_FUNC_AREA, | |
99 | HEADER_ROW_POLY_AREA, | |
100 | HEADER_ROW_COLUMN_NAMES, | |
101 | NUM_HEADER_ROWS | |
102 | }; | |
103 | ||
104 | QTableView *m_view; | |
105 | GeometryModel *m_model; | |
106 | ||
107 | GeometryStrategyContext m_geometryStrategyContext; | |
108 | ||
109 | // Export format is updated after every CmdAbstractBase gets redone/undone | |
110 | DocumentModelExportFormat m_modelExport; | |
111 | }; | |
112 | ||
113 | #endif // GEOMETRY_WINDOW_H |
0 | /****************************************************************************************************** | |
1 | * (C) 2016 markummitchell@github.com. This file is part of Engauge Digitizer, which is released * | |
2 | * under GNU General Public License version 2 (GPLv2) or (at your option) any later version. See file * | |
3 | * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. * | |
4 | ******************************************************************************************************/ | |
5 | ||
6 | #include "Curve.h" | |
7 | #include "DataKey.h" | |
8 | #include "GraphicsItemsExtractor.h" | |
9 | #include "GraphicsItemType.h" | |
10 | #include "Logger.h" | |
11 | #include "Point.h" | |
12 | #include <QGraphicsItem> | |
13 | ||
14 | GraphicsItemsExtractor::GraphicsItemsExtractor() | |
15 | { | |
16 | } | |
17 | ||
18 | GraphicsItemsExtractor::~GraphicsItemsExtractor() | |
19 | { | |
20 | } | |
21 | ||
22 | bool GraphicsItemsExtractor::allSelectedItemsAreEitherAxisOrGraph (const QList<QGraphicsItem*> &items, | |
23 | AxisOrGraph axisOrGraph) const | |
24 | { | |
25 | bool allAreEitherAxisOrGraph = true; | |
26 | ||
27 | QList<QGraphicsItem*>::const_iterator itr; | |
28 | for (itr = items.begin(); itr != items.end(); itr++) { | |
29 | ||
30 | QGraphicsItem *item = *itr; | |
31 | GraphicsItemType type = (GraphicsItemType) item->data (DATA_KEY_GRAPHICS_ITEM_TYPE).toInt (); | |
32 | ||
33 | if (type == GRAPHICS_ITEM_TYPE_POINT) { | |
34 | ||
35 | QString pointIdentifier = item->data (DATA_KEY_IDENTIFIER).toString (); | |
36 | QString curveName = Point::curveNameFromPointIdentifier (pointIdentifier); | |
37 | ||
38 | bool unwantedAxisPoint = ((curveName == AXIS_CURVE_NAME) && (axisOrGraph == GRAPH_POINTS)); | |
39 | bool unwantedCurvePoint = ((curveName != AXIS_CURVE_NAME) && (axisOrGraph == AXIS_POINTS)); | |
40 | ||
41 | if (unwantedAxisPoint || unwantedCurvePoint) { | |
42 | ||
43 | allAreEitherAxisOrGraph = false; | |
44 | break; | |
45 | ||
46 | } | |
47 | } else { | |
48 | ||
49 | allAreEitherAxisOrGraph = false; | |
50 | break; | |
51 | ||
52 | } | |
53 | } | |
54 | ||
55 | return allAreEitherAxisOrGraph; | |
56 | } | |
57 | ||
58 | QStringList GraphicsItemsExtractor::selectedPointIdentifiers (const QList<QGraphicsItem*> &items) const | |
59 | { | |
60 | LOG4CPP_INFO_S ((*mainCat)) << "GraphicsScene::selectedPointIdentifiers" | |
61 | << " selectedItems=" << items.count(); | |
62 | ||
63 | QStringList selectedIds; | |
64 | QList<QGraphicsItem*>::const_iterator itr; | |
65 | for (itr = items.begin(); itr != items.end(); itr++) { | |
66 | ||
67 | const QGraphicsItem* item = *itr; | |
68 | ||
69 | // Skip the image and only keep the Points | |
70 | bool isPoint = (item->data (DATA_KEY_GRAPHICS_ITEM_TYPE).toInt () == GRAPHICS_ITEM_TYPE_POINT); | |
71 | if (isPoint) { | |
72 | ||
73 | // Add Point to the list | |
74 | selectedIds << item->data(DATA_KEY_IDENTIFIER).toString (); | |
75 | ||
76 | } | |
77 | } | |
78 | ||
79 | return selectedIds; | |
80 | } |
0 | /****************************************************************************************************** | |
1 | * (C) 2016 markummitchell@github.com. This file is part of Engauge Digitizer, which is released * | |
2 | * under GNU General Public License version 2 (GPLv2) or (at your option) any later version. See file * | |
3 | * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. * | |
4 | ******************************************************************************************************/ | |
5 | ||
6 | #ifndef GRAPHICS_ITEMS_EXTRACTOR_H | |
7 | #define GRAPHICS_ITEMS_EXTRACTOR_H | |
8 | ||
9 | #include <QStringList> | |
10 | ||
11 | class QGraphicsItem; | |
12 | ||
13 | enum AxisOrGraph { | |
14 | AXIS_POINTS, | |
15 | GRAPH_POINTS | |
16 | }; | |
17 | ||
18 | /// This class consolidates utility routines that deal with graphics items that are getting extracted from the scene | |
19 | class GraphicsItemsExtractor | |
20 | { | |
21 | public: | |
22 | /// Single constructor | |
23 | GraphicsItemsExtractor(); | |
24 | ~GraphicsItemsExtractor(); | |
25 | ||
26 | /// Return true if all selected points are of the specified axis or graph type | |
27 | bool allSelectedItemsAreEitherAxisOrGraph (const QList<QGraphicsItem*> &items, | |
28 | AxisOrGraph axisOrGraph) const; | |
29 | ||
30 | /// Return list of selected point identifiers | |
31 | QStringList selectedPointIdentifiers (const QList<QGraphicsItem*> &items) const; | |
32 | ||
33 | }; | |
34 | ||
35 | #endif // GRAPHICS_ITEMS_EXTRACTOR_H |
6 | 6 | #include "DataKey.h" |
7 | 7 | #include "EngaugeAssert.h" |
8 | 8 | #include "EnumsToQt.h" |
9 | #include "GeometryWindow.h" | |
9 | 10 | #include "GraphicsItemType.h" |
10 | 11 | #include "GraphicsLinesForCurve.h" |
11 | 12 | #include "GraphicsPoint.h" |
319 | 320 | |
320 | 321 | void GraphicsLinesForCurve::updateAfterCommand (GraphicsScene &scene, |
321 | 322 | const PointStyle &pointStyle, |
322 | const Point &point) | |
323 | const Point &point, | |
324 | GeometryWindow *geometryWindow) | |
323 | 325 | { |
324 | 326 | LOG4CPP_DEBUG_S ((*mainCat)) << "GraphicsLinesForCurve::updateAfterCommand" |
325 | 327 | << " curve=" << m_curveName.toLatin1().data() |
342 | 344 | // Point does not exist in scene so create it |
343 | 345 | graphicsPoint = scene.createPoint (point.identifier (), |
344 | 346 | pointStyle, |
345 | point.posScreen()); | |
347 | point.posScreen(), | |
348 | geometryWindow); | |
346 | 349 | m_graphicsPoints [point.ordinal ()] = graphicsPoint; |
347 | 350 | |
348 | 351 | } |
361 | 364 | |
362 | 365 | GraphicsPoint *point = itr.value(); |
363 | 366 | point->updateCurveStyle (curveStyle); |
367 | } | |
368 | } | |
369 | ||
370 | void GraphicsLinesForCurve::updateHighlightOpacity (double highlightOpacity) | |
371 | { | |
372 | LOG4CPP_INFO_S ((*mainCat)) << "GraphicsLinesForCurve::updateCurveStyle" | |
373 | << " curve=" << m_curveName.toLatin1().data() | |
374 | << " highlightOpacity=" << highlightOpacity; | |
375 | ||
376 | OrdinalToGraphicsPoint::const_iterator itr; | |
377 | for (itr = m_graphicsPoints.begin(); itr != m_graphicsPoints.end(); itr++) { | |
378 | ||
379 | GraphicsPoint *point = itr.value(); | |
380 | point->setHighlightOpacity (highlightOpacity); | |
364 | 381 | } |
365 | 382 | } |
366 | 383 |
11 | 11 | #include <QGraphicsPathItem> |
12 | 12 | |
13 | 13 | class CurveStyle; |
14 | class GeometryWindow; | |
14 | 15 | class GraphicsPoint; |
15 | 16 | class GraphicsScene; |
16 | 17 | class LineStyle; |
58 | 59 | /// Update the GraphicsScene with the specified Point from the Document. If it does not exist yet in the scene, we add it |
59 | 60 | void updateAfterCommand (GraphicsScene &scene, |
60 | 61 | const PointStyle &pointStyle, |
61 | const Point &point); | |
62 | const Point &point, | |
63 | GeometryWindow *geometryWindow); | |
62 | 64 | |
63 | 65 | /// Update the curve style for this curve |
64 | 66 | void updateCurveStyle (const CurveStyle &curveStyle); |
65 | 67 | |
66 | 68 | /// Calls to moveLinesWithDraggedPoint have finished so update the lines correspondingly |
67 | 69 | void updateGraphicsLinesToMatchGraphicsPoints (const LineStyle &lineStyle); |
70 | ||
71 | /// Update the highlight opacity value. This may or may not affect the current display immediately depending on the state | |
72 | void updateHighlightOpacity (double highlightOpacity); | |
68 | 73 | |
69 | 74 | /// See GraphicsScene::updateOrdinalsAfterDrag. Pretty much the same steps as Curve::updatePointOrdinals |
70 | 75 | void updatePointOrdinalsAfterDrag (const LineStyle &lineStyle, |
171 | 171 | void GraphicsLinesForCurves::updateAfterCommand (GraphicsScene &scene, |
172 | 172 | const CurveStyles &curveStyles, |
173 | 173 | const QString &curveName, |
174 | const Point &point) | |
174 | const Point &point, | |
175 | GeometryWindow *geometryWindow) | |
175 | 176 | { |
176 | 177 | LOG4CPP_DEBUG_S ((*mainCat)) << "GraphicsLinesForCurves::updateAfterCommand" |
177 | 178 | << " point=" << point.identifier().toLatin1().data() |
180 | 181 | ENGAUGE_ASSERT (m_graphicsLinesForCurve.contains (curveName)); |
181 | 182 | m_graphicsLinesForCurve [curveName]->updateAfterCommand (scene, |
182 | 183 | curveStyles.pointStyle(curveName), |
183 | point); | |
184 | point, | |
185 | geometryWindow); | |
184 | 186 | } |
185 | 187 | |
186 | 188 | void GraphicsLinesForCurves::updateCurveStyles (const CurveStyles &modelCurveStyles) |
213 | 215 | } |
214 | 216 | } |
215 | 217 | |
218 | void GraphicsLinesForCurves::updateHighlightOpacity (double highlightOpacity) | |
219 | { | |
220 | LOG4CPP_INFO_S ((*mainCat)) << "GraphicsLinesForCurves::updateHighlightOpacity" | |
221 | << " highlightOpacity=" << highlightOpacity; | |
222 | ||
223 | GraphicsLinesContainer::const_iterator itr; | |
224 | for (itr = m_graphicsLinesForCurve.begin (); itr != m_graphicsLinesForCurve.end (); itr++) { | |
225 | ||
226 | QString curveName = itr.key(); | |
227 | ||
228 | m_graphicsLinesForCurve [curveName]->updateHighlightOpacity (highlightOpacity); | |
229 | } | |
230 | } | |
231 | ||
216 | 232 | void GraphicsLinesForCurves::updatePointOrdinalsAfterDrag (const CurveStyles &curveStyles, |
217 | 233 | const Transformation &transformation) |
218 | 234 | { |
9 | 9 | #include <QHash> |
10 | 10 | |
11 | 11 | class CurveStyles; |
12 | class GeometryWindow; | |
12 | 13 | class GraphicsLinesForCurve; |
13 | 14 | class GraphicsPoint; |
14 | 15 | class GraphicsScene; |
65 | 66 | void updateAfterCommand (GraphicsScene &scene, |
66 | 67 | const CurveStyles &curveStyles, |
67 | 68 | const QString &curveName, |
68 | const Point &point); | |
69 | const Point &point, | |
70 | GeometryWindow *geometryWindow); | |
69 | 71 | |
70 | 72 | /// Update the curve style for every curve |
71 | 73 | void updateCurveStyles (const CurveStyles &modelCurveStyles); |
72 | 74 | |
73 | 75 | /// Calls to moveLinesWithDraggedPoint have finished so update the lines correspondingly |
74 | 76 | void updateGraphicsLinesToMatchGraphicsPoints (const CurveStyles &curveStyles); |
77 | ||
78 | /// Update the highlight opacity value. This may or may not affect the current display immediately depending on the state | |
79 | void updateHighlightOpacity (double highlightOpacity); | |
75 | 80 | |
76 | 81 | /// See GraphicsScene::updateOrdinalsAfterDrag |
77 | 82 | void updatePointOrdinalsAfterDrag (const CurveStyles &curveStyles, |
6 | 6 | #include "CurveStyle.h" |
7 | 7 | #include "DataKey.h" |
8 | 8 | #include "EnumsToQt.h" |
9 | #include "GeometryWindow.h" | |
9 | 10 | #include "GraphicsItemType.h" |
10 | 11 | #include "GraphicsPoint.h" |
11 | 12 | #include "GraphicsPointEllipse.h" |
16 | 17 | #include <QGraphicsPolygonItem> |
17 | 18 | #include <QGraphicsScene> |
18 | 19 | #include <QGraphicsSceneContextMenuEvent> |
20 | #include <QObject> | |
19 | 21 | #include <QPen> |
20 | 22 | #include <QTextStream> |
21 | 23 | #include "QtToString.h" |
22 | 24 | #include "ZValues.h" |
23 | 25 | |
26 | const double DEFAULT_HIGHLIGHT_OPACITY = 0.35; // 0=transparent to 1=opaque. Values above 0.5 are very hard to notice | |
27 | const double MAX_OPACITY = 1.0; | |
24 | 28 | const double ZERO_WIDTH = 0.0; |
25 | 29 | |
26 | 30 | GraphicsPoint::GraphicsPoint(QGraphicsScene &scene, |
28 | 32 | const QPointF &posScreen, |
29 | 33 | const QColor &color, |
30 | 34 | unsigned int radius, |
31 | double lineWidth) : | |
35 | double lineWidth, | |
36 | GeometryWindow *geometryWindow) : | |
32 | 37 | GraphicsPointAbstractBase (), |
33 | 38 | m_scene (scene), |
34 | 39 | m_graphicsItemEllipse (0), |
39 | 44 | m_posScreen (posScreen), |
40 | 45 | m_color (color), |
41 | 46 | m_lineWidth (lineWidth), |
42 | m_wanted (true) | |
47 | m_wanted (true), | |
48 | m_highlightOpacity (DEFAULT_HIGHLIGHT_OPACITY), | |
49 | m_geometryWindow (geometryWindow) | |
43 | 50 | { |
44 | 51 | LOG4CPP_DEBUG_S ((*mainCat)) << "GraphicsPoint::GraphicsPoint" |
45 | 52 | << " identifier=" << identifier.toLatin1 ().data (); |
52 | 59 | const QPointF &posScreen, |
53 | 60 | const QColor &color, |
54 | 61 | const QPolygonF &polygon, |
55 | double lineWidth) : | |
62 | double lineWidth, | |
63 | GeometryWindow *geometryWindow) : | |
56 | 64 | GraphicsPointAbstractBase (), |
57 | 65 | m_scene (scene), |
58 | 66 | m_graphicsItemEllipse (0), |
63 | 71 | m_posScreen (posScreen), |
64 | 72 | m_color (color), |
65 | 73 | m_lineWidth (lineWidth), |
66 | m_wanted (true) | |
74 | m_wanted (true), | |
75 | m_highlightOpacity (DEFAULT_HIGHLIGHT_OPACITY), | |
76 | m_geometryWindow (geometryWindow) | |
67 | 77 | { |
68 | 78 | LOG4CPP_DEBUG_S ((*mainCat)) << "GraphicsPoint::GraphicsPoint " |
69 | 79 | << " identifier=" << identifier.toLatin1 ().data (); |
121 | 131 | m_graphicsItemEllipse->setFlags (QGraphicsItem::ItemIsSelectable | |
122 | 132 | QGraphicsItem::ItemIsMovable | |
123 | 133 | QGraphicsItem::ItemSendsGeometryChanges); |
124 | ||
125 | m_graphicsItemEllipse->setToolTip (m_identifier); | |
126 | 134 | m_graphicsItemEllipse->setData (DATA_KEY_GRAPHICS_ITEM_TYPE, GRAPHICS_ITEM_TYPE_POINT); |
135 | if (m_geometryWindow != 0) { | |
136 | QObject::connect (m_graphicsItemEllipse, SIGNAL (signalPointHoverEnter (QString)), m_geometryWindow, SLOT (slotPointHoverEnter (QString))); | |
137 | QObject::connect (m_graphicsItemEllipse, SIGNAL (signalPointHoverLeave (QString)), m_geometryWindow, SLOT (slotPointHoverLeave (QString))); | |
138 | } | |
127 | 139 | |
128 | 140 | // Shadow item is not selectable so it needs no stored data. Do NOT |
129 | 141 | // call QGraphicsScene::addItem since the QGraphicsItem::setParentItem call adds the item |
136 | 148 | |
137 | 149 | m_shadowZeroWidthEllipse->setPen (QPen (QBrush (m_color), ZERO_WIDTH)); |
138 | 150 | m_shadowZeroWidthEllipse->setEnabled (true); |
151 | ||
152 | m_graphicsItemEllipse->setShadow (m_shadowZeroWidthEllipse); | |
139 | 153 | } |
140 | 154 | |
141 | 155 | void GraphicsPoint::createPointPolygon (const QPolygonF &polygon) |
156 | 170 | m_graphicsItemPolygon->setFlags (QGraphicsItem::ItemIsSelectable | |
157 | 171 | QGraphicsItem::ItemIsMovable | |
158 | 172 | QGraphicsItem::ItemSendsGeometryChanges); |
159 | ||
160 | m_graphicsItemPolygon->setToolTip (m_identifier); | |
161 | 173 | m_graphicsItemPolygon->setData (DATA_KEY_GRAPHICS_ITEM_TYPE, GRAPHICS_ITEM_TYPE_POINT); |
174 | if (m_geometryWindow != 0) { | |
175 | QObject::connect (m_graphicsItemPolygon, SIGNAL (signalPointHoverEnter (QString)), m_geometryWindow, SLOT (slotPointHoverEnter (QString))); | |
176 | QObject::connect (m_graphicsItemPolygon, SIGNAL (signalPointHoverLeave (QString)), m_geometryWindow, SLOT (slotPointHoverLeave (QString))); | |
177 | } | |
162 | 178 | |
163 | 179 | // Shadow item is not selectable so it needs no stored data. Do NOT |
164 | 180 | // call QGraphicsScene::addItem since the QGraphicsItem::setParentItem call adds the item |
168 | 184 | |
169 | 185 | m_shadowZeroWidthPolygon->setPen (QPen (QBrush (m_color), ZERO_WIDTH)); |
170 | 186 | m_shadowZeroWidthPolygon->setEnabled (true); |
187 | ||
188 | m_graphicsItemPolygon->setShadow (m_shadowZeroWidthPolygon); | |
171 | 189 | } |
172 | 190 | |
173 | 191 | QVariant GraphicsPoint::data (int key) const |
177 | 195 | } else { |
178 | 196 | return m_graphicsItemEllipse->data (key); |
179 | 197 | } |
198 | } | |
199 | ||
200 | double GraphicsPoint::highlightOpacity () const | |
201 | { | |
202 | return m_highlightOpacity; | |
180 | 203 | } |
181 | 204 | |
182 | 205 | QPointF GraphicsPoint::pos () const |
234 | 257 | } else { |
235 | 258 | m_graphicsItemEllipse->setData (key, data); |
236 | 259 | } |
260 | } | |
261 | ||
262 | void GraphicsPoint::setHighlightOpacity (double highlightOpacity) | |
263 | { | |
264 | LOG4CPP_DEBUG_S ((*mainCat)) << "GraphicsPoint::setHighlightOpacity" | |
265 | << " identifier=" << m_identifier.toLatin1().data() | |
266 | << " highlightOpacity=" << highlightOpacity; | |
267 | ||
268 | m_highlightOpacity = highlightOpacity; | |
237 | 269 | } |
238 | 270 | |
239 | 271 | void GraphicsPoint::setPointStyle(const PointStyle &pointStyle) |
293 | 325 | } |
294 | 326 | } |
295 | 327 | |
296 | void GraphicsPoint::setToolTip (const QString &toolTip) | |
297 | { | |
298 | if (m_graphicsItemEllipse == 0) { | |
299 | m_graphicsItemPolygon->setToolTip (toolTip); | |
300 | } else { | |
301 | m_graphicsItemEllipse->setToolTip (toolTip); | |
302 | } | |
303 | } | |
304 | ||
305 | 328 | void GraphicsPoint::setWanted () |
306 | 329 | { |
307 | 330 | m_wanted = true; |
7 | 7 | #define GRAPHICS_POINT_H |
8 | 8 | |
9 | 9 | #include "GraphicsPointAbstractBase.h" |
10 | #include "GraphicsPoint.h" | |
11 | 10 | #include <QColor> |
12 | 11 | #include <QPointF> |
13 | 12 | |
13 | extern const double DEFAULT_HIGHLIGHT_OPACITY; | |
14 | extern const double MAX_OPACITY; | |
15 | ||
14 | 16 | class CurveStyle; |
17 | class GeometryWindow; | |
15 | 18 | class GraphicsPointEllipse; |
16 | 19 | class GraphicsPointPolygon; |
17 | 20 | class PointStyle; |
44 | 47 | const QPointF &posScreen, |
45 | 48 | const QColor &color, |
46 | 49 | unsigned int radius, |
47 | double lineWidth); | |
50 | double lineWidth, | |
51 | GeometryWindow *geometryWindow); | |
48 | 52 | |
49 | 53 | /// Constructor of polygon point. |
50 | 54 | GraphicsPoint(QGraphicsScene &scene, |
52 | 56 | const QPointF &posScreen, |
53 | 57 | const QColor &color, |
54 | 58 | const QPolygonF &polygon, |
55 | double lineWidth); | |
59 | double lineWidth, | |
60 | GeometryWindow *geometryWindow); | |
56 | 61 | |
57 | 62 | /// Destructor. This remove the graphics item from the scene |
58 | 63 | ~GraphicsPoint (); |
59 | 64 | |
60 | 65 | /// Proxy method for QGraphicsItem::data |
61 | 66 | QVariant data (int key) const; |
67 | ||
68 | /// Get method for highlight opacity | |
69 | double highlightOpacity () const; | |
62 | 70 | |
63 | 71 | /// Proxy method for QGraphicsItem::pos. |
64 | 72 | QPointF pos () const; |
74 | 82 | /// Proxy method for QGraphicsItem::setData |
75 | 83 | void setData (int key, const QVariant &data); |
76 | 84 | |
85 | /// Set method for highlight opacity | |
86 | void setHighlightOpacity (double highlightOpacity); | |
87 | ||
77 | 88 | /// Update the point style |
78 | 89 | void setPointStyle (const PointStyle &pointStyle); |
79 | 90 | |
80 | 91 | /// Update the position |
81 | 92 | void setPos (const QPointF pos); |
82 | ||
83 | /// Proxy method for QGraphicsItem::setToolTip | |
84 | void setToolTip (const QString &toolTip); | |
85 | 93 | |
86 | 94 | /// Mark point as wanted. Marking as unwanted is done by the reset function |
87 | 95 | void setWanted (); |
116 | 124 | |
117 | 125 | // Housekeeping |
118 | 126 | bool m_wanted; |
127 | ||
128 | double m_highlightOpacity; | |
129 | ||
130 | GeometryWindow *m_geometryWindow; // Can receive hover signals. Null if unused | |
119 | 131 | }; |
120 | 132 | |
121 | 133 | #endif // GRAPHICS_POINT_H |
7 | 7 | #include "GraphicsPoint.h" |
8 | 8 | #include "GraphicsPointEllipse.h" |
9 | 9 | #include "Logger.h" |
10 | #include <QColor> | |
10 | 11 | #include <QGraphicsScene> |
11 | 12 | #include "QtToString.h" |
12 | 13 | |
13 | 14 | GraphicsPointEllipse::GraphicsPointEllipse(GraphicsPoint &graphicsPoint, |
14 | 15 | const QRect &rect) : |
15 | 16 | QGraphicsEllipseItem (rect), |
16 | m_graphicsPoint (graphicsPoint) | |
17 | m_graphicsPoint (graphicsPoint), | |
18 | m_shadow (0) | |
17 | 19 | { |
18 | 20 | LOG4CPP_INFO_S ((*mainCat)) << "GraphicsPointEllipse::GraphicsPointEllipse"; |
19 | 21 | } |
34 | 36 | value); |
35 | 37 | } |
36 | 38 | |
39 | void GraphicsPointEllipse::hoverEnterEvent(QGraphicsSceneHoverEvent *event) | |
40 | { | |
41 | // Highlighted | |
42 | setOpacityForSubtree (m_graphicsPoint.highlightOpacity()); | |
43 | ||
44 | emit signalPointHoverEnter (data (DATA_KEY_IDENTIFIER).toString ()); | |
45 | ||
46 | QGraphicsEllipseItem::hoverEnterEvent (event); | |
47 | } | |
48 | ||
49 | void GraphicsPointEllipse::hoverLeaveEvent(QGraphicsSceneHoverEvent *event) | |
50 | { | |
51 | // Unhighlighted | |
52 | setOpacityForSubtree (MAX_OPACITY); | |
53 | ||
54 | emit signalPointHoverLeave (data (DATA_KEY_IDENTIFIER).toString ()); | |
55 | ||
56 | QGraphicsEllipseItem::hoverLeaveEvent (event); | |
57 | } | |
58 | ||
59 | void GraphicsPointEllipse::setOpacityForSubtree (double opacity) | |
60 | { | |
61 | // Set this item | |
62 | setOpacity (opacity); | |
63 | ||
64 | if (m_shadow != 0) { | |
65 | ||
66 | // Set the child item. Opacity < MAX_OPACITY is too dark so child is set to totally transparent | |
67 | m_shadow->setOpacity (opacity < MAX_OPACITY ? 0.0 : opacity); | |
68 | } | |
69 | } | |
70 | ||
37 | 71 | void GraphicsPointEllipse::setRadius(int radius) |
38 | 72 | { |
39 | 73 | // Resize assuming symmetry about the origin, and an aspect ratio of 1:1 (so x and y scales are the same) |
40 | 74 | double scale = (2 * radius) / boundingRect().width(); |
41 | 75 | setScale (scale); |
42 | 76 | } |
77 | ||
78 | void GraphicsPointEllipse::setShadow (GraphicsPointEllipse *shadow) | |
79 | { | |
80 | m_shadow = shadow; | |
81 | } |
7 | 7 | #define GRAPHICS_POINT_ELLIPSE_H |
8 | 8 | |
9 | 9 | #include <QGraphicsEllipseItem> |
10 | #include <QObject> | |
10 | 11 | #include <QPointF> |
11 | 12 | |
12 | 13 | class GraphicsPoint; |
13 | 14 | |
14 | 15 | /// This class add event handling to QGraphicsEllipseItem |
15 | class GraphicsPointEllipse : public QGraphicsEllipseItem | |
16 | class GraphicsPointEllipse : public QObject, public QGraphicsEllipseItem | |
16 | 17 | { |
18 | Q_OBJECT; | |
19 | ||
17 | 20 | public: |
18 | 21 | /// Single constructor |
19 | 22 | GraphicsPointEllipse(GraphicsPoint &graphicsPoint, |
21 | 24 | |
22 | 25 | /// Intercept moves by dragging so moved items can be identified. This replaces unreliable hit tests. |
23 | 26 | QVariant itemChange(GraphicsItemChange change, const QVariant &value); |
27 | ||
28 | /// Accept hover so point can be highlighted when cursor is over it as a guide to user | |
29 | virtual void hoverEnterEvent(QGraphicsSceneHoverEvent *event); | |
30 | ||
31 | /// Unhighlight this point | |
32 | virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent *event); | |
33 | ||
24 | 34 | /// Update the radius |
25 | 35 | void setRadius(int radius); |
36 | ||
37 | /// Bind this graphics item to its shadow | |
38 | void setShadow (GraphicsPointEllipse *shadow); | |
39 | ||
40 | signals: | |
41 | ||
42 | /// Signal for geometry window to highlight the current point upon hover enter | |
43 | void signalPointHoverEnter (QString); | |
44 | ||
45 | /// Signal for geometry window to unhighlight the current point upon hover leave | |
46 | void signalPointHoverLeave (QString); | |
26 | 47 | |
27 | 48 | private: |
28 | 49 | GraphicsPointEllipse(); |
29 | 50 | |
51 | void setOpacityForSubtree (double opacity); | |
52 | ||
30 | 53 | // Reference to the GraphicsPoint that this class belongs to |
31 | 54 | GraphicsPoint &m_graphicsPoint; |
55 | ||
56 | GraphicsPointEllipse *m_shadow; | |
32 | 57 | }; |
33 | 58 | |
34 | 59 | #endif // GRAPHICS_POINT_ELLIPSE_H |
5 | 5 | |
6 | 6 | #include "DataKey.h" |
7 | 7 | #include "EnumsToQt.h" |
8 | #include "GeometryWindow.h" | |
8 | 9 | #include "GraphicsItemType.h" |
9 | 10 | #include "GraphicsPoint.h" |
10 | 11 | #include "GraphicsPointFactory.h" |
21 | 22 | GraphicsPoint *GraphicsPointFactory::createPoint (QGraphicsScene &scene, |
22 | 23 | const QString &identifier, |
23 | 24 | const QPointF &posScreen, |
24 | const PointStyle &pointStyle) | |
25 | const PointStyle &pointStyle, | |
26 | GeometryWindow *geometryWindow) | |
25 | 27 | { |
26 | 28 | GraphicsPoint *item = 0; |
27 | 29 | |
34 | 36 | posScreen, |
35 | 37 | ColorPaletteToQColor (pointStyle.paletteColor ()), |
36 | 38 | pointStyle.radius (), |
37 | pointStyle.lineWidth()); | |
39 | pointStyle.lineWidth(), | |
40 | geometryWindow); | |
38 | 41 | } |
39 | 42 | break; |
40 | 43 | |
45 | 48 | posScreen, |
46 | 49 | ColorPaletteToQColor (pointStyle.paletteColor ()), |
47 | 50 | pointStyle.polygon (), |
48 | pointStyle.lineWidth()); | |
51 | pointStyle.lineWidth(), | |
52 | geometryWindow); | |
49 | 53 | } |
50 | 54 | break; |
51 | 55 | } |
8 | 8 | |
9 | 9 | #include "PointShape.h" |
10 | 10 | |
11 | class GeometryWindow; | |
11 | 12 | class GraphicsPoint; |
12 | 13 | class PointStyle; |
13 | 14 | class QGraphicsScene; |
24 | 25 | GraphicsPoint *createPoint (QGraphicsScene &scene, |
25 | 26 | const QString &identifier, |
26 | 27 | const QPointF &posScreen, |
27 | const PointStyle &pointStyle); | |
28 | const PointStyle &pointStyle, | |
29 | GeometryWindow *geometryWindow); | |
28 | 30 | }; |
29 | 31 | |
30 | 32 | #endif // GRAPHICS_POINT_FACTORY_H |
13 | 13 | GraphicsPointPolygon::GraphicsPointPolygon(GraphicsPoint &graphicsPoint, |
14 | 14 | const QPolygonF &polygon) : |
15 | 15 | QGraphicsPolygonItem (polygon), |
16 | m_graphicsPoint (graphicsPoint) | |
17 | ||
16 | m_graphicsPoint (graphicsPoint), | |
17 | m_shadow (0) | |
18 | 18 | { |
19 | 19 | LOG4CPP_INFO_S ((*mainCat)) << "GraphicsPointPolygon::GraphicsPointPolygon"; |
20 | 20 | } |
35 | 35 | value); |
36 | 36 | } |
37 | 37 | |
38 | void GraphicsPointPolygon::hoverEnterEvent(QGraphicsSceneHoverEvent *event) | |
39 | { | |
40 | // Highlighted | |
41 | setOpacityForSubtree (m_graphicsPoint.highlightOpacity ()); | |
42 | ||
43 | emit signalPointHoverEnter (data (DATA_KEY_IDENTIFIER).toString ()); | |
44 | ||
45 | QGraphicsPolygonItem::hoverEnterEvent (event); | |
46 | } | |
47 | ||
48 | void GraphicsPointPolygon::hoverLeaveEvent(QGraphicsSceneHoverEvent *event) | |
49 | { | |
50 | // Unhighlighted | |
51 | setOpacityForSubtree (MAX_OPACITY); | |
52 | ||
53 | emit signalPointHoverLeave (data (DATA_KEY_IDENTIFIER).toString ()); | |
54 | ||
55 | QGraphicsPolygonItem::hoverLeaveEvent (event); | |
56 | } | |
57 | ||
58 | void GraphicsPointPolygon::setOpacityForSubtree (double opacity) | |
59 | { | |
60 | // Set this item | |
61 | setOpacity (opacity); | |
62 | ||
63 | if (m_shadow != 0) { | |
64 | ||
65 | // Set the child item. Opacity < MAX_OPACITY is too dark so child is set to totally transparent | |
66 | m_shadow->setOpacity (opacity < MAX_OPACITY ? 0.0 : opacity); | |
67 | } | |
68 | } | |
69 | ||
38 | 70 | void GraphicsPointPolygon::setRadius(int radius) |
39 | 71 | { |
40 | 72 | // Resize assuming symmetry about the origin, and an aspect ratio of 1:1 (so x and y scales are the same) |
41 | 73 | double scale = (2 * radius) / boundingRect().width(); |
42 | 74 | setScale (scale); |
43 | 75 | } |
76 | ||
77 | void GraphicsPointPolygon::setShadow (GraphicsPointPolygon *shadow) | |
78 | { | |
79 | m_shadow = shadow; | |
80 | } |
7 | 7 | #define GRAPHICS_POINT_POLYGON_H |
8 | 8 | |
9 | 9 | #include <QGraphicsPolygonItem> |
10 | #include <QObject> | |
10 | 11 | #include <QPointF> |
11 | 12 | |
12 | 13 | class GraphicsPoint; |
13 | 14 | |
14 | 15 | /// This class add event handling to QGraphicsPolygonItem |
15 | class GraphicsPointPolygon : public QGraphicsPolygonItem | |
16 | class GraphicsPointPolygon : public QObject, public QGraphicsPolygonItem | |
16 | 17 | { |
18 | Q_OBJECT; | |
19 | ||
17 | 20 | public: |
18 | 21 | /// Single constructor |
19 | 22 | GraphicsPointPolygon(GraphicsPoint &graphicsPoint, |
22 | 25 | /// Intercept moves by dragging so moved items can be identified. This replaces unreliable hit tests. |
23 | 26 | QVariant itemChange(GraphicsItemChange change, const QVariant &value); |
24 | 27 | |
28 | /// Accept hover so point can be highlighted when cursor is over it as a guide to user | |
29 | virtual void hoverEnterEvent(QGraphicsSceneHoverEvent *event); | |
30 | ||
31 | /// Unhighlight this point | |
32 | virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent *event); | |
33 | ||
25 | 34 | /// Update the radius |
26 | 35 | void setRadius(int radius); |
36 | ||
37 | /// Bind this graphics item to its shadow | |
38 | void setShadow (GraphicsPointPolygon *shadow); | |
39 | ||
40 | signals: | |
41 | ||
42 | /// Signal for geometry window to highlight the current point upon hover enter | |
43 | void signalPointHoverEnter (QString); | |
44 | ||
45 | /// Signal for geometry window to unhighlight the current point upon hover leave | |
46 | void signalPointHoverLeave (QString); | |
27 | 47 | |
28 | 48 | private: |
29 | 49 | GraphicsPointPolygon(); |
30 | 50 | |
51 | void setOpacityForSubtree (double opacity); | |
52 | ||
31 | 53 | // Reference to the GraphicsPoint that this class belongs to |
32 | 54 | GraphicsPoint &m_graphicsPoint; |
55 | ||
56 | GraphicsPointPolygon *m_shadow; | |
33 | 57 | }; |
34 | 58 | |
35 | 59 | #endif // GRAPHICS_POINT_POLYGON_H |
10 | 10 | #include "DataKey.h" |
11 | 11 | #include "EngaugeAssert.h" |
12 | 12 | #include "EnumsToQt.h" |
13 | #include "GeometryWindow.h" | |
13 | 14 | #include "GraphicsItemType.h" |
14 | 15 | #include "GraphicsPoint.h" |
15 | 16 | #include "GraphicsPointFactory.h" |
42 | 43 | |
43 | 44 | GraphicsPoint *GraphicsScene::createPoint (const QString &identifier, |
44 | 45 | const PointStyle &pointStyle, |
45 | const QPointF &posScreen) | |
46 | const QPointF &posScreen, | |
47 | GeometryWindow *geometryWindow) | |
46 | 48 | { |
47 | 49 | LOG4CPP_INFO_S ((*mainCat)) << "GraphicsScene::createPoint" |
48 | 50 | << " identifier=" << identifier.toLatin1().data(); |
55 | 57 | GraphicsPoint *point = pointFactory.createPoint (*this, |
56 | 58 | identifier, |
57 | 59 | posScreen, |
58 | pointStyle); | |
59 | ||
60 | point->setToolTip (identifier); | |
60 | pointStyle, | |
61 | geometryWindow); | |
62 | ||
61 | 63 | point->setData (DATA_KEY_GRAPHICS_ITEM_TYPE, GRAPHICS_ITEM_TYPE_POINT); |
62 | 64 | |
63 | 65 | return point; |
197 | 199 | } |
198 | 200 | } |
199 | 201 | |
200 | QStringList GraphicsScene::selectedPointIdentifiers () const | |
201 | { | |
202 | const QList<QGraphicsItem*> &items = QGraphicsScene::selectedItems(); | |
203 | ||
204 | LOG4CPP_INFO_S ((*mainCat)) << "GraphicsScene::selectedPointIdentifiers" | |
205 | << " selectedItems=" << items.count(); | |
206 | ||
207 | QStringList selectedIds; | |
208 | QList<QGraphicsItem*>::const_iterator itr; | |
209 | for (itr = items.begin(); itr != items.end(); itr++) { | |
210 | ||
211 | const QGraphicsItem* item = *itr; | |
212 | ||
213 | // Skip the image and only keep the Points | |
214 | bool isPoint = (item->data (DATA_KEY_GRAPHICS_ITEM_TYPE).toInt () == GRAPHICS_ITEM_TYPE_POINT); | |
215 | if (isPoint) { | |
216 | ||
217 | // Add Point to the list | |
218 | selectedIds << item->data(DATA_KEY_IDENTIFIER).toString (); | |
219 | ||
220 | } | |
221 | } | |
222 | ||
223 | return selectedIds; | |
224 | } | |
225 | ||
226 | 202 | void GraphicsScene::showCurves (bool show, |
227 | 203 | bool showAll, |
228 | 204 | const QString &curveNameWanted) |
266 | 242 | } |
267 | 243 | } |
268 | 244 | |
269 | void GraphicsScene::updateAfterCommand (CmdMediator &cmdMediator) | |
245 | void GraphicsScene::updateAfterCommand (CmdMediator &cmdMediator, | |
246 | double highlightOpacity, | |
247 | GeometryWindow *geometryWindow) | |
270 | 248 | { |
271 | 249 | LOG4CPP_INFO_S ((*mainCat)) << "GraphicsScene::updateAfterCommand"; |
272 | 250 | |
251 | m_graphicsLinesForCurves.updateHighlightOpacity (highlightOpacity); | |
252 | ||
273 | 253 | updateCurves (cmdMediator); |
274 | 254 | |
275 | 255 | // Update the points |
276 | updatePointMembership (cmdMediator); | |
256 | updatePointMembership (cmdMediator, | |
257 | geometryWindow); | |
277 | 258 | } |
278 | 259 | |
279 | 260 | void GraphicsScene::updateCurves (CmdMediator &cmdMediator) |
312 | 293 | } |
313 | 294 | } |
314 | 295 | |
315 | void GraphicsScene::updatePointMembership (CmdMediator &cmdMediator) | |
296 | void GraphicsScene::updatePointMembership (CmdMediator &cmdMediator, | |
297 | GeometryWindow *geometryWindow) | |
316 | 298 | { |
317 | 299 | LOG4CPP_INFO_S ((*mainCat)) << "GraphicsScene::updatePointMembership"; |
318 | 300 | |
319 | 301 | CallbackSceneUpdateAfterCommand ftor (m_graphicsLinesForCurves, |
320 | 302 | *this, |
321 | cmdMediator.document ()); | |
303 | cmdMediator.document (), | |
304 | geometryWindow); | |
322 | 305 | Functor2wRet<const QString &, const Point &, CallbackSearchReturn> ftorWithCallback = functor_ret (ftor, |
323 | 306 | &CallbackSceneUpdateAfterCommand::callback); |
324 | 307 |
15 | 15 | class Curve; |
16 | 16 | class CurvesGraphs; |
17 | 17 | class CurveStyles; |
18 | class GeometryWindow; | |
18 | 19 | class GraphicsPoint; |
19 | 20 | class MainWindow; |
20 | 21 | class PointStyle; |
40 | 41 | /// Create one QGraphicsItem-based object that represents one Point. It is NOT added to m_graphicsLinesForCurves (see addPoint) |
41 | 42 | GraphicsPoint *createPoint (const QString &identifier, |
42 | 43 | const PointStyle &pointStyle, |
43 | const QPointF &posScreen); | |
44 | const QPointF &posScreen, | |
45 | GeometryWindow *geometryWindow); | |
44 | 46 | |
45 | 47 | /// Hide all graphics items, except background image, in preparation for preview during IMPORT_TYPE_ADVANCED |
46 | 48 | void hideAllItemsExceptImage(); |
65 | 67 | /// Reset positionHasChanged flag for all items. Typically this is done as part of mousePressEvent. |
66 | 68 | void resetPositionHasChangedFlags(); |
67 | 69 | |
68 | /// Return a list of identifiers for the currently selected points. | |
69 | QStringList selectedPointIdentifiers () const; | |
70 | ||
71 | 70 | /// Show or hide all Curves (if showAll is true) or just the selected Curve (if showAll is false); |
72 | 71 | void showCurves (bool show, |
73 | 72 | bool showAll = false, |
75 | 74 | |
76 | 75 | /// Update the Points and their Curves after executing a command. After a mouse drag, the lines are already updated and |
77 | 76 | /// updating would be done on out of date information (since that would be brought up to date by the NEXT command) |
78 | void updateAfterCommand (CmdMediator &cmdMediator); | |
77 | void updateAfterCommand (CmdMediator &cmdMediator, | |
78 | double highlightOpacity, | |
79 | GeometryWindow *geometryWindow); | |
79 | 80 | |
80 | 81 | /// Update curve styles after settings changed. |
81 | 82 | void updateCurveStyles(const CurveStyles &modelCurveStyles); |
96 | 97 | void updateCurves (CmdMediator &cmdMediator); |
97 | 98 | |
98 | 99 | /// Update Points using a multi-pass algorithm. |
99 | void updatePointMembership (CmdMediator &cmdMediator); | |
100 | void updatePointMembership (CmdMediator &cmdMediator, | |
101 | GeometryWindow *geometryWindow); | |
100 | 102 | |
101 | 103 | /// Curve name to GraphicsLinesForCurve |
102 | 104 | GraphicsLinesForCurves m_graphicsLinesForCurves; |
4 | 4 | ******************************************************************************************************/ |
5 | 5 | |
6 | 6 | #include "DataKey.h" |
7 | #include "EngaugeAssert.h" | |
8 | #include "GraphicsItemsExtractor.h" | |
7 | 9 | #include "GraphicsItemType.h" |
8 | 10 | #include "GraphicsView.h" |
9 | 11 | #include "LoadFileInfo.h" |
27 | 29 | MainWindow &mainWindow) : |
28 | 30 | QGraphicsView (scene) |
29 | 31 | { |
30 | connect (this, SIGNAL (signalContextMenuEvent (QString)), &mainWindow, SLOT (slotContextMenuEvent (QString))); | |
32 | connect (this, SIGNAL (signalContextMenuEventAxis (QString)), &mainWindow, SLOT (slotContextMenuEventAxis (QString))); | |
33 | connect (this, SIGNAL (signalContextMenuEventGraph (QStringList)), &mainWindow, SLOT (slotContextMenuEventGraph (QStringList))); | |
31 | 34 | connect (this, SIGNAL (signalDraggedDigFile (QString)), &mainWindow, SLOT (slotFileOpenDraggedDigFile (QString))); |
32 | 35 | connect (this, SIGNAL (signalDraggedImage (QImage)), &mainWindow, SLOT (slotFileImportDraggedImage (QImage))); |
33 | 36 | connect (this, SIGNAL (signalDraggedImageUrl (QUrl)), &mainWindow, SLOT (slotFileImportDraggedImageUrl (QUrl))); |
34 | 37 | connect (this, SIGNAL (signalKeyPress (Qt::Key, bool)), &mainWindow, SLOT (slotKeyPress (Qt::Key, bool))); |
35 | connect (this, SIGNAL (signalLeave ()), &mainWindow, SLOT (slotLeave ())); | |
36 | 38 | connect (this, SIGNAL (signalMouseMove(QPointF)), &mainWindow, SLOT (slotMouseMove (QPointF))); |
37 | 39 | connect (this, SIGNAL (signalMousePress (QPointF)), &mainWindow, SLOT (slotMousePress (QPointF))); |
38 | 40 | connect (this, SIGNAL (signalMouseRelease (QPointF)), &mainWindow, SLOT (slotMouseRelease (QPointF))); |
66 | 68 | { |
67 | 69 | } |
68 | 70 | |
69 | void GraphicsView::contextMenuEvent (QContextMenuEvent *event) | |
70 | { | |
71 | LOG4CPP_INFO_S ((*mainCat)) << "GraphicsView::contextMenuEvent"; | |
72 | ||
73 | QList<QGraphicsItem*> items = scene()->selectedItems (); | |
74 | ||
75 | if (items.count () == 1) { | |
76 | ||
77 | QGraphicsItem *item = items.first (); | |
78 | QString pointIdentifier = item->data (DATA_KEY_IDENTIFIER).toString (); | |
79 | GraphicsItemType type = (GraphicsItemType) item->data (DATA_KEY_GRAPHICS_ITEM_TYPE).toInt (); | |
80 | QString curveName = Point::curveNameFromPointIdentifier (pointIdentifier); | |
81 | ||
82 | if ((type == GRAPHICS_ITEM_TYPE_POINT) && | |
83 | (curveName == AXIS_CURVE_NAME)) { | |
71 | void GraphicsView::contextMenuEvent(QContextMenuEvent *event) | |
72 | { | |
73 | LOG4CPP_INFO_S ((*mainCat)) << "GraphicsView::contextMenuEvent" | |
74 | << " selectedCount=" << scene()->selectedItems().count(); | |
75 | ||
76 | GraphicsItemsExtractor graphicsItemsExtractor; | |
77 | const QList<QGraphicsItem*> &items = scene()->selectedItems(); | |
78 | QStringList pointIdentifiers = graphicsItemsExtractor.selectedPointIdentifiers(items); | |
79 | ||
80 | if (pointIdentifiers.count() > 0) { | |
81 | ||
82 | if (graphicsItemsExtractor.allSelectedItemsAreEitherAxisOrGraph (items, | |
83 | GRAPH_POINTS)) { | |
84 | ||
85 | // One or more graph points are selected so edit their coordinates | |
86 | emit signalContextMenuEventGraph (pointIdentifiers); | |
87 | ||
88 | } else if (graphicsItemsExtractor.allSelectedItemsAreEitherAxisOrGraph (items, | |
89 | AXIS_POINTS) && pointIdentifiers.count() == 1) { | |
84 | 90 | |
85 | 91 | // A single axis point is selected so edit it |
86 | emit signalContextMenuEvent (pointIdentifier); | |
87 | event->accept (); | |
88 | ||
89 | return; | |
92 | emit signalContextMenuEventAxis (pointIdentifiers.first()); | |
93 | ||
90 | 94 | } |
91 | 95 | } |
92 | 96 | |
204 | 208 | } |
205 | 209 | } |
206 | 210 | |
207 | void GraphicsView::leaveEvent (QEvent *event) | |
208 | { | |
209 | LOG4CPP_DEBUG_S ((*mainCat)) << "GraphicsView::leaveEvent"; | |
210 | ||
211 | emit signalLeave (); | |
212 | ||
213 | QGraphicsView::leaveEvent (event); | |
214 | } | |
215 | ||
216 | 211 | void GraphicsView::mouseMoveEvent (QMouseEvent *event) |
217 | 212 | { |
218 | 213 | // LOG4CPP_DEBUG_S ((*mainCat)) << "GraphicsView::mouseMoveEvent cursor=" |
268 | 263 | |
269 | 264 | if (!isRightClick) { |
270 | 265 | |
271 | ||
272 | 266 | emit signalMouseRelease (posScreen); |
273 | 267 | |
274 | 268 | } |
275 | 269 | |
276 | 270 | QGraphicsView::mouseReleaseEvent (event); |
271 | } | |
272 | ||
273 | QStringList GraphicsView::pointIdentifiersFromSelection (const QList<QGraphicsItem*> &items) const | |
274 | { | |
275 | // This method assumes that all specified items are points | |
276 | ||
277 | QStringList pointIdentifiers; | |
278 | ||
279 | QList<QGraphicsItem*>::const_iterator itr; | |
280 | for (itr = items.begin(); itr != items.end(); itr++) { | |
281 | ||
282 | QGraphicsItem *item = *itr; | |
283 | GraphicsItemType type = (GraphicsItemType) item->data (DATA_KEY_GRAPHICS_ITEM_TYPE).toInt (); | |
284 | ENGAUGE_ASSERT (type == GRAPHICS_ITEM_TYPE_POINT); | |
285 | ||
286 | QString pointIdentifier = item->data (DATA_KEY_IDENTIFIER).toString (); | |
287 | pointIdentifiers << pointIdentifier; | |
288 | } | |
289 | ||
290 | return pointIdentifiers; | |
277 | 291 | } |
278 | 292 | |
279 | 293 | void GraphicsView::wheelEvent(QWheelEvent *event) |
26 | 26 | MainWindow &mainWindow); |
27 | 27 | virtual ~GraphicsView(); |
28 | 28 | |
29 | /// Intercept right click to support point editing. | |
30 | void contextMenuEvent (QContextMenuEvent *event); | |
29 | /// Intercept context event to support point editing | |
30 | virtual void contextMenuEvent (QContextMenuEvent *event); | |
31 | 31 | |
32 | 32 | /// Intercept mouse drag event to support drag-and-drop. |
33 | 33 | virtual void dragEnterEvent (QDragEnterEvent *event); |
40 | 40 | |
41 | 41 | /// Intercept key press events to handle left/right/up/down moving. |
42 | 42 | virtual void keyPressEvent (QKeyEvent *event); |
43 | ||
44 | /// Intercept leave events to manage override cursor. | |
45 | virtual void leaveEvent (QEvent *event); | |
46 | 43 | |
47 | 44 | /// Intercept mouse move events to populate the current cursor position in StatusBar. |
48 | 45 | virtual void mouseMoveEvent (QMouseEvent *event); |
58 | 55 | |
59 | 56 | signals: |
60 | 57 | /// Send right click on axis point to MainWindow for editing. |
61 | void signalContextMenuEvent (QString pointIdentifier); | |
58 | void signalContextMenuEventAxis (QString pointIdentifier); | |
59 | ||
60 | /// Send right click on graph point(s) to MainWindow for editing. | |
61 | void signalContextMenuEventGraph (QStringList pointIdentifiers); | |
62 | 62 | |
63 | 63 | /// Send dragged dig file to MainWindow for import. This comes from dragging an engauge dig file |
64 | 64 | void signalDraggedDigFile (QString); |
71 | 71 | |
72 | 72 | /// Send keypress to MainWindow for eventual processing by DigitizeStateAbstractBase subclasses. |
73 | 73 | void signalKeyPress (Qt::Key, bool atLeastOneSelectedItem); |
74 | ||
75 | /// Send leave to MainWindow for managing the override cursor. | |
76 | void signalLeave (); | |
77 | 74 | |
78 | 75 | /// Send mouse move to MainWindow for eventual display of cursor coordinates in StatusBar |
79 | 76 | void signalMouseMove (QPointF); |
93 | 90 | private: |
94 | 91 | GraphicsView(); |
95 | 92 | |
93 | QStringList pointIdentifiersFromSelection (const QList<QGraphicsItem*> &items) const; | |
96 | 94 | bool inBounds (const QPointF &posScreen); |
97 | 95 | |
98 | 96 | }; |
0 | /****************************************************************************************************** | |
1 | * (C) 2014 markummitchell@github.com. This file is part of Engauge Digitizer, which is released * | |
2 | * under GNU General Public License version 2 (GPLv2) or (at your option) any later version. See file * | |
3 | * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. * | |
4 | ******************************************************************************************************/ | |
5 | ||
0 | 6 | #ifndef GRID_LINE_H |
1 | 7 | #define GRID_LINE_H |
2 | 8 |
9 | 9 | #include "EnumsToQt.h" |
10 | 10 | #include "GraphicsArcItem.h" |
11 | 11 | #include "GridLineFactory.h" |
12 | #include "GridLineLimiter.h" | |
12 | 13 | #include "GridLines.h" |
13 | 14 | #include "GridLineStyle.h" |
14 | 15 | #include "Logger.h" |
16 | #include "MainWindowModel.h" | |
15 | 17 | #include <QGraphicsScene> |
16 | 18 | #include <qmath.h> |
17 | 19 | #include <QTextStream> |
29 | 31 | const double RADIANS_TO_TICS = 5760 / TWO_PI; |
30 | 32 | |
31 | 33 | GridLineFactory::GridLineFactory(QGraphicsScene &scene, |
32 | const DocumentModelCoords &modelCoords, | |
33 | const Transformation &transformation) : | |
34 | const DocumentModelCoords &modelCoords) : | |
34 | 35 | m_scene (scene), |
35 | 36 | m_pointRadius (0.0), |
36 | 37 | m_modelCoords (modelCoords), |
37 | m_transformation (transformation), | |
38 | 38 | m_isChecker (false) |
39 | 39 | { |
40 | LOG4CPP_DEBUG_S ((*mainCat)) << "GridLineFactory::GridLineFactory" | |
41 | << " transformation=" << transformation; | |
40 | LOG4CPP_DEBUG_S ((*mainCat)) << "GridLineFactory::GridLineFactory"; | |
42 | 41 | } |
43 | 42 | |
44 | 43 | GridLineFactory::GridLineFactory(QGraphicsScene &scene, |
45 | 44 | int pointRadius, |
46 | 45 | const QList<Point> &pointsToIsolate, |
47 | const DocumentModelCoords &modelCoords, | |
48 | const Transformation &transformation) : | |
46 | const DocumentModelCoords &modelCoords) : | |
49 | 47 | m_scene (scene), |
50 | 48 | m_pointRadius (pointRadius), |
51 | 49 | m_pointsToIsolate (pointsToIsolate), |
52 | 50 | m_modelCoords (modelCoords), |
53 | m_transformation (transformation), | |
54 | 51 | m_isChecker (true) |
55 | 52 | { |
56 | 53 | LOG4CPP_DEBUG_S ((*mainCat)) << "GridLineFactory::GridLineFactory" |
57 | 54 | << " pointRadius=" << pointRadius |
58 | << " pointsToIsolate=" << pointsToIsolate.count() | |
59 | << " transformation=" << transformation; | |
55 | << " pointsToIsolate=" << pointsToIsolate.count(); | |
60 | 56 | } |
61 | 57 | |
62 | 58 | void GridLineFactory::bindItemToScene(QGraphicsItem *item) const |
75 | 71 | GridLine *GridLineFactory::createGridLine (double xFrom, |
76 | 72 | double yFrom, |
77 | 73 | double xTo, |
78 | double yTo) | |
74 | double yTo, | |
75 | const Transformation &transformation) | |
79 | 76 | { |
80 | 77 | LOG4CPP_DEBUG_S ((*mainCat)) << "GridLineFactory::createGridLine" |
81 | 78 | << " xFrom=" << xFrom |
117 | 114 | } |
118 | 115 | |
119 | 116 | QPointF pointScreen; |
120 | m_transformation.transformRawGraphToScreen (QPointF (xGraph, yGraph), | |
121 | pointScreen); | |
117 | transformation.transformRawGraphToScreen (QPointF (xGraph, yGraph), | |
118 | pointScreen); | |
122 | 119 | |
123 | 120 | double distanceToNearestPoint = minScreenDistanceFromPoints (pointScreen); |
124 | 121 | if ((distanceToNearestPoint < m_pointRadius) || |
132 | 129 | pointScreen, |
133 | 130 | yFrom, |
134 | 131 | yTo, |
132 | transformation, | |
135 | 133 | *gridLine); |
136 | 134 | stateSegmentIsActive = false; |
137 | 135 | |
153 | 151 | } |
154 | 152 | |
155 | 153 | void GridLineFactory::createGridLinesForEvenlySpacedGrid (const DocumentModelGridDisplay &modelGridDisplay, |
154 | const MainWindowModel &modelMainWindow, | |
155 | const Transformation &transformation, | |
156 | 156 | GridLines &gridLines) |
157 | 157 | { |
158 | 158 | // At a minimum the transformation must be defined. Also, there is a brief interval between the definition of |
159 | 159 | // the transformation and the initialization of modelGridDisplay (at which point this method gets called again) and |
160 | 160 | // we do not want to create grid lines during that brief interval |
161 | if (m_transformation.transformIsDefined() && | |
161 | if (transformation.transformIsDefined() && | |
162 | 162 | modelGridDisplay.stable()) { |
163 | 163 | |
164 | 164 | double startX = modelGridDisplay.startX (); |
168 | 168 | double stopX = modelGridDisplay.stopX (); |
169 | 169 | double stopY = modelGridDisplay.stopY (); |
170 | 170 | |
171 | // Limit the number of grid lines. This is a noop if the limit is not exceeded | |
172 | GridLineLimiter gridLineLimiter; | |
173 | stepX = gridLineLimiter.limitedStepXTheta (m_modelCoords, | |
174 | modelMainWindow, | |
175 | modelGridDisplay); | |
176 | stepY = gridLineLimiter.limitedStepYRange (m_modelCoords, | |
177 | modelMainWindow, | |
178 | modelGridDisplay); | |
179 | ||
180 | // Apply if possible | |
171 | 181 | if (stepX != 0 && |
172 | 182 | stepY != 0) { |
173 | 183 | |
179 | 189 | bool isLinearX = (m_modelCoords.coordScaleXTheta() == COORD_SCALE_LINEAR); |
180 | 190 | for (double x = startX; x <= stopX; (isLinearX ? x += stepX : x *= stepX)) { |
181 | 191 | |
182 | GridLine *gridLine = createGridLine (x, startY, x, stopY); | |
192 | GridLine *gridLine = createGridLine (x, startY, x, stopY, transformation); | |
183 | 193 | gridLine->setPen (pen); |
184 | 194 | gridLines.add (gridLine); |
185 | 195 | } |
187 | 197 | bool isLinearY = (m_modelCoords.coordScaleYRadius() == COORD_SCALE_LINEAR); |
188 | 198 | for (double y = startY; y <= stopY; (isLinearY ? y += stepY : y *= stepY)) { |
189 | 199 | |
190 | GridLine *gridLine = createGridLine (startX, y, stopX, y); | |
200 | GridLine *gridLine = createGridLine (startX, y, stopX, y, transformation); | |
191 | 201 | gridLine->setPen (pen); |
192 | 202 | gridLines.add (gridLine); |
193 | 203 | } |
317 | 327 | const QPointF &posEndScreen, |
318 | 328 | double yFrom, |
319 | 329 | double yTo, |
330 | const Transformation &transformation, | |
320 | 331 | GridLine &gridLine) const |
321 | 332 | { |
322 | 333 | LOG4CPP_DEBUG_S ((*mainCat)) << "GridLineFactory::finishActiveGridLine" |
332 | 343 | // Linear cartesian radius |
333 | 344 | double radiusLinearCartesian = yFrom; |
334 | 345 | if (m_modelCoords.coordScaleYRadius() == COORD_SCALE_LOG) { |
335 | radiusLinearCartesian = m_transformation.logToLinearRadius(yFrom, | |
336 | m_modelCoords.originRadius()); | |
346 | radiusLinearCartesian = transformation.logToLinearRadius(yFrom, | |
347 | m_modelCoords.originRadius()); | |
337 | 348 | } else { |
338 | 349 | radiusLinearCartesian -= m_modelCoords.originRadius(); |
339 | 350 | } |
340 | 351 | |
341 | 352 | // Draw along an arc since this is a side of constant radius, and we have polar coordinates |
342 | item = ellipseItem (m_transformation, | |
353 | item = ellipseItem (transformation, | |
343 | 354 | radiusLinearCartesian, |
344 | 355 | posStartScreen, |
345 | 356 | posEndScreen); |
13 | 13 | class DocumentModelCoords; |
14 | 14 | class DocumentModelGridDisplay; |
15 | 15 | class GridLines; |
16 | class MainWindowModel; | |
16 | 17 | class QGraphicsScene; |
17 | 18 | class QTransform; |
18 | 19 | class Transformation; |
28 | 29 | public: |
29 | 30 | /// Simple constructor for general use (i.e. not by Checker) |
30 | 31 | GridLineFactory(QGraphicsScene &scene, |
31 | const DocumentModelCoords &modelCoords, | |
32 | const Transformation &transformation); | |
32 | const DocumentModelCoords &modelCoords); | |
33 | 33 | |
34 | 34 | /// Constructor for use by Checker, which has points that are isolated |
35 | 35 | GridLineFactory(QGraphicsScene &scene, |
36 | 36 | int pointRadius, |
37 | 37 | const QList<Point> &pointsToIsolate, |
38 | const DocumentModelCoords &modelCoords, | |
39 | const Transformation &transformation); | |
38 | const DocumentModelCoords &modelCoords); | |
40 | 39 | |
41 | 40 | /// Create grid line, either along constant X/theta or constant Y/radius side. Line goes from pointFromGraph to pointToGraph. |
42 | 41 | /// If the coordinates are polar, we go clockwise from pointFromGraph to pointToGraph (as set up by adjustPolarAngleRange). |
43 | 42 | GridLine *createGridLine (double xFrom, |
44 | 43 | double yFrom, |
45 | 44 | double xTo, |
46 | double yTo); | |
45 | double yTo, | |
46 | const Transformation &transformation); | |
47 | 47 | |
48 | 48 | /// Create a rectangular (cartesian) or annular (polar) grid of evenly spaced grid lines. |
49 | 49 | void createGridLinesForEvenlySpacedGrid (const DocumentModelGridDisplay &modelGridDisplay, |
50 | const MainWindowModel &modelMainWindow, | |
51 | const Transformation &transformation, | |
50 | 52 | GridLines &gridLines); |
51 | 53 | |
52 | 54 | private: |
67 | 69 | const QPointF &posEndScreen, |
68 | 70 | double yFrom, |
69 | 71 | double yTo, |
72 | const Transformation &transformation, | |
70 | 73 | GridLine &gridLine) const; |
71 | 74 | QGraphicsItem *lineItem (const QPointF &posStartScreen, |
72 | 75 | const QPointF &posEndScreen) const; |
76 | 79 | const int m_pointRadius; |
77 | 80 | const QList<Point> m_pointsToIsolate; |
78 | 81 | const DocumentModelCoords m_modelCoords; |
79 | const Transformation &m_transformation; | |
80 | 82 | bool m_isChecker; |
81 | 83 | }; |
82 | 84 |
0 | /****************************************************************************************************** | |
1 | * (C) 2016 markummitchell@github.com. This file is part of Engauge Digitizer, which is released * | |
2 | * under GNU General Public License version 2 (GPLv2) or (at your option) any later version. See file * | |
3 | * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. * | |
4 | ******************************************************************************************************/ | |
5 | ||
6 | #include "DocumentModelCoords.h" | |
7 | #include "DocumentModelGridDisplay.h" | |
8 | #include "DocumentModelGridRemoval.h" | |
9 | #include "GridLineLimiter.h" | |
10 | #include "MainWindowModel.h" | |
11 | #include <qmath.h> | |
12 | ||
13 | const int DEFAULT_MAXIMUM_GRID_LINES = 25; | |
14 | ||
15 | GridLineLimiter::GridLineLimiter () | |
16 | { | |
17 | } | |
18 | ||
19 | double GridLineLimiter::limitedStepXTheta (const DocumentModelCoords &modelCoords, | |
20 | const MainWindowModel &modelMainWindow, | |
21 | const DocumentModelGridDisplay &modelGrid) const | |
22 | { | |
23 | double step = modelGrid.stepX(); | |
24 | ||
25 | if (modelCoords.coordScaleXTheta() == COORD_SCALE_LINEAR) { | |
26 | ||
27 | // Linear | |
28 | double count = 1.0 + (modelGrid.stopX() - modelGrid.startX()) / modelGrid.stepX(); | |
29 | if ((int) count > modelMainWindow.maximumGridLines()) { | |
30 | ||
31 | // Adjust step so maximum grid lines limit is met | |
32 | step = (modelGrid.stopX() - modelGrid.startX()) / (modelMainWindow.maximumGridLines() - 1); | |
33 | ||
34 | } | |
35 | ||
36 | } else { | |
37 | ||
38 | // Log | |
39 | double count = 1.0 + (qLn (modelGrid.stopX()) - qLn (modelGrid.startX())) / qLn (modelMainWindow.maximumGridLines()); | |
40 | if ((int) count > modelMainWindow.maximumGridLines()) { | |
41 | ||
42 | // Adjust step so maximum grid lines limit is met | |
43 | step = qExp ((qLn (modelGrid.stopX()) - qLn (modelGrid.startX())) / (modelMainWindow.maximumGridLines() - 1)); | |
44 | ||
45 | } | |
46 | } | |
47 | ||
48 | return step; | |
49 | } | |
50 | ||
51 | double GridLineLimiter::limitedStepYRange (const DocumentModelCoords &modelCoords, | |
52 | const MainWindowModel &modelMainWindow, | |
53 | const DocumentModelGridDisplay &modelGrid) const | |
54 | { | |
55 | double step = modelGrid.stepY(); | |
56 | ||
57 | if (modelCoords.coordScaleYRadius() == COORD_SCALE_LINEAR) { | |
58 | ||
59 | // Linear | |
60 | double count = 1.0 + (modelGrid.stopY() - modelGrid.startY()) / modelGrid.stepY(); | |
61 | if ((int) count > modelMainWindow.maximumGridLines()) { | |
62 | ||
63 | // Adjust step so maximum grid lines limit is met | |
64 | step = (modelGrid.stopY() - modelGrid.startY()) / (modelMainWindow.maximumGridLines() - 1); | |
65 | ||
66 | } | |
67 | ||
68 | } else { | |
69 | ||
70 | // Log | |
71 | double count = 1.0 + (qLn (modelGrid.stopY()) - qLn (modelGrid.startY())) / qLn (modelMainWindow.maximumGridLines()); | |
72 | if ((int) count > modelMainWindow.maximumGridLines()) { | |
73 | ||
74 | // Adjust step so maximum grid lines limit is met | |
75 | step = qExp ((qLn (modelGrid.stopY()) - qLn (modelGrid.startY())) / (modelMainWindow.maximumGridLines() - 1)); | |
76 | ||
77 | } | |
78 | } | |
79 | ||
80 | return step; | |
81 | } |
0 | /****************************************************************************************************** | |
1 | * (C) 2016 markummitchell@github.com. This file is part of Engauge Digitizer, which is released * | |
2 | * under GNU General Public License version 2 (GPLv2) or (at your option) any later version. See file * | |
3 | * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. * | |
4 | ******************************************************************************************************/ | |
5 | ||
6 | #ifndef GRID_LINE_LIMITER_H | |
7 | #define GRID_LINE_LIMITER_H | |
8 | ||
9 | class DocumentModelCoords; | |
10 | class DocumentModelGridDisplay; | |
11 | class MainWindowModel; | |
12 | ||
13 | /// Default for maximum number of grid lines | |
14 | extern const int DEFAULT_MAXIMUM_GRID_LINES; | |
15 | ||
16 | /// Limit the number of grid lines so a bad combination of start/step/stop value will not lead to extremely | |
17 | /// long delays when the step size is much too small for the start/stop values | |
18 | class GridLineLimiter | |
19 | { | |
20 | public: | |
21 | /// Single constructor | |
22 | GridLineLimiter (); | |
23 | ||
24 | /// Limit step value for x/theta coordinate. This is a noop if the maximum grid line limit in MainWindowModel is not exceeded | |
25 | double limitedStepXTheta (const DocumentModelCoords &modelCoords, | |
26 | const MainWindowModel &modelMainWindow, | |
27 | const DocumentModelGridDisplay &modelGrid) const; | |
28 | ||
29 | /// Limit step value for y/range coordinate. This is a noop if the maximum grid line limit in MainWindowModel is not exceeded | |
30 | double limitedStepYRange (const DocumentModelCoords &modelCoords, | |
31 | const MainWindowModel &modelMainWindow, | |
32 | const DocumentModelGridDisplay &modelGrid) const; | |
33 | ||
34 | }; | |
35 | ||
36 | #endif // GRID_LINE_LIMITER_H |
0 | /****************************************************************************************************** | |
1 | * (C) 2014 markummitchell@github.com. This file is part of Engauge Digitizer, which is released * | |
2 | * under GNU General Public License version 2 (GPLv2) or (at your option) any later version. See file * | |
3 | * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. * | |
4 | ******************************************************************************************************/ | |
5 | ||
0 | 6 | #ifndef GRID_LINES_H |
1 | 7 | #define GRID_LINES_H |
2 | 8 |
0 | /****************************************************************************************************** | |
1 | * (C) 2016 markummitchell@github.com. This file is part of Engauge Digitizer, which is released * | |
2 | * under GNU General Public License version 2 (GPLv2) or (at your option) any later version. See file * | |
3 | * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. * | |
4 | ******************************************************************************************************/ | |
5 | ||
6 | #include "ImportCropping.h" | |
7 | #include <QObject> | |
8 | ||
9 | const QString IMPORT_CROPPING_NEVER_STRING (QObject::tr ("Never crop during import")); | |
10 | const QString IMPORT_CROPPING_MULTIPAGE_PDFS_STRING (QObject::tr ("Crop during import only for multiple-page pdf files")); | |
11 | const QString IMPORT_CROPPING_ALWAYS_STRING (QObject::tr ("Always crop during import")); | |
12 | ||
13 | const ImportCropping DEFAULT_IMPORT_CROPPING = IMPORT_CROPPING_NEVER; | |
14 | ||
15 | QString ImportCroppingToString (ImportCropping importCropping) | |
16 | { | |
17 | ||
18 | } |
0 | /****************************************************************************************************** | |
1 | * (C) 2016 markummitchell@github.com. This file is part of Engauge Digitizer, which is released * | |
2 | * under GNU General Public License version 2 (GPLv2) or (at your option) any later version. See file * | |
3 | * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. * | |
4 | ******************************************************************************************************/ | |
5 | ||
6 | #ifndef IMPORT_CROPPING_H | |
7 | #define IMPORT_CROPPING_H | |
8 | ||
9 | enum ImportCropping | |
10 | { | |
11 | IMPORT_CROPPING_NEVER, | |
12 | IMPORT_CROPPING_MULTIPAGE_PDFS, | |
13 | IMPORT_CROPPING_ALWAYS, | |
14 | NUMBER_IMPORT_CROPPING | |
15 | }; | |
16 | ||
17 | extern const ImportCropping DEFAULT_IMPORT_CROPPING; | |
18 | ||
19 | #endif // IMPORT_CROPPING_H |
0 | /****************************************************************************************************** | |
1 | * (C) 2016 markummitchell@github.com. This file is part of Engauge Digitizer, which is released * | |
2 | * under GNU General Public License version 2 (GPLv2) or (at your option) any later version. See file * | |
3 | * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. * | |
4 | ******************************************************************************************************/ | |
5 | ||
6 | #include "EngaugeAssert.h" | |
7 | #include "ImportCroppingUtilBase.h" | |
8 | #include <QHash> | |
9 | #include <QObject> | |
10 | ||
11 | const ImportCropping DEFAULT_IMPORT_CROPPING = IMPORT_CROPPING_NEVER; // Traditional, and simplest, option | |
12 | ||
13 | ImportCroppingUtilBase::ImportCroppingUtilBase() | |
14 | { | |
15 | } | |
16 | ||
17 | QString ImportCroppingUtilBase::importCroppingToString (ImportCropping importCropping) | |
18 | { | |
19 | QHash<ImportCropping, QString> lookupTable; | |
20 | ||
21 | lookupTable.insert (IMPORT_CROPPING_NEVER, QObject::tr ("No cropping")); | |
22 | lookupTable.insert (IMPORT_CROPPING_MULTIPAGE_PDFS, QObject::tr ("Crop pdf files with multiple pages")); | |
23 | lookupTable.insert (IMPORT_CROPPING_ALWAYS, QObject::tr ("Always crop")); | |
24 | ||
25 | ENGAUGE_ASSERT (lookupTable.count() == NUMBER_IMPORT_CROPPING); | |
26 | ||
27 | QString rtn; | |
28 | ||
29 | if (lookupTable.contains (importCropping)) { | |
30 | rtn = lookupTable [importCropping]; | |
31 | } | |
32 | ||
33 | return rtn; | |
34 | } |
0 | /****************************************************************************************************** | |
1 | * (C) 2016 markummitchell@github.com. This file is part of Engauge Digitizer, which is released * | |
2 | * under GNU General Public License version 2 (GPLv2) or (at your option) any later version. See file * | |
3 | * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. * | |
4 | ******************************************************************************************************/ | |
5 | ||
6 | #ifndef IMPORT_CROPPING_UTIL_BASE_H | |
7 | #define IMPORT_CROPPING_UTIL_BASE_H | |
8 | ||
9 | #include "ImportCropping.h" | |
10 | #include <QString> | |
11 | ||
12 | /// Utility class for import cropping options. Default option is oldest, and simplest, behavior, which is no cropping. | |
13 | /// | |
14 | /// A complication is that a dialog for cropping is not wanted during batch-mode regression testing, so this class | |
15 | /// and its subclasses offer methods for overriding the current setting during regression testing | |
16 | class ImportCroppingUtilBase | |
17 | { | |
18 | public: | |
19 | /// Single constructor | |
20 | ImportCroppingUtilBase(); | |
21 | ||
22 | /// Option as string for display to user | |
23 | static QString importCroppingToString (ImportCropping importCropping); | |
24 | ||
25 | }; | |
26 | ||
27 | #endif // IMPORT_CROPPING_UTIL_BASE_H |
0 | /****************************************************************************************************** | |
1 | * (C) 2016 markummitchell@github.com. This file is part of Engauge Digitizer, which is released * | |
2 | * under GNU General Public License version 2 (GPLv2) or (at your option) any later version. See file * | |
3 | * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. * | |
4 | ******************************************************************************************************/ | |
5 | ||
6 | #include "ImportCroppingUtilNonPdf.h" | |
7 | ||
8 | ImportCroppingUtilNonPdf::ImportCroppingUtilNonPdf() | |
9 | { | |
10 | } | |
11 | ||
12 | bool ImportCroppingUtilNonPdf::applyImportCropping (bool isRegression, | |
13 | ImportCropping importCropping) const | |
14 | { | |
15 | bool cropping = false; | |
16 | ||
17 | if (!isRegression) { | |
18 | ||
19 | cropping = (importCropping == IMPORT_CROPPING_ALWAYS); | |
20 | } | |
21 | ||
22 | return cropping; | |
23 | } |
0 | /****************************************************************************************************** | |
1 | * (C) 2016 markummitchell@github.com. This file is part of Engauge Digitizer, which is released * | |
2 | * under GNU General Public License version 2 (GPLv2) or (at your option) any later version. See file * | |
3 | * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. * | |
4 | ******************************************************************************************************/ | |
5 | ||
6 | #ifndef IMPORT_CROPPING_UTIL_NON_PDF_H | |
7 | #define IMPORT_CROPPING_UTIL_NON_PDF_H | |
8 | ||
9 | #include "ImportCropping.h" | |
10 | #include "ImportCroppingUtilBase.h" | |
11 | ||
12 | /// Import of non-pdf files | |
13 | class ImportCroppingUtilNonPdf : public ImportCroppingUtilBase | |
14 | { | |
15 | public: | |
16 | /// Single constructor | |
17 | ImportCroppingUtilNonPdf(); | |
18 | ||
19 | /// Skip cropping dialog during regression testing, otherwise crop if it is always turned on | |
20 | bool applyImportCropping (bool isRegression, | |
21 | ImportCropping importCropping) const; | |
22 | ||
23 | }; | |
24 | ||
25 | #endif // IMPORT_CROPPING_UTIL_NON_PDF_H |
0 | /****************************************************************************************************** | |
1 | * (C) 2016 markummitchell@github.com. This file is part of Engauge Digitizer, which is released * | |
2 | * under GNU General Public License version 2 (GPLv2) or (at your option) any later version. See file * | |
3 | * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. * | |
4 | ******************************************************************************************************/ | |
5 | ||
6 | #include "ImportCroppingUtilPdf.h" | |
7 | #include "poppler-qt5.h" | |
8 | #include <QApplication> | |
9 | ||
10 | using namespace Poppler; | |
11 | ||
12 | ImportCroppingUtilPdf::ImportCroppingUtilPdf() | |
13 | { | |
14 | } | |
15 | ||
16 | bool ImportCroppingUtilPdf::applyImportCropping (bool isErrorReportRegressionTest, | |
17 | const QString &fileName, | |
18 | ImportCropping importCropping, | |
19 | Document *&document) const | |
20 | { | |
21 | document = 0; | |
22 | ||
23 | bool cropping = false; | |
24 | ||
25 | if (!isErrorReportRegressionTest) { | |
26 | ||
27 | // Simple check to prevent complaints from poppler code | |
28 | if (fileName.right (4).toLower () == ".pdf") { | |
29 | ||
30 | // Try to read the file | |
31 | QApplication::setOverrideCursor (Qt::BusyCursor); // Since load could take a while | |
32 | document = Document::load (fileName); | |
33 | QApplication::restoreOverrideCursor(); | |
34 | if (document != 0) { | |
35 | if (!document->isLocked ()) { | |
36 | ||
37 | cropping = (importCropping == IMPORT_CROPPING_ALWAYS || | |
38 | (importCropping == IMPORT_CROPPING_MULTIPAGE_PDFS && document->numPages () > 1)); | |
39 | } | |
40 | } | |
41 | } | |
42 | } | |
43 | ||
44 | return cropping; | |
45 | } |
0 | /****************************************************************************************************** | |
1 | * (C) 2016 markummitchell@github.com. This file is part of Engauge Digitizer, which is released * | |
2 | * under GNU General Public License version 2 (GPLv2) or (at your option) any later version. See file * | |
3 | * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. * | |
4 | ******************************************************************************************************/ | |
5 | ||
6 | #ifndef IMPORT_CROPPING_UTIL_PDF_H | |
7 | #define IMPORT_CROPPING_UTIL_PDF_H | |
8 | ||
9 | #include "ImportCropping.h" | |
10 | #include "ImportCroppingUtilBase.h" | |
11 | #include <QString> | |
12 | ||
13 | namespace Poppler { | |
14 | class Document; | |
15 | } | |
16 | ||
17 | /// Import of pdf files | |
18 | class ImportCroppingUtilPdf : public ImportCroppingUtilBase | |
19 | { | |
20 | public: | |
21 | /// Single constructor | |
22 | ImportCroppingUtilPdf(); | |
23 | ||
24 | /// For pdf files, skip cropping dialog during regression testing, otherwise crop if it is always turned on or if | |
25 | /// there are multiple pages. | |
26 | /// | |
27 | /// For speed, the Document is returned if cropping is to be performed so the file needs to be read only once | |
28 | bool applyImportCropping (bool isRegression, | |
29 | const QString &fileName, | |
30 | ImportCropping importCropping, | |
31 | Poppler::Document *&document) const; | |
32 | ||
33 | }; | |
34 | ||
35 | #endif // IMPORT_CROPPING_UTIL_PDF_H |
0 | /****************************************************************************************************** | |
1 | * (C) 2014 markummitchell@github.com. This file is part of Engauge Digitizer, which is released * | |
2 | * under GNU General Public License version 2 (GPLv2) or (at your option) any later version. See file * | |
3 | * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. * | |
4 | ******************************************************************************************************/ | |
5 | ||
6 | #include "DlgImportCroppingNonPdf.h" | |
7 | #include "ImportCroppingUtilNonPdf.h" | |
8 | #include "NonPdf.h" | |
9 | #include <QApplication> | |
10 | #include <QImage> | |
11 | #include <QString> | |
12 | ||
13 | NonPdf::NonPdf () | |
14 | { | |
15 | } | |
16 | ||
17 | NonPdfReturn NonPdf::load (const QString &fileName, | |
18 | QImage &image, | |
19 | ImportCropping importCropping, | |
20 | bool isErrorReportRegressionTest) const | |
21 | { | |
22 | ImportCroppingUtilNonPdf importCroppingUtil; | |
23 | bool cropping = importCroppingUtil.applyImportCropping (isErrorReportRegressionTest, | |
24 | importCropping); | |
25 | ||
26 | NonPdfReturn rtn; | |
27 | QApplication::setOverrideCursor(Qt::BusyCursor); // Since loading can be slow | |
28 | if (cropping) { | |
29 | ||
30 | rtn = loadWithCropping (fileName, | |
31 | image); | |
32 | ||
33 | } else { | |
34 | ||
35 | rtn = loadWithoutCropping (fileName, | |
36 | image); | |
37 | ||
38 | } | |
39 | QApplication::restoreOverrideCursor(); | |
40 | ||
41 | return rtn; | |
42 | } | |
43 | ||
44 | NonPdfReturn NonPdf::loadWithCropping (const QString &fileName, | |
45 | QImage &image) const | |
46 | { | |
47 | NonPdfReturn nonPdfReturn = NON_PDF_RETURN_FAILED; | |
48 | ||
49 | // Get page and extent. At this point it is always true that the image can be read | |
50 | DlgImportCroppingNonPdf dlg (fileName); | |
51 | if (dlg.exec() == QDialog::Accepted) { | |
52 | ||
53 | // Returned image is null if it could not be read | |
54 | image = dlg.image (); | |
55 | ||
56 | if (!image.isNull()) { | |
57 | nonPdfReturn = NON_PDF_RETURN_SUCCESS; | |
58 | } | |
59 | ||
60 | } else { | |
61 | nonPdfReturn = NON_PDF_RETURN_CANCELED; | |
62 | } | |
63 | ||
64 | return nonPdfReturn; | |
65 | } | |
66 | ||
67 | NonPdfReturn NonPdf::loadWithoutCropping (const QString &fileName, | |
68 | QImage &image) const | |
69 | { | |
70 | NonPdfReturn nonPdfReturn = NON_PDF_RETURN_FAILED; | |
71 | ||
72 | if (image.load (fileName)) { | |
73 | nonPdfReturn = NON_PDF_RETURN_SUCCESS; | |
74 | } | |
75 | ||
76 | return nonPdfReturn; | |
77 | } |
0 | /****************************************************************************************************** | |
1 | * (C) 2014 markummitchell@github.com. This file is part of Engauge Digitizer, which is released * | |
2 | * under GNU General Public License version 2 (GPLv2) or (at your option) any later version. See file * | |
3 | * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. * | |
4 | ******************************************************************************************************/ | |
5 | ||
6 | #ifndef NON_PDF_H | |
7 | #define NON_PDF_H | |
8 | ||
9 | #include "ImportCropping.h" | |
10 | ||
11 | namespace Poppler { | |
12 | class Document; | |
13 | } | |
14 | class QImage; | |
15 | class QString; | |
16 | ||
17 | /// Return values from load operation | |
18 | enum NonPdfReturn { | |
19 | NON_PDF_RETURN_CANCELED, | |
20 | NON_PDF_RETURN_FAILED, | |
21 | NON_PDF_RETURN_SUCCESS | |
22 | }; | |
23 | ||
24 | /// Wrapper around the QImage class for read and importing non-PDF files. | |
25 | class NonPdf | |
26 | { | |
27 | public: | |
28 | /// Single constructor | |
29 | NonPdf(); | |
30 | ||
31 | /// Try to load the specified file. Success is indicated in the function return value | |
32 | NonPdfReturn load (const QString &fileName, | |
33 | QImage &image, | |
34 | ImportCropping importCropping, | |
35 | bool isErrorReportRegressionTest) const; | |
36 | ||
37 | private: | |
38 | ||
39 | NonPdfReturn loadWithCropping (const QString &fileName, | |
40 | QImage &image) const; // Dialog is used when not testing | |
41 | NonPdfReturn loadWithoutCropping (const QString &fileName, | |
42 | QImage &image) const; // No dialog is used during testing. Entire image will be loadedd | |
43 | ||
44 | }; | |
45 | ||
46 | #endif // NON_PDF_H |
0 | /****************************************************************************************************** | |
1 | * (C) 2014 markummitchell@github.com. This file is part of Engauge Digitizer, which is released * | |
2 | * under GNU General Public License version 2 (GPLv2) or (at your option) any later version. See file * | |
3 | * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. * | |
4 | ******************************************************************************************************/ | |
5 | ||
6 | #include "Logger.h" | |
7 | #include "NonPdfCropping.h" | |
8 | #include "NonPdfFrameHandle.h" | |
9 | #include <QGraphicsRectItem> | |
10 | #include <QGraphicsScene> | |
11 | #include <QRect> | |
12 | #include "QtToString.h" | |
13 | #include "ViewPreview.h" | |
14 | ||
15 | const int Z_BOX = 50; // Under box and over background image | |
16 | const int Z_HANDLE = 100; // Over box and background image | |
17 | ||
18 | NonPdfCropping::NonPdfCropping (QGraphicsScene &scene, | |
19 | ViewPreview &view) : | |
20 | m_view (view) | |
21 | { | |
22 | createWidgets (scene); | |
23 | } | |
24 | ||
25 | void NonPdfCropping::createWidgets(QGraphicsScene &scene) | |
26 | { | |
27 | const double MARGIN_PERCENT = 5.0; | |
28 | const int ZERO_WIDTH_IS_ALWAYS_VISIBLE = 0; | |
29 | ||
30 | int marginHor = scene.width() * MARGIN_PERCENT / 100.0; | |
31 | int marginVer = scene.height() * MARGIN_PERCENT / 100.0; | |
32 | ||
33 | QRect box (scene.sceneRect().left() + marginHor, | |
34 | scene.sceneRect().top() + marginVer, | |
35 | scene.sceneRect().width() - 2 * marginHor, | |
36 | scene.sceneRect().height() - 2 * marginVer); | |
37 | ||
38 | m_handleTL = new NonPdfFrameHandle (scene, m_view, box.topLeft() , NON_PDF_CROPPING_LEFT | NON_PDF_CROPPING_TOP , *this, Z_HANDLE); | |
39 | m_handleTR = new NonPdfFrameHandle (scene, m_view, box.topRight() , NON_PDF_CROPPING_RIGHT | NON_PDF_CROPPING_TOP , *this, Z_HANDLE); | |
40 | m_handleBR = new NonPdfFrameHandle (scene, m_view, box.bottomRight(), NON_PDF_CROPPING_RIGHT | NON_PDF_CROPPING_BOTTOM , *this, Z_HANDLE); | |
41 | m_handleBL = new NonPdfFrameHandle (scene, m_view, box.bottomLeft() , NON_PDF_CROPPING_LEFT | NON_PDF_CROPPING_BOTTOM , *this, Z_HANDLE); | |
42 | ||
43 | m_box = new QGraphicsRectItem; | |
44 | m_box->setZValue (Z_BOX); | |
45 | m_box->setPen (QPen (QBrush (Qt::gray), ZERO_WIDTH_IS_ALWAYS_VISIBLE)); | |
46 | scene.addItem (m_box); | |
47 | ||
48 | updateBox (); | |
49 | } | |
50 | ||
51 | void NonPdfCropping::disableEventsWhileMovingAutomatically () | |
52 | { | |
53 | m_handleTL->setDisableEventsWhileMovingAutomatically (true); | |
54 | m_handleTR->setDisableEventsWhileMovingAutomatically (true); | |
55 | m_handleBR->setDisableEventsWhileMovingAutomatically (true); | |
56 | m_handleBL->setDisableEventsWhileMovingAutomatically (true); | |
57 | } | |
58 | ||
59 | void NonPdfCropping::enableEventsWhileMovingAutomatically () | |
60 | { | |
61 | m_handleTL->setDisableEventsWhileMovingAutomatically (false); | |
62 | m_handleTR->setDisableEventsWhileMovingAutomatically (false); | |
63 | m_handleBR->setDisableEventsWhileMovingAutomatically (false); | |
64 | m_handleBL->setDisableEventsWhileMovingAutomatically (false); | |
65 | } | |
66 | ||
67 | QRectF NonPdfCropping::frameRect () const | |
68 | { | |
69 | // The x(), y(), pos(), rect() and boundingRect() will return coordinates assuming origin at the initial position of | |
70 | // each handle. So to get the coordinates in the window reference frame it takes a two step process like | |
71 | // QGraphicsRectItem::mapRectToScene (QGraphicsRectItem::rect()) | |
72 | ||
73 | QRectF rectTL = m_handleTL->mapRectToScene (m_handleTL->boundingRect()); | |
74 | QRectF rectBR = m_handleBR->mapRectToScene (m_handleBR->boundingRect()); | |
75 | ||
76 | QRectF rectUnited = rectTL.united (rectBR); | |
77 | ||
78 | return rectUnited; | |
79 | } | |
80 | ||
81 | void NonPdfCropping::moveBL (const QPointF &newPos, | |
82 | const QPointF &oldPos) | |
83 | { | |
84 | disableEventsWhileMovingAutomatically(); | |
85 | ||
86 | double deltaX = newPos.x() - oldPos.x(); | |
87 | double deltaY = newPos.y() - oldPos.y(); | |
88 | ||
89 | m_handleTL->moveBy (deltaX, | |
90 | 0); | |
91 | m_handleBR->moveBy (0, | |
92 | deltaY); | |
93 | ||
94 | enableEventsWhileMovingAutomatically(); | |
95 | ||
96 | updateBox(); | |
97 | } | |
98 | ||
99 | void NonPdfCropping::moveBR (const QPointF &newPos, | |
100 | const QPointF &oldPos) | |
101 | { | |
102 | disableEventsWhileMovingAutomatically(); | |
103 | ||
104 | double deltaX = newPos.x() - oldPos.x(); | |
105 | double deltaY = newPos.y() - oldPos.y(); | |
106 | ||
107 | m_handleBL->moveBy (0, | |
108 | deltaY); | |
109 | m_handleTR->moveBy (deltaX, | |
110 | 0); | |
111 | ||
112 | enableEventsWhileMovingAutomatically(); | |
113 | ||
114 | updateBox(); | |
115 | } | |
116 | ||
117 | void NonPdfCropping::moveTL (const QPointF &newPos, | |
118 | const QPointF &oldPos) | |
119 | { | |
120 | disableEventsWhileMovingAutomatically(); | |
121 | ||
122 | double deltaX = newPos.x() - oldPos.x(); | |
123 | double deltaY = newPos.y() - oldPos.y(); | |
124 | ||
125 | m_handleBL->moveBy (deltaX, | |
126 | 0); | |
127 | m_handleTR->moveBy (0, | |
128 | deltaY); | |
129 | ||
130 | enableEventsWhileMovingAutomatically(); | |
131 | ||
132 | updateBox(); | |
133 | } | |
134 | ||
135 | void NonPdfCropping::moveTR (const QPointF &newPos, | |
136 | const QPointF &oldPos) | |
137 | { | |
138 | disableEventsWhileMovingAutomatically(); | |
139 | ||
140 | double deltaX = newPos.x() - oldPos.x(); | |
141 | double deltaY = newPos.y() - oldPos.y(); | |
142 | ||
143 | m_handleTL->moveBy (0, | |
144 | deltaY); | |
145 | m_handleBR->moveBy (deltaX, | |
146 | 0); | |
147 | ||
148 | enableEventsWhileMovingAutomatically(); | |
149 | ||
150 | updateBox(); | |
151 | } | |
152 | ||
153 | void NonPdfCropping::updateBox () | |
154 | { | |
155 | QRectF rectUnited = frameRect (); | |
156 | ||
157 | // Adjust by one pixel in both horizontal and vertical directions so bottom/right handles end on the box | |
158 | rectUnited.setWidth (rectUnited.width () - 1); | |
159 | rectUnited.setHeight (rectUnited.height () - 1); | |
160 | ||
161 | m_box->setRect (rectUnited); | |
162 | } | |
163 | ||
164 | QSize NonPdfCropping::windowSize () const | |
165 | { | |
166 | return QSize (m_view.scene()->width(), | |
167 | m_view.scene()->height()); | |
168 | } |
0 | /****************************************************************************************************** | |
1 | * (C) 2014 markummitchell@github.com. This file is part of Engauge Digitizer, which is released * | |
2 | * under GNU General Public License version 2 (GPLv2) or (at your option) any later version. See file * | |
3 | * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. * | |
4 | ******************************************************************************************************/ | |
5 | ||
6 | #ifndef NON_PDF_CROPPING_H | |
7 | #define NON_PDF_CROPPING_H | |
8 | ||
9 | #include <QRect> | |
10 | #include <QSize> | |
11 | ||
12 | class NonPdfFrameHandle; | |
13 | class QGraphicsRectItem; | |
14 | class QGraphicsScene; | |
15 | class QPointF; | |
16 | class ViewPreview; | |
17 | ||
18 | /// This class shows a frame around the selected portion of the import preview window | |
19 | /// | |
20 | /// This class was developed as a non-pdf equivalent to the PdfCropping class. See that class for more details | |
21 | class NonPdfCropping | |
22 | { | |
23 | public: | |
24 | /// Single constructor | |
25 | NonPdfCropping(QGraphicsScene &scene, | |
26 | ViewPreview &view); | |
27 | ||
28 | /// Frame rectangle selected by user | |
29 | QRectF frameRect () const; | |
30 | ||
31 | /// Bottom left corner handle was moved | |
32 | void moveBL (const QPointF &newPos, | |
33 | const QPointF &oldPos); | |
34 | ||
35 | /// Bottom right corner handle was moved | |
36 | void moveBR (const QPointF &newPos, | |
37 | const QPointF &oldPos); | |
38 | ||
39 | /// Top left corner handle was moved | |
40 | void moveTL (const QPointF &newPos, | |
41 | const QPointF &oldPos); | |
42 | ||
43 | /// Top right corner handle was moved | |
44 | void moveTR (const QPointF &newPos, | |
45 | const QPointF &oldPos); | |
46 | ||
47 | static const int NON_PDF_CROPPING_BOTTOM = 1; ///< Bit flag when handle is aligned with bottom edge at reference point | |
48 | static const int NON_PDF_CROPPING_LEFT = 2; ///< Bit flag when handle is aligned with left edge at reference point | |
49 | static const int NON_PDF_CROPPING_RIGHT = 4; ///< Bit flag when handle is aligned with right edge at reference point | |
50 | static const int NON_PDF_CROPPING_TOP = 8; ///< Bit flag when handle is aligned with top edge at reference point | |
51 | ||
52 | /// Size of window in scene coordinates | |
53 | QSize windowSize () const; | |
54 | ||
55 | private: | |
56 | NonPdfCropping (); | |
57 | ||
58 | void createWidgets (QGraphicsScene &scene); | |
59 | void disableEventsWhileMovingAutomatically(); | |
60 | void enableEventsWhileMovingAutomatically(); | |
61 | QRectF rectFromTLAndBR () const; | |
62 | void updateBox(); | |
63 | ||
64 | ViewPreview &m_view; | |
65 | ||
66 | // Box | |
67 | QGraphicsRectItem *m_box; | |
68 | ||
69 | // Handles | |
70 | NonPdfFrameHandle *m_handleTL; | |
71 | NonPdfFrameHandle *m_handleTR; | |
72 | NonPdfFrameHandle *m_handleBR; | |
73 | NonPdfFrameHandle *m_handleBL; | |
74 | ||
75 | }; | |
76 | ||
77 | #endif // NON_PDF_CROPPING_H |
0 | /****************************************************************************************************** | |
1 | * (C) 2014 markummitchell@github.com. This file is part of Engauge Digitizer, which is released * | |
2 | * under GNU General Public License version 2 (GPLv2) or (at your option) any later version. See file * | |
3 | * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. * | |
4 | ******************************************************************************************************/ | |
5 | ||
6 | #include "NonPdfCropping.h" | |
7 | #include "NonPdfFrameHandle.h" | |
8 | #include <QBrush> | |
9 | #include <QGraphicsScene> | |
10 | #include <QGraphicsView> | |
11 | #include <QStyleOptionGraphicsItem> | |
12 | ||
13 | const double HANDLE_SIZE_AS_FRACTION_OF_WINDOW_SIZE = 30; | |
14 | ||
15 | NonPdfFrameHandle::NonPdfFrameHandle (QGraphicsScene &scene, | |
16 | QGraphicsView &view, | |
17 | const QPointF &pointReference, | |
18 | int orientationFlags, | |
19 | NonPdfCropping &nonPdfCropping, | |
20 | int zValue) : | |
21 | m_nonPdfCropping (nonPdfCropping), | |
22 | m_orientationFlags (orientationFlags), | |
23 | m_disableEventsWhileMovingAutomatically (false), | |
24 | m_scene (scene), | |
25 | m_view (view) | |
26 | { | |
27 | const double SUBTLE_OPACITY = 0.2; | |
28 | ||
29 | // Advantages of using ItemIgnoresTransformations: | |
30 | // 1) handles do not get bigger or smaller depending on the size of the image | |
31 | // 2) handles never get ugly when zoomed in | |
32 | // 3) handles never get too tiny when zoomed out | |
33 | // Disadvantages of using ItemIgnoresTransformation: | |
34 | // 1) Resizing the preview window with ItemIgnoresTransformations moves the handles out of position | |
35 | // 2) More conversions back and forth between untransformed and transformed coordinates. This was the deal breaker since | |
36 | // the transformations were undocumented and ultimately too difficult | |
37 | // The solution is to have constant-size handles WITHOUT ItemIgnoresTransformations. This means resizing the window | |
38 | // also involves resizing the handles, but everything else is pretty easy | |
39 | // | |
40 | // ItemIgnoresTransformations flag must agree with the QGraphicsRectItem used for the frame box by PdfCropping | |
41 | setFlags (QGraphicsItem::ItemIsMovable | | |
42 | QGraphicsItem::ItemIsSelectable | | |
43 | QGraphicsItem::ItemSendsScenePositionChanges); | |
44 | ||
45 | // Fill with nice color for better visibility. Note that the pen is disabled by overriding the paint method | |
46 | setBrush (QBrush (Qt::blue)); | |
47 | setVisible (true); | |
48 | setZValue (zValue); | |
49 | setOpacity (SUBTLE_OPACITY); | |
50 | setPos (pointReference); // Point position is handled in scene/view coordinates | |
51 | ||
52 | // Add to scene | |
53 | scene.addItem (this); | |
54 | ||
55 | QSize handleSize = m_nonPdfCropping.windowSize() / HANDLE_SIZE_AS_FRACTION_OF_WINDOW_SIZE; | |
56 | ||
57 | // Adjust positions of handles that are not at the top left so handles are laid out symmetrically | |
58 | QPointF pointPos = pointReference; | |
59 | if ((orientationFlags & NonPdfCropping::NON_PDF_CROPPING_LEFT) != 0) { | |
60 | pointPos.setX (pointPos.x() - handleSize.width() / 2.0); | |
61 | } else if ((orientationFlags & NonPdfCropping::NON_PDF_CROPPING_RIGHT) != 0) { | |
62 | pointPos.setX (pointPos.x() + handleSize.width() / 2.0); | |
63 | } | |
64 | if ((orientationFlags & NonPdfCropping::NON_PDF_CROPPING_TOP) != 0) { | |
65 | pointPos.setY (pointPos.y() - handleSize.height() / 2.0); | |
66 | } else if ((orientationFlags & NonPdfCropping::NON_PDF_CROPPING_BOTTOM) != 0) { | |
67 | pointPos.setY (pointPos.y() + handleSize.height() / 2.0); | |
68 | } | |
69 | ||
70 | // Start with geometry. Since point positions are handled in scene/view coordinates, we have to convert | |
71 | // to local coordinates for the rectangle | |
72 | QPointF topLeftLocal = mapFromScene (pointPos); | |
73 | ||
74 | setRect (QRectF (topLeftLocal, | |
75 | handleSize)); | |
76 | } | |
77 | ||
78 | QVariant NonPdfFrameHandle::itemChange (GraphicsItemChange change, | |
79 | const QVariant &value) | |
80 | { | |
81 | QVariant valueFiltered = value; | |
82 | ||
83 | if (change == ItemPositionChange && scene()) { | |
84 | ||
85 | QPointF sizeAsPointF (boundingRect().size().width(), | |
86 | boundingRect().size().height()); | |
87 | ||
88 | // New position is in the value argument | |
89 | QPointF newPos = valueFiltered.toPointF(); | |
90 | QPointF oldPos = pos (); | |
91 | ||
92 | // This sequence is from http://www.qtcentre.org/threads/47248-How-to-efficiently-get-position-of-a-QGraphicsItem-in-view-coordinates | |
93 | QRectF newRectItem (newPos, | |
94 | QSize (boundingRect().size().width(), | |
95 | boundingRect().size().height())); | |
96 | QPolygonF newRectScene = mapToScene (newRectItem); | |
97 | QPolygon newRectView = m_view.mapFromScene (newRectScene.boundingRect()); | |
98 | ||
99 | // Skip moving of this handle if it will go outside of the window | |
100 | QRectF rectWindow = m_scene.sceneRect(); | |
101 | if (!rectWindow.contains (newRectView.boundingRect())) { | |
102 | ||
103 | // Keep the item inside the scene rectangle | |
104 | newPos.setX (qMin (rectWindow.right(), qMax (newPos.x(), rectWindow.left()))); | |
105 | newPos.setY (qMin (rectWindow.bottom(), qMax (newPos.y(), rectWindow.top()))); | |
106 | ||
107 | valueFiltered = (newPos); | |
108 | ||
109 | } | |
110 | ||
111 | // Skip moving of other handles, in response to the move of this handle, if event handling is (temporarily) off, | |
112 | // to prevent an infinite loop | |
113 | if (!m_disableEventsWhileMovingAutomatically) { | |
114 | ||
115 | bool left = ((m_orientationFlags & NonPdfCropping::NON_PDF_CROPPING_LEFT ) != 0); | |
116 | bool right = ((m_orientationFlags & NonPdfCropping::NON_PDF_CROPPING_RIGHT ) != 0); | |
117 | bool top = ((m_orientationFlags & NonPdfCropping::NON_PDF_CROPPING_TOP ) != 0); | |
118 | bool bottom = ((m_orientationFlags & NonPdfCropping::NON_PDF_CROPPING_BOTTOM) != 0); | |
119 | ||
120 | if (left && top) { | |
121 | m_nonPdfCropping.moveTL (newPos, oldPos); | |
122 | } else if (right && top) { | |
123 | m_nonPdfCropping.moveTR (newPos, oldPos); | |
124 | } else if (right && bottom) { | |
125 | m_nonPdfCropping.moveBR (newPos, oldPos); | |
126 | } else if (left && bottom) { | |
127 | m_nonPdfCropping.moveBL (newPos, oldPos); | |
128 | } | |
129 | } | |
130 | } | |
131 | ||
132 | return QGraphicsItem::itemChange(change, valueFiltered); | |
133 | } | |
134 | ||
135 | void NonPdfFrameHandle::paint (QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) | |
136 | { | |
137 | // Temporarily remove the selected option | |
138 | QStyleOptionGraphicsItem scrubbed (*option); | |
139 | scrubbed.state &= ~QStyle::State_Selected; | |
140 | QGraphicsRectItem::paint (painter, &scrubbed, widget); | |
141 | } | |
142 | ||
143 | void NonPdfFrameHandle::setDisableEventsWhileMovingAutomatically (bool disable) | |
144 | { | |
145 | m_disableEventsWhileMovingAutomatically = disable; | |
146 | } |
0 | /****************************************************************************************************** | |
1 | * (C) 2014 markummitchell@github.com. This file is part of Engauge Digitizer, which is released * | |
2 | * under GNU General Public License version 2 (GPLv2) or (at your option) any later version. See file * | |
3 | * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. * | |
4 | ******************************************************************************************************/ | |
5 | ||
6 | #ifndef NON_PDF_FRAME_HANDLE_H | |
7 | #define NON_PDF_FRAME_HANDLE_H | |
8 | ||
9 | #include <QGraphicsRectItem> | |
10 | ||
11 | class NonPdfCropping; | |
12 | class QGraphicsScene; | |
13 | class QGraphicsView; | |
14 | class QPointF; | |
15 | class QRectF; | |
16 | ||
17 | /// This class acts as a single handle for the NonPdfCropping class | |
18 | class NonPdfFrameHandle : public QGraphicsRectItem | |
19 | { | |
20 | public: | |
21 | /// Single constructor | |
22 | NonPdfFrameHandle(QGraphicsScene &scene, | |
23 | QGraphicsView &view, | |
24 | const QPointF &pointReference, | |
25 | int orientationFlags, | |
26 | NonPdfCropping &nonPdfCropping, | |
27 | int zValue); | |
28 | ||
29 | /// Intercept the drags and process them, which is the whole point of handles | |
30 | virtual QVariant itemChange(GraphicsItemChange change, const QVariant &value); | |
31 | ||
32 | /// Override the paint method so the dashed-border-when-selected can be removed | |
33 | virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); | |
34 | ||
35 | /// Temporarily disable event handling so code can move this object without triggering a cascade of events | |
36 | void setDisableEventsWhileMovingAutomatically (bool disable); | |
37 | ||
38 | private: | |
39 | NonPdfFrameHandle(); | |
40 | ||
41 | NonPdfCropping &m_nonPdfCropping; | |
42 | int m_orientationFlags; // From PdfCropping constants | |
43 | ||
44 | bool m_disableEventsWhileMovingAutomatically; | |
45 | QGraphicsScene &m_scene; | |
46 | QGraphicsView &m_view; | |
47 | }; | |
48 | ||
49 | #endif // NON_PDF_FRAME_HANDLE_H |
3 | 3 | * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. * |
4 | 4 | ******************************************************************************************************/ |
5 | 5 | |
6 | #include "DlgPdfFrame.h" | |
6 | #include "DlgImportCroppingPdf.h" | |
7 | #include "ImportCroppingUtilPdf.h" | |
7 | 8 | #include "Pdf.h" |
8 | 9 | #include "poppler-qt5.h" |
10 | #include <QApplication> | |
9 | 11 | #include <QImage> |
10 | 12 | #include <QString> |
11 | 13 | |
22 | 24 | PdfReturn Pdf::load (const QString &fileName, |
23 | 25 | QImage &image, |
24 | 26 | int resolution, |
27 | ImportCropping importCropping, | |
25 | 28 | bool isErrorReportRegressionTest) const |
26 | 29 | { |
27 | if (isErrorReportRegressionTest) { | |
28 | return loadForTesting (fileName, | |
29 | image, | |
30 | resolution); | |
30 | Document *document = 0; | |
31 | ||
32 | ImportCroppingUtilPdf importCroppingUtil; | |
33 | bool cropping = importCroppingUtil.applyImportCropping (isErrorReportRegressionTest, | |
34 | fileName, | |
35 | importCropping, | |
36 | document); | |
37 | ||
38 | PdfReturn rtn; | |
39 | QApplication::setOverrideCursor(Qt::BusyCursor); // Since loading can be slow | |
40 | if (cropping) { | |
41 | ||
42 | rtn = loadWithCropping (document, | |
43 | image, | |
44 | resolution); | |
45 | ||
31 | 46 | } else { |
32 | return loadNotTesting (fileName, | |
33 | image, | |
34 | resolution); | |
47 | ||
48 | rtn = loadWithoutCropping (fileName, | |
49 | image, | |
50 | resolution); | |
51 | ||
35 | 52 | } |
53 | QApplication::restoreOverrideCursor(); | |
54 | ||
55 | if (document != 0) { | |
56 | delete document; | |
57 | } | |
58 | ||
59 | return rtn; | |
36 | 60 | } |
37 | 61 | |
38 | PdfReturn Pdf::loadForTesting (const QString &fileName, | |
39 | QImage &image, | |
40 | int resolution) const | |
62 | PdfReturn Pdf::loadWithCropping (Document *document, | |
63 | QImage &image, | |
64 | int resolution) const | |
65 | { | |
66 | PdfReturn pdfReturn = PDF_RETURN_FAILED; | |
67 | ||
68 | // Get page and extent. At this point it is always true that the image can be read | |
69 | DlgImportCroppingPdf dlg (*document, | |
70 | resolution); | |
71 | if (dlg.exec() == QDialog::Accepted) { | |
72 | ||
73 | // Returned image is null if it could not be read | |
74 | image = dlg.image (); | |
75 | ||
76 | if (!image.isNull()) { | |
77 | pdfReturn = PDF_RETURN_SUCCESS; | |
78 | } | |
79 | ||
80 | } else { | |
81 | pdfReturn = PDF_RETURN_CANCELED; | |
82 | } | |
83 | ||
84 | return pdfReturn; | |
85 | } | |
86 | ||
87 | PdfReturn Pdf::loadWithoutCropping (const QString &fileName, | |
88 | QImage &image, | |
89 | int resolution) const | |
41 | 90 | { |
42 | 91 | PdfReturn pdfReturn = PDF_RETURN_FAILED; |
43 | 92 | |
74 | 123 | |
75 | 124 | return pdfReturn; |
76 | 125 | } |
77 | ||
78 | PdfReturn Pdf::loadNotTesting (const QString &fileName, | |
79 | QImage &image, | |
80 | int resolution) const | |
81 | { | |
82 | PdfReturn pdfReturn = PDF_RETURN_FAILED; | |
83 | ||
84 | // Simple check to prevent complaints from poppler code | |
85 | if (fileName.right (4).toLower () == ".pdf") { | |
86 | ||
87 | // Try to read the file | |
88 | Document *document = Document::load (fileName); | |
89 | ||
90 | if (document != 0) { | |
91 | if (!document->isLocked ()) { | |
92 | ||
93 | // Get page and extent | |
94 | DlgPdfFrame dlg (*document, | |
95 | resolution); | |
96 | if (dlg.exec() == QDialog::Accepted) { | |
97 | ||
98 | // Returned image is null if it could not be read | |
99 | image = dlg.image (); | |
100 | ||
101 | if (!image.isNull()) { | |
102 | pdfReturn = PDF_RETURN_SUCCESS; | |
103 | } | |
104 | ||
105 | } else { | |
106 | pdfReturn = PDF_RETURN_CANCELED; | |
107 | } | |
108 | } | |
109 | ||
110 | delete document; | |
111 | } | |
112 | } | |
113 | ||
114 | return pdfReturn; | |
115 | } |
6 | 6 | #ifndef PDF_H |
7 | 7 | #define PDF_H |
8 | 8 | |
9 | #include "ImportCropping.h" | |
10 | ||
11 | namespace Poppler { | |
12 | class Document; | |
13 | } | |
9 | 14 | class QImage; |
10 | 15 | class QString; |
11 | 16 | |
27 | 32 | |
28 | 33 | /// Try to load the specified file. Success is indicated in the function return value |
29 | 34 | PdfReturn load (const QString &fileName, |
30 | QImage &image, | |
31 | int resolution, | |
32 | bool isErrorReportRegressionTest) const; | |
35 | QImage &image, | |
36 | int resolution, | |
37 | ImportCropping importCropping, | |
38 | bool isErrorReportRegressionTest) const; | |
33 | 39 | |
34 | 40 | private: |
35 | 41 | |
36 | PdfReturn loadForTesting (const QString &fileName, | |
37 | QImage &image, | |
38 | int resolution) const; // No dialog is used during testing. Entire first page will be loaded | |
39 | PdfReturn loadNotTesting (const QString &fileName, | |
40 | QImage &image, | |
41 | int resolution) const; // Dialog is used when not testing | |
42 | PdfReturn loadWithCropping (Poppler::Document *document, | |
43 | QImage &image, | |
44 | int resolution) const; // Dialog is used when not testing | |
45 | PdfReturn loadWithoutCropping (const QString &fileName, | |
46 | QImage &image, | |
47 | int resolution) const; // No dialog is used during testing. Entire first page will be loaded | |
42 | 48 | |
43 | 49 | }; |
44 | 50 |
0 | /****************************************************************************************************** | |
1 | * (C) 2014 markummitchell@github.com. This file is part of Engauge Digitizer, which is released * | |
2 | * under GNU General Public License version 2 (GPLv2) or (at your option) any later version. See file * | |
3 | * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. * | |
4 | ******************************************************************************************************/ | |
5 | ||
6 | #include "Logger.h" | |
7 | #include "PdfCropping.h" | |
8 | #include "PdfFrameHandle.h" | |
9 | #include <QGraphicsRectItem> | |
10 | #include <QGraphicsScene> | |
11 | #include <QRect> | |
12 | #include "QtToString.h" | |
13 | #include "ViewPreview.h" | |
14 | ||
15 | const int Z_BOX = 50; // Under box and over background image | |
16 | const int Z_HANDLE = 100; // Over box and background image | |
17 | ||
18 | PdfCropping::PdfCropping (QGraphicsScene &scene, | |
19 | ViewPreview &view) : | |
20 | m_view (view) | |
21 | { | |
22 | createWidgets (scene); | |
23 | } | |
24 | ||
25 | void PdfCropping::createWidgets(QGraphicsScene &scene) | |
26 | { | |
27 | const double MARGIN_PERCENT = 5.0; | |
28 | const int ZERO_WIDTH_IS_ALWAYS_VISIBLE = 0; | |
29 | ||
30 | int marginHor = scene.width() * MARGIN_PERCENT / 100.0; | |
31 | int marginVer = scene.height() * MARGIN_PERCENT / 100.0; | |
32 | ||
33 | QRect box (scene.sceneRect().left() + marginHor, | |
34 | scene.sceneRect().top() + marginVer, | |
35 | scene.sceneRect().width() - 2 * marginHor, | |
36 | scene.sceneRect().height() - 2 * marginVer); | |
37 | ||
38 | m_handleTL = new PdfFrameHandle (scene, m_view, box.topLeft() , PDF_CROPPING_LEFT | PDF_CROPPING_TOP , *this, Z_HANDLE); | |
39 | m_handleTR = new PdfFrameHandle (scene, m_view, box.topRight() , PDF_CROPPING_RIGHT | PDF_CROPPING_TOP , *this, Z_HANDLE); | |
40 | m_handleBR = new PdfFrameHandle (scene, m_view, box.bottomRight(), PDF_CROPPING_RIGHT | PDF_CROPPING_BOTTOM , *this, Z_HANDLE); | |
41 | m_handleBL = new PdfFrameHandle (scene, m_view, box.bottomLeft() , PDF_CROPPING_LEFT | PDF_CROPPING_BOTTOM , *this, Z_HANDLE); | |
42 | ||
43 | m_box = new QGraphicsRectItem; | |
44 | m_box->setZValue (Z_BOX); | |
45 | m_box->setPen (QPen (QBrush (Qt::gray), ZERO_WIDTH_IS_ALWAYS_VISIBLE)); | |
46 | scene.addItem (m_box); | |
47 | ||
48 | updateBox (); | |
49 | } | |
50 | ||
51 | void PdfCropping::disableEventsWhileMovingAutomatically () | |
52 | { | |
53 | m_handleTL->setDisableEventsWhileMovingAutomatically (true); | |
54 | m_handleTR->setDisableEventsWhileMovingAutomatically (true); | |
55 | m_handleBR->setDisableEventsWhileMovingAutomatically (true); | |
56 | m_handleBL->setDisableEventsWhileMovingAutomatically (true); | |
57 | } | |
58 | ||
59 | void PdfCropping::enableEventsWhileMovingAutomatically () | |
60 | { | |
61 | m_handleTL->setDisableEventsWhileMovingAutomatically (false); | |
62 | m_handleTR->setDisableEventsWhileMovingAutomatically (false); | |
63 | m_handleBR->setDisableEventsWhileMovingAutomatically (false); | |
64 | m_handleBL->setDisableEventsWhileMovingAutomatically (false); | |
65 | } | |
66 | ||
67 | QRectF PdfCropping::frameRect () const | |
68 | { | |
69 | // The x(), y(), pos(), rect() and boundingRect() will return coordinates assuming origin at the initial position of | |
70 | // each handle. So to get the coordinates in the window reference frame it takes a two step process like | |
71 | // QGraphicsRectItem::mapRectToScene (QGraphicsRectItem::rect()) | |
72 | ||
73 | QRectF rectTL = m_handleTL->mapRectToScene (m_handleTL->boundingRect()); | |
74 | QRectF rectBR = m_handleBR->mapRectToScene (m_handleBR->boundingRect()); | |
75 | ||
76 | QRectF rectUnited = rectTL.united (rectBR); | |
77 | ||
78 | return rectUnited; | |
79 | } | |
80 | ||
81 | void PdfCropping::moveBL (const QPointF &newPos, | |
82 | const QPointF &oldPos) | |
83 | { | |
84 | disableEventsWhileMovingAutomatically(); | |
85 | ||
86 | double deltaX = newPos.x() - oldPos.x(); | |
87 | double deltaY = newPos.y() - oldPos.y(); | |
88 | ||
89 | m_handleTL->moveBy (deltaX, | |
90 | 0); | |
91 | m_handleBR->moveBy (0, | |
92 | deltaY); | |
93 | ||
94 | enableEventsWhileMovingAutomatically(); | |
95 | ||
96 | updateBox(); | |
97 | } | |
98 | ||
99 | void PdfCropping::moveBR (const QPointF &newPos, | |
100 | const QPointF &oldPos) | |
101 | { | |
102 | disableEventsWhileMovingAutomatically(); | |
103 | ||
104 | double deltaX = newPos.x() - oldPos.x(); | |
105 | double deltaY = newPos.y() - oldPos.y(); | |
106 | ||
107 | m_handleBL->moveBy (0, | |
108 | deltaY); | |
109 | m_handleTR->moveBy (deltaX, | |
110 | 0); | |
111 | ||
112 | enableEventsWhileMovingAutomatically(); | |
113 | ||
114 | updateBox(); | |
115 | } | |
116 | ||
117 | void PdfCropping::moveTL (const QPointF &newPos, | |
118 | const QPointF &oldPos) | |
119 | { | |
120 | disableEventsWhileMovingAutomatically(); | |
121 | ||
122 | double deltaX = newPos.x() - oldPos.x(); | |
123 | double deltaY = newPos.y() - oldPos.y(); | |
124 | ||
125 | m_handleBL->moveBy (deltaX, | |
126 | 0); | |
127 | m_handleTR->moveBy (0, | |
128 | deltaY); | |
129 | ||
130 | enableEventsWhileMovingAutomatically(); | |
131 | ||
132 | updateBox(); | |
133 | } | |
134 | ||
135 | void PdfCropping::moveTR (const QPointF &newPos, | |
136 | const QPointF &oldPos) | |
137 | { | |
138 | disableEventsWhileMovingAutomatically(); | |
139 | ||
140 | double deltaX = newPos.x() - oldPos.x(); | |
141 | double deltaY = newPos.y() - oldPos.y(); | |
142 | ||
143 | m_handleTL->moveBy (0, | |
144 | deltaY); | |
145 | m_handleBR->moveBy (deltaX, | |
146 | 0); | |
147 | ||
148 | enableEventsWhileMovingAutomatically(); | |
149 | ||
150 | updateBox(); | |
151 | } | |
152 | ||
153 | void PdfCropping::updateBox () | |
154 | { | |
155 | QRectF rectUnited = frameRect (); | |
156 | ||
157 | // Adjust by one pixel in both horizontal and vertical directions so bottom/right handles end on the box | |
158 | rectUnited.setWidth (rectUnited.width () - 1); | |
159 | rectUnited.setHeight (rectUnited.height () - 1); | |
160 | ||
161 | m_box->setRect (rectUnited); | |
162 | } | |
163 | ||
164 | QSize PdfCropping::windowSize () const | |
165 | { | |
166 | return QSize (m_view.scene()->width(), | |
167 | m_view.scene()->height()); | |
168 | } |
0 | /****************************************************************************************************** | |
1 | * (C) 2014 markummitchell@github.com. This file is part of Engauge Digitizer, which is released * | |
2 | * under GNU General Public License version 2 (GPLv2) or (at your option) any later version. See file * | |
3 | * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. * | |
4 | ******************************************************************************************************/ | |
5 | ||
6 | #ifndef PDF_CROPPING_H | |
7 | #define PDF_CROPPING_H | |
8 | ||
9 | #include <QRect> | |
10 | #include <QSize> | |
11 | ||
12 | class PdfFrameHandle; | |
13 | class QGraphicsRectItem; | |
14 | class QGraphicsScene; | |
15 | class QPointF; | |
16 | class ViewPreview; | |
17 | ||
18 | /// This class shows a frame around the selected portion of the pdf import preview window | |
19 | /// | |
20 | /// Originally there were 4 handles at the corners and 4 handles at the middles of the sides, but dragging | |
21 | /// the corner handles did not result in 1/2 the movement at the middle handles. The middle handles were deemed | |
22 | /// not worth the effort | |
23 | class PdfCropping | |
24 | { | |
25 | public: | |
26 | /// Single constructor | |
27 | PdfCropping(QGraphicsScene &scene, | |
28 | ViewPreview &view); | |
29 | ||
30 | /// Frame rectangle selected by user | |
31 | QRectF frameRect () const; | |
32 | ||
33 | /// Bottom left corner handle was moved | |
34 | void moveBL (const QPointF &newPos, | |
35 | const QPointF &oldPos); | |
36 | ||
37 | /// Bottom right corner handle was moved | |
38 | void moveBR (const QPointF &newPos, | |
39 | const QPointF &oldPos); | |
40 | ||
41 | /// Top left corner handle was moved | |
42 | void moveTL (const QPointF &newPos, | |
43 | const QPointF &oldPos); | |
44 | ||
45 | /// Top right corner handle was moved | |
46 | void moveTR (const QPointF &newPos, | |
47 | const QPointF &oldPos); | |
48 | ||
49 | static const int PDF_CROPPING_BOTTOM = 1; ///< Bit flag when handle is aligned with bottom edge at reference point | |
50 | static const int PDF_CROPPING_LEFT = 2; ///< Bit flag when handle is aligned with left edge at reference point | |
51 | static const int PDF_CROPPING_RIGHT = 4; ///< Bit flag when handle is aligned with right edge at reference point | |
52 | static const int PDF_CROPPING_TOP = 8; ///< Bit flag when handle is aligned with top edge at reference point | |
53 | ||
54 | /// Size of window in scene coordinates | |
55 | QSize windowSize () const; | |
56 | ||
57 | private: | |
58 | PdfCropping (); | |
59 | ||
60 | void createWidgets (QGraphicsScene &scene); | |
61 | void disableEventsWhileMovingAutomatically(); | |
62 | void enableEventsWhileMovingAutomatically(); | |
63 | QRectF rectFromTLAndBR () const; | |
64 | void updateBox(); | |
65 | ||
66 | ViewPreview &m_view; | |
67 | ||
68 | // Box | |
69 | QGraphicsRectItem *m_box; | |
70 | ||
71 | // Handles | |
72 | PdfFrameHandle *m_handleTL; | |
73 | PdfFrameHandle *m_handleTR; | |
74 | PdfFrameHandle *m_handleBR; | |
75 | PdfFrameHandle *m_handleBL; | |
76 | ||
77 | }; | |
78 | ||
79 | #endif // PDF_CROPPING_H |
0 | /****************************************************************************************************** | |
1 | * (C) 2014 markummitchell@github.com. This file is part of Engauge Digitizer, which is released * | |
2 | * under GNU General Public License version 2 (GPLv2) or (at your option) any later version. See file * | |
3 | * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. * | |
4 | ******************************************************************************************************/ | |
5 | ||
6 | #include "Logger.h" | |
7 | #include "PdfFrame.h" | |
8 | #include "PdfFrameHandle.h" | |
9 | #include <QGraphicsRectItem> | |
10 | #include <QGraphicsScene> | |
11 | #include <QRect> | |
12 | #include "QtToString.h" | |
13 | #include "ViewPreview.h" | |
14 | ||
15 | const int Z_BOX = 50; // Under box and over background image | |
16 | const int Z_HANDLE = 100; // Over box and background image | |
17 | ||
18 | PdfFrame::PdfFrame (QGraphicsScene &scene, | |
19 | ViewPreview &view) : | |
20 | m_view (view) | |
21 | { | |
22 | createWidgets (scene); | |
23 | } | |
24 | ||
25 | void PdfFrame::createWidgets(QGraphicsScene &scene) | |
26 | { | |
27 | const double MARGIN_PERCENT = 5.0; | |
28 | const int ZERO_WIDTH_IS_ALWAYS_VISIBLE = 0; | |
29 | ||
30 | int marginHor = scene.width() * MARGIN_PERCENT / 100.0; | |
31 | int marginVer = scene.height() * MARGIN_PERCENT / 100.0; | |
32 | ||
33 | QRect box (scene.sceneRect().left() + marginHor, | |
34 | scene.sceneRect().top() + marginVer, | |
35 | scene.sceneRect().width() - 2 * marginHor, | |
36 | scene.sceneRect().height() - 2 * marginVer); | |
37 | ||
38 | m_handleTL = new PdfFrameHandle (scene, m_view, box.topLeft() , PDF_FRAME_LEFT | PDF_FRAME_TOP , *this, Z_HANDLE); | |
39 | m_handleTR = new PdfFrameHandle (scene, m_view, box.topRight() , PDF_FRAME_RIGHT | PDF_FRAME_TOP , *this, Z_HANDLE); | |
40 | m_handleBR = new PdfFrameHandle (scene, m_view, box.bottomRight(), PDF_FRAME_RIGHT | PDF_FRAME_BOTTOM , *this, Z_HANDLE); | |
41 | m_handleBL = new PdfFrameHandle (scene, m_view, box.bottomLeft() , PDF_FRAME_LEFT | PDF_FRAME_BOTTOM , *this, Z_HANDLE); | |
42 | ||
43 | m_box = new QGraphicsRectItem; | |
44 | m_box->setZValue (Z_BOX); | |
45 | m_box->setPen (QPen (QBrush (Qt::gray), ZERO_WIDTH_IS_ALWAYS_VISIBLE)); | |
46 | scene.addItem (m_box); | |
47 | ||
48 | updateBox (); | |
49 | } | |
50 | ||
51 | void PdfFrame::disableEventsWhileMovingAutomatically () | |
52 | { | |
53 | m_handleTL->setDisableEventsWhileMovingAutomatically (true); | |
54 | m_handleTR->setDisableEventsWhileMovingAutomatically (true); | |
55 | m_handleBR->setDisableEventsWhileMovingAutomatically (true); | |
56 | m_handleBL->setDisableEventsWhileMovingAutomatically (true); | |
57 | } | |
58 | ||
59 | void PdfFrame::enableEventsWhileMovingAutomatically () | |
60 | { | |
61 | m_handleTL->setDisableEventsWhileMovingAutomatically (false); | |
62 | m_handleTR->setDisableEventsWhileMovingAutomatically (false); | |
63 | m_handleBR->setDisableEventsWhileMovingAutomatically (false); | |
64 | m_handleBL->setDisableEventsWhileMovingAutomatically (false); | |
65 | } | |
66 | ||
67 | QRectF PdfFrame::frameRect () const | |
68 | { | |
69 | // The x(), y(), pos(), rect() and boundingRect() will return coordinates assuming origin at the initial position of | |
70 | // each handle. So to get the coordinates in the window reference frame it takes a two step process like | |
71 | // QGraphicsRectItem::mapRectToScene (QGraphicsRectItem::rect()) | |
72 | ||
73 | QRectF rectTL = m_handleTL->mapRectToScene (m_handleTL->boundingRect()); | |
74 | QRectF rectBR = m_handleBR->mapRectToScene (m_handleBR->boundingRect()); | |
75 | ||
76 | QRectF rectUnited = rectTL.united (rectBR); | |
77 | ||
78 | return rectUnited; | |
79 | } | |
80 | ||
81 | void PdfFrame::moveBL (const QPointF &newPos, | |
82 | const QPointF &oldPos) | |
83 | { | |
84 | disableEventsWhileMovingAutomatically(); | |
85 | ||
86 | double deltaX = newPos.x() - oldPos.x(); | |
87 | double deltaY = newPos.y() - oldPos.y(); | |
88 | ||
89 | m_handleTL->moveBy (deltaX, | |
90 | 0); | |
91 | m_handleBR->moveBy (0, | |
92 | deltaY); | |
93 | ||
94 | enableEventsWhileMovingAutomatically(); | |
95 | ||
96 | updateBox(); | |
97 | } | |
98 | ||
99 | void PdfFrame::moveBR (const QPointF &newPos, | |
100 | const QPointF &oldPos) | |
101 | { | |
102 | disableEventsWhileMovingAutomatically(); | |
103 | ||
104 | double deltaX = newPos.x() - oldPos.x(); | |
105 | double deltaY = newPos.y() - oldPos.y(); | |
106 | ||
107 | m_handleBL->moveBy (0, | |
108 | deltaY); | |
109 | m_handleTR->moveBy (deltaX, | |
110 | 0); | |
111 | ||
112 | enableEventsWhileMovingAutomatically(); | |
113 | ||
114 | updateBox(); | |
115 | } | |
116 | ||
117 | void PdfFrame::moveTL (const QPointF &newPos, | |
118 | const QPointF &oldPos) | |
119 | { | |
120 | disableEventsWhileMovingAutomatically(); | |
121 | ||
122 | double deltaX = newPos.x() - oldPos.x(); | |
123 | double deltaY = newPos.y() - oldPos.y(); | |
124 | ||
125 | m_handleBL->moveBy (deltaX, | |
126 | 0); | |
127 | m_handleTR->moveBy (0, | |
128 | deltaY); | |
129 | ||
130 | enableEventsWhileMovingAutomatically(); | |
131 | ||
132 | updateBox(); | |
133 | } | |
134 | ||
135 | void PdfFrame::moveTR (const QPointF &newPos, | |
136 | const QPointF &oldPos) | |
137 | { | |
138 | disableEventsWhileMovingAutomatically(); | |
139 | ||
140 | double deltaX = newPos.x() - oldPos.x(); | |
141 | double deltaY = newPos.y() - oldPos.y(); | |
142 | ||
143 | m_handleTL->moveBy (0, | |
144 | deltaY); | |
145 | m_handleBR->moveBy (deltaX, | |
146 | 0); | |
147 | ||
148 | enableEventsWhileMovingAutomatically(); | |
149 | ||
150 | updateBox(); | |
151 | } | |
152 | ||
153 | void PdfFrame::updateBox () | |
154 | { | |
155 | QRectF rectUnited = frameRect (); | |
156 | ||
157 | // Adjust by one pixel in both horizontal and vertical directions so bottom/right handles end on the box | |
158 | rectUnited.setWidth (rectUnited.width () - 1); | |
159 | rectUnited.setHeight (rectUnited.height () - 1); | |
160 | ||
161 | m_box->setRect (rectUnited); | |
162 | } | |
163 | ||
164 | QSize PdfFrame::windowSize () const | |
165 | { | |
166 | return QSize (m_view.scene()->width(), | |
167 | m_view.scene()->height()); | |
168 | } |
0 | /****************************************************************************************************** | |
1 | * (C) 2014 markummitchell@github.com. This file is part of Engauge Digitizer, which is released * | |
2 | * under GNU General Public License version 2 (GPLv2) or (at your option) any later version. See file * | |
3 | * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. * | |
4 | ******************************************************************************************************/ | |
5 | ||
6 | #ifndef PDF_FRAME_H | |
7 | #define PDF_FRAME_H | |
8 | ||
9 | #include <QRect> | |
10 | #include <QSize> | |
11 | ||
12 | class PdfFrameHandle; | |
13 | class QGraphicsRectItem; | |
14 | class QGraphicsScene; | |
15 | class QPointF; | |
16 | class ViewPreview; | |
17 | ||
18 | /// This class shows a frame around the selected portion of the pdf import preview window | |
19 | /// | |
20 | /// Originally there were 4 handles at the corners and 4 handles at the middles of the sides, but dragging | |
21 | /// the corner handles did not result in 1/2 the movement at the middle handles. The middle handles were deemed | |
22 | /// not worth the effort | |
23 | class PdfFrame | |
24 | { | |
25 | public: | |
26 | /// Single constructor | |
27 | PdfFrame(QGraphicsScene &scene, | |
28 | ViewPreview &view); | |
29 | ||
30 | /// Frame rectangle selected by user | |
31 | QRectF frameRect () const; | |
32 | ||
33 | /// Bottom left corner handle was moved | |
34 | void moveBL (const QPointF &newPos, | |
35 | const QPointF &oldPos); | |
36 | ||
37 | /// Bottom right corner handle was moved | |
38 | void moveBR (const QPointF &newPos, | |
39 | const QPointF &oldPos); | |
40 | ||
41 | /// Top left corner handle was moved | |
42 | void moveTL (const QPointF &newPos, | |
43 | const QPointF &oldPos); | |
44 | ||
45 | /// Top right corner handle was moved | |
46 | void moveTR (const QPointF &newPos, | |
47 | const QPointF &oldPos); | |
48 | ||
49 | static const int PDF_FRAME_BOTTOM = 1; ///< Bit flag when handle is aligned with bottom edge at reference point | |
50 | static const int PDF_FRAME_LEFT = 2; ///< Bit flag when handle is aligned with left edge at reference point | |
51 | static const int PDF_FRAME_RIGHT = 4; ///< Bit flag when handle is aligned with right edge at reference point | |
52 | static const int PDF_FRAME_TOP = 8; ///< Bit flag when handle is aligned with top edge at reference point | |
53 | ||
54 | /// Size of window in scene coordinates | |
55 | QSize windowSize () const; | |
56 | ||
57 | private: | |
58 | PdfFrame(); | |
59 | ||
60 | void createWidgets (QGraphicsScene &scene); | |
61 | void disableEventsWhileMovingAutomatically(); | |
62 | void enableEventsWhileMovingAutomatically(); | |
63 | QRectF rectFromTLAndBR () const; | |
64 | void updateBox(); | |
65 | ||
66 | ViewPreview &m_view; | |
67 | ||
68 | // Box | |
69 | QGraphicsRectItem *m_box; | |
70 | ||
71 | // Handles | |
72 | PdfFrameHandle *m_handleTL; | |
73 | PdfFrameHandle *m_handleTR; | |
74 | PdfFrameHandle *m_handleBR; | |
75 | PdfFrameHandle *m_handleBL; | |
76 | ||
77 | }; | |
78 | ||
79 | #endif // PDF_FRAME_H |
3 | 3 | * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. * |
4 | 4 | ******************************************************************************************************/ |
5 | 5 | |
6 | #include "PdfFrame.h" | |
6 | #include "PdfCropping.h" | |
7 | 7 | #include "PdfFrameHandle.h" |
8 | 8 | #include <QBrush> |
9 | 9 | #include <QGraphicsScene> |
16 | 16 | QGraphicsView &view, |
17 | 17 | const QPointF &pointReference, |
18 | 18 | int orientationFlags, |
19 | PdfFrame &pdfFrame, | |
19 | PdfCropping &pdfCropping, | |
20 | 20 | int zValue) : |
21 | m_pdfFrame (pdfFrame), | |
21 | m_pdfCropping (pdfCropping), | |
22 | 22 | m_orientationFlags (orientationFlags), |
23 | 23 | m_disableEventsWhileMovingAutomatically (false), |
24 | 24 | m_scene (scene), |
37 | 37 | // The solution is to have constant-size handles WITHOUT ItemIgnoresTransformations. This means resizing the window |
38 | 38 | // also involves resizing the handles, but everything else is pretty easy |
39 | 39 | // |
40 | // ItemIgnoresTransformations flag must agree with the QGraphicsRectItem used for the frame box by PdfFrame | |
40 | // ItemIgnoresTransformations flag must agree with the QGraphicsRectItem used for the frame box by PdfCropping | |
41 | 41 | setFlags (QGraphicsItem::ItemIsMovable | |
42 | 42 | QGraphicsItem::ItemIsSelectable | |
43 | 43 | QGraphicsItem::ItemSendsScenePositionChanges); |
52 | 52 | // Add to scene |
53 | 53 | scene.addItem (this); |
54 | 54 | |
55 | QSize handleSize = m_pdfFrame.windowSize() / HANDLE_SIZE_AS_FRACTION_OF_WINDOW_SIZE; | |
55 | QSize handleSize = m_pdfCropping.windowSize() / HANDLE_SIZE_AS_FRACTION_OF_WINDOW_SIZE; | |
56 | 56 | |
57 | 57 | // Adjust positions of handles that are not at the top left so handles are laid out symmetrically |
58 | 58 | QPointF pointPos = pointReference; |
59 | if ((orientationFlags && PdfFrame::PDF_FRAME_LEFT) != 0) { | |
59 | if ((orientationFlags && PdfCropping::PDF_CROPPING_LEFT) != 0) { | |
60 | 60 | pointPos.setX (pointPos.x() - handleSize.width() / 2.0); |
61 | } else if ((orientationFlags && PdfFrame::PDF_FRAME_RIGHT) != 0) { | |
61 | } else if ((orientationFlags && PdfCropping::PDF_CROPPING_RIGHT) != 0) { | |
62 | 62 | pointPos.setX (pointPos.x() + handleSize.width() / 2.0); |
63 | 63 | } |
64 | if ((orientationFlags && PdfFrame::PDF_FRAME_TOP) != 0) { | |
64 | if ((orientationFlags && PdfCropping::PDF_CROPPING_TOP) != 0) { | |
65 | 65 | pointPos.setY (pointPos.y() - handleSize.height() / 2.0); |
66 | } else if ((orientationFlags && PdfFrame::PDF_FRAME_BOTTOM) != 0) { | |
66 | } else if ((orientationFlags && PdfCropping::PDF_CROPPING_BOTTOM) != 0) { | |
67 | 67 | pointPos.setY (pointPos.y() + handleSize.height() / 2.0); |
68 | 68 | } |
69 | 69 | |
112 | 112 | // to prevent an infinite loop |
113 | 113 | if (!m_disableEventsWhileMovingAutomatically) { |
114 | 114 | |
115 | bool left = ((m_orientationFlags & PdfFrame::PDF_FRAME_LEFT ) != 0); | |
116 | bool right = ((m_orientationFlags & PdfFrame::PDF_FRAME_RIGHT ) != 0); | |
117 | bool top = ((m_orientationFlags & PdfFrame::PDF_FRAME_TOP ) != 0); | |
118 | bool bottom = ((m_orientationFlags & PdfFrame::PDF_FRAME_BOTTOM) != 0); | |
115 | bool left = ((m_orientationFlags & PdfCropping::PDF_CROPPING_LEFT ) != 0); | |
116 | bool right = ((m_orientationFlags & PdfCropping::PDF_CROPPING_RIGHT ) != 0); | |
117 | bool top = ((m_orientationFlags & PdfCropping::PDF_CROPPING_TOP ) != 0); | |
118 | bool bottom = ((m_orientationFlags & PdfCropping::PDF_CROPPING_BOTTOM) != 0); | |
119 | 119 | |
120 | 120 | if (left && top) { |
121 | m_pdfFrame.moveTL (newPos, oldPos); | |
121 | m_pdfCropping.moveTL (newPos, oldPos); | |
122 | 122 | } else if (right && top) { |
123 | m_pdfFrame.moveTR (newPos, oldPos); | |
123 | m_pdfCropping.moveTR (newPos, oldPos); | |
124 | 124 | } else if (right && bottom) { |
125 | m_pdfFrame.moveBR (newPos, oldPos); | |
125 | m_pdfCropping.moveBR (newPos, oldPos); | |
126 | 126 | } else if (left && bottom) { |
127 | m_pdfFrame.moveBL (newPos, oldPos); | |
127 | m_pdfCropping.moveBL (newPos, oldPos); | |
128 | 128 | } |
129 | 129 | } |
130 | 130 | } |
8 | 8 | |
9 | 9 | #include <QGraphicsRectItem> |
10 | 10 | |
11 | class PdfFrame; | |
11 | class PdfCropping; | |
12 | 12 | class QGraphicsScene; |
13 | 13 | class QGraphicsView; |
14 | 14 | class QPointF; |
15 | 15 | class QRectF; |
16 | 16 | |
17 | /// This class acts as a single handle for the PdfFrame class | |
17 | /// This class acts as a single handle for the PdfCropping class | |
18 | 18 | class PdfFrameHandle : public QGraphicsRectItem |
19 | 19 | { |
20 | 20 | public: |
23 | 23 | QGraphicsView &view, |
24 | 24 | const QPointF &pointReference, |
25 | 25 | int orientationFlags, |
26 | PdfFrame &pdfFrame, | |
26 | PdfCropping &pdfCropping, | |
27 | 27 | int zValue); |
28 | 28 | |
29 | 29 | /// Intercept the drags and process them, which is the whole point of handles |
38 | 38 | private: |
39 | 39 | PdfFrameHandle(); |
40 | 40 | |
41 | PdfFrame &m_pdfFrame; | |
42 | int m_orientationFlags; // From PdfFrame constants | |
41 | PdfCropping &m_pdfCropping; | |
42 | int m_orientationFlags; // From PdfCropping constants | |
43 | 43 | |
44 | 44 | bool m_disableEventsWhileMovingAutomatically; |
45 | 45 | QGraphicsScene &m_scene; |
18 | 18 | const QString SETTINGS_CHECKLIST_GUIDE_DOCK_AREA ("checklistGuideDockArea"); |
19 | 19 | const QString SETTINGS_CHECKLIST_GUIDE_DOCK_GEOMETRY ("checklistGuideDockGeometry"); |
20 | 20 | const QString SETTINGS_CHECKLIST_GUIDE_WIZARD ("checklistGuideWizard"); |
21 | const QString SETTINGS_GEOMETRY_WINDOW_DOCK_AREA ("geometryWIndowDockArea"); | |
22 | const QString SETTINGS_GEOMETRY_WINDOW_DOCK_GEOMETRY ("geometryWindowGeometry"); | |
21 | 23 | const QString SETTINGS_GROUP_MAIN_WINDOW ("MainWindow"); // Capitalize both M and W since this is a group string |
22 | 24 | const QString SETTINGS_HELP_POS ("helpPos"); |
23 | 25 | const QString SETTINGS_HELP_SIZE ("helpSize"); |
26 | const QString SETTINGS_HIGHLIGHT_OPACITY ("highlightOpacity"); | |
24 | 27 | const QString SETTINGS_LOCALE_COUNTRY ("country"); |
25 | 28 | const QString SETTINGS_LOCALE_LANGUAGE ("language"); |
26 | 29 | const QString SETTINGS_MAIN_TITLE_BAR_FORMAT ("titleBarFormat"); |
30 | const QString SETTINGS_MAXIMUM_GRID_LINES ("maximumGridLines"); | |
27 | 31 | const QString SETTINGS_POS ("pos"); |
28 | 32 | const QString SETTINGS_RECENT_FILE_LIST ("recentFileList"); |
29 | 33 | const QString SETTINGS_SIZE ("size"); |
56 | 60 | const QString SETTINGS_GROUP_GENERAL ("GeneralEngauge"); // "General" group name is reserved for ungrouped settings |
57 | 61 | |
58 | 62 | // Import group |
63 | const QString SETTINGS_GROUP_IMPORT ("Import"); | |
64 | const QString SETTINGS_IMPORT_CROPPING ("Cropping"); | |
59 | 65 | const QString SETTINGS_IMPORT_PDF_RESOLUTION ("PdfResolution"); |
60 | const QString SETTINGS_GROUP_IMPORT ("Import"); | |
61 | 66 | |
62 | 67 | // Export group |
63 | 68 | const QString SETTINGS_EXPORT_CURVE_NAMES_NOT_EXPORTED ("curveNamesNotExported"); |
74 | 79 | const QString SETTINGS_EXPORT_X_LABEL ("xLabel"); |
75 | 80 | const QString SETTINGS_GROUP_EXPORT ("Export"); |
76 | 81 | |
77 | // Pdf group | |
78 | const QString SETTINGS_PDF_POS ("pos"); | |
79 | const QString SETTINGS_GROUP_PDF ("Pdf"); | |
82 | // Dialogs for import cropping group | |
83 | const QString SETTINGS_GROUP_IMPORT_CROPPING ("ImportCropping"); | |
84 | const QString SETTINGS_IMPORT_CROPPING_POS ("pos"); |
38 | 38 | extern const QString SETTINGS_EXPORT_X_LABEL; |
39 | 39 | extern const QString SETTINGS_GENERAL_CURSOR_SIZE; |
40 | 40 | extern const QString SETTINGS_GENERAL_EXTRA_PRECISION; |
41 | extern const QString SETTINGS_GEOMETRY_WINDOW_DOCK_AREA; | |
42 | extern const QString SETTINGS_GEOMETRY_WINDOW_DOCK_GEOMETRY; | |
41 | 43 | extern const QString SETTINGS_GROUP_CURVE_AXES; |
42 | 44 | extern const QString SETTINGS_GROUP_CURVE_GRAPH; |
43 | 45 | extern const QString SETTINGS_GROUP_CURVE_GRAPH_PLACEHOLDER; |
45 | 47 | extern const QString SETTINGS_GROUP_EXPORT; |
46 | 48 | extern const QString SETTINGS_GROUP_GENERAL; |
47 | 49 | extern const QString SETTINGS_GROUP_IMPORT; |
50 | extern const QString SETTINGS_GROUP_IMPORT_CROPPING; | |
48 | 51 | extern const QString SETTINGS_GROUP_MAIN_WINDOW; |
49 | extern const QString SETTINGS_GROUP_PDF; | |
50 | 52 | extern const QString SETTINGS_HELP_POS; |
51 | 53 | extern const QString SETTINGS_HELP_SIZE; |
54 | extern const QString SETTINGS_HIGHLIGHT_OPACITY; | |
55 | extern const QString SETTINGS_IMPORT_CROPPING; | |
56 | extern const QString SETTINGS_IMPORT_CROPPING_POS; | |
52 | 57 | extern const QString SETTINGS_IMPORT_PDF_RESOLUTION; |
53 | 58 | extern const QString SETTINGS_LOCALE_COUNTRY; |
54 | 59 | extern const QString SETTINGS_LOCALE_LANGUAGE; |
55 | 60 | extern const QString SETTINGS_MAIN_TITLE_BAR_FORMAT; |
56 | extern const QString SETTINGS_PDF_POS; | |
61 | extern const QString SETTINGS_MAXIMUM_GRID_LINES; | |
57 | 62 | extern const QString SETTINGS_POS; |
58 | 63 | extern const QString SETTINGS_RECENT_FILE_LIST; |
59 | 64 | extern const QString SETTINGS_SIZE; |
22 | 22 | const QString NO_REGRESSION_OPEN_FILE; |
23 | 23 | const bool NO_GNUPLOT_LOG_FILES = false; |
24 | 24 | const bool NO_REGRESSION_IMPORT = false; |
25 | const bool NO_RESET = false; | |
25 | 26 | const bool DEBUG_FLAG = false; |
26 | 27 | const QStringList NO_LOAD_STARTUP_FILES; |
27 | 28 | |
32 | 33 | MainWindow w (NO_ERROR_REPORT_LOG_FILE, |
33 | 34 | NO_REGRESSION_OPEN_FILE, |
34 | 35 | NO_GNUPLOT_LOG_FILES, |
36 | NO_RESET, | |
35 | 37 | NO_REGRESSION_IMPORT, |
36 | 38 | NO_LOAD_STARTUP_FILES); |
37 | 39 | w.show (); |
21 | 21 | const QString NO_REGRESSION_OPEN_FILE; |
22 | 22 | const bool NO_GNUPLOT_LOG_FILES = false; |
23 | 23 | const bool NO_REGRESSION_IMPORT = false; |
24 | const bool NO_RESET = false; | |
24 | 25 | const bool DEBUG_FLAG = false; |
25 | 26 | const QStringList NO_LOAD_STARTUP_FILES; |
26 | 27 | |
31 | 32 | MainWindow w (NO_ERROR_REPORT_LOG_FILE, |
32 | 33 | NO_REGRESSION_OPEN_FILE, |
33 | 34 | NO_GNUPLOT_LOG_FILES, |
35 | NO_RESET, | |
34 | 36 | NO_REGRESSION_IMPORT, |
35 | 37 | NO_LOAD_STARTUP_FILES); |
36 | 38 | w.show (); |
22 | 22 | const QString NO_REGRESSION_OPEN_FILE; |
23 | 23 | const bool NO_GNUPLOT_LOG_FILES = false; |
24 | 24 | const bool NO_REGRESSION_IMPORT = false; |
25 | const bool NO_RESET = false; | |
25 | 26 | const bool DEBUG_FLAG = false; |
26 | 27 | const QStringList NO_LOAD_STARTUP_FILES; |
27 | 28 | |
32 | 33 | MainWindow w (NO_ERROR_REPORT_LOG_FILE, |
33 | 34 | NO_REGRESSION_OPEN_FILE, |
34 | 35 | NO_GNUPLOT_LOG_FILES, |
36 | NO_RESET, | |
35 | 37 | NO_REGRESSION_IMPORT, |
36 | 38 | NO_LOAD_STARTUP_FILES); |
37 | 39 | w.show (); |
29 | 29 | const QString NO_REGRESSION_OPEN_FILE; |
30 | 30 | const bool NO_GNUPLOT_LOG_FILES = false; |
31 | 31 | const bool NO_REGRESSION_IMPORT = false; |
32 | const bool NO_RESET = false; | |
32 | 33 | const bool DEBUG_FLAG = false; |
33 | 34 | const QStringList NO_LOAD_STARTUP_FILES; |
34 | 35 | |
40 | 41 | NO_REGRESSION_OPEN_FILE, |
41 | 42 | NO_GNUPLOT_LOG_FILES, |
42 | 43 | NO_REGRESSION_IMPORT, |
44 | NO_RESET, | |
43 | 45 | NO_LOAD_STARTUP_FILES); |
44 | 46 | w.show (); |
45 | 47 | } |
33 | 33 | const QString NO_REGRESSION_OPEN_FILE; |
34 | 34 | const bool NO_GNUPLOT_LOG_FILES = false; |
35 | 35 | const bool NO_REGRESSION_IMPORT = false; |
36 | const bool NO_RESET = false; | |
36 | 37 | const bool DEBUG_FLAG = false; |
37 | 38 | const QStringList NO_LOAD_STARTUP_FILES; |
38 | 39 | |
44 | 45 | NO_REGRESSION_OPEN_FILE, |
45 | 46 | NO_GNUPLOT_LOG_FILES, |
46 | 47 | NO_REGRESSION_IMPORT, |
48 | NO_RESET, | |
47 | 49 | NO_LOAD_STARTUP_FILES); |
48 | 50 | m.show (); |
49 | 51 | } |
25 | 25 | const QString NO_REGRESSION_OPEN_FILE; |
26 | 26 | const bool NO_GNUPLOT_LOG_FILES = false; |
27 | 27 | const bool NO_REGRESSION_IMPORT = false; |
28 | const bool NO_RESET = false; | |
28 | 29 | const bool DEBUG_FLAG = false; |
29 | 30 | const QStringList NO_LOAD_STARTUP_FILES; |
30 | 31 | |
36 | 37 | NO_REGRESSION_OPEN_FILE, |
37 | 38 | NO_GNUPLOT_LOG_FILES, |
38 | 39 | NO_REGRESSION_IMPORT, |
40 | NO_RESET, | |
39 | 41 | NO_LOAD_STARTUP_FILES); |
40 | 42 | w.show (); |
41 | 43 | } |
35 | 35 | const QString NO_REGRESSION_OPEN_FILE; |
36 | 36 | const bool NO_GNUPLOT_LOG_FILES = false; |
37 | 37 | const bool NO_REGRESSION_IMPORT = false; |
38 | const bool NO_RESET = false; | |
38 | 39 | const bool DEBUG_FLAG = false; |
39 | 40 | const QStringList NO_LOAD_STARTUP_FILES; |
40 | 41 | |
46 | 47 | NO_REGRESSION_OPEN_FILE, |
47 | 48 | NO_GNUPLOT_LOG_FILES, |
48 | 49 | NO_REGRESSION_IMPORT, |
50 | NO_RESET, | |
49 | 51 | NO_LOAD_STARTUP_FILES); |
50 | 52 | w.show (); |
51 | 53 | } |
23 | 23 | const QString NO_REGRESSION_OPEN_FILE; |
24 | 24 | const bool NO_GNUPLOT_LOG_FILES = false; |
25 | 25 | const bool NO_REGRESSION_IMPORT = false; |
26 | const bool NO_RESET = false; | |
26 | 27 | const bool DEBUG_FLAG = false; |
27 | 28 | const QStringList NO_LOAD_STARTUP_FILES; |
28 | 29 | |
34 | 35 | NO_REGRESSION_OPEN_FILE, |
35 | 36 | NO_GNUPLOT_LOG_FILES, |
36 | 37 | NO_REGRESSION_IMPORT, |
38 | NO_RESET, | |
37 | 39 | NO_LOAD_STARTUP_FILES); |
38 | 40 | w.show (); |
39 | 41 | } |
28 | 28 | { |
29 | 29 | } |
30 | 30 | |
31 | Transformation::Transformation (const Transformation &other) : | |
32 | m_transformIsDefined (other.transformIsDefined()), | |
33 | m_transform (other.transformMatrix()) | |
34 | { | |
35 | setModelCoords (other.modelCoords(), | |
36 | other.modelMainWindow()); | |
37 | } | |
38 | ||
31 | 39 | Transformation &Transformation::operator=(const Transformation &other) |
32 | 40 | { |
33 | 41 | m_transformIsDefined = other.transformIsDefined(); |
34 | 42 | m_transform = other.transformMatrix (); |
43 | setModelCoords (other.modelCoords(), | |
44 | other.modelMainWindow()); | |
35 | 45 | |
36 | 46 | return *this; |
37 | 47 | } |
243 | 253 | return m_modelCoords; |
244 | 254 | } |
245 | 255 | |
256 | MainWindowModel Transformation::modelMainWindow() const | |
257 | { | |
258 | return m_modelMainWindow; | |
259 | } | |
260 | ||
246 | 261 | ostringstream &operator<<(ostringstream &strOuter, |
247 | 262 | const Transformation &transformation) |
248 | 263 | { |
34 | 34 | public: |
35 | 35 | /// Default constructor. This is marked as undefined until the proper number of axis points are added |
36 | 36 | Transformation(); |
37 | ||
38 | /// Copy constructor | |
39 | Transformation (const Transformation &other); | |
37 | 40 | |
38 | 41 | /// Assignment operator. |
39 | 42 | Transformation &operator=(const Transformation &other); |
80 | 83 | |
81 | 84 | /// Get method for DocumentModelCoords |
82 | 85 | DocumentModelCoords modelCoords() const; |
86 | ||
87 | /// Get method for MainWindowModel | |
88 | MainWindowModel modelMainWindow() const; | |
83 | 89 | |
84 | 90 | /// Debugging method that supports print method of this class and printStream method of some other class(es) |
85 | 91 | void printStream (QString indentation, |
26 | 26 | // Normally we would need to call QGraphicsView::mouseMoveEvent at this point so that the mouse move event could be handled, |
27 | 27 | // but this is unwanted since: |
28 | 28 | // 1) Everywhere, except the pdf import preview, there is nothing to drag |
29 | // 2) Dragging of PdfFrameHandle objects in the pdf import preview is handled indirectly by PdfFrame | |
29 | // 2) Dragging of PdfFrameHandle objects in the pdf import preview is handled indirectly by PdfCropping | |
30 | 30 | QGraphicsView::mouseMoveEvent (event); |
31 | 31 | } |
32 | 32 |
13 | 13 | # qmake "CONFIG+=debug jpeg2000" |
14 | 14 | # 2) Add 'pdf' to the qmake command line to include support for PDF input files. Requires |
15 | 15 | # 1) previous installation of the poppler-qt5 development package |
16 | # 2) POPPLER_INCLUDE environment variable pointing to directory containing Document.h | |
16 | # 2) POPPLER_INCLUDE environment variable pointing to directory containing poppler-qt5.h | |
17 | 17 | # 3) POPPLER_LIB environment variable pointing to directory containing libpoppler-qt5.so |
18 | 18 | # Sample command lines |
19 | 19 | # qmake CONFIG+=pdf |
67 | 67 | Cmd/CmdCut.h \ |
68 | 68 | Cmd/CmdDelete.h \ |
69 | 69 | Cmd/CmdEditPointAxis.h \ |
70 | Cmd/CmdEditPointGraph.h \ | |
70 | 71 | Cmd/CmdFactory.h \ |
71 | 72 | Cmd/CmdMediator.h \ |
72 | 73 | Cmd/CmdMoveBy.h \ |
140 | 141 | DigitizeState/DigitizeStateSegment.h \ |
141 | 142 | DigitizeState/DigitizeStateSelect.h \ |
142 | 143 | Dlg/DlgAbout.h \ |
143 | Dlg/DlgEditPoint.h \ | |
144 | Dlg/DlgEditPointAxis.h \ | |
145 | Dlg/DlgEditPointGraph.h \ | |
146 | Dlg/DlgEditPointGraphLineEdit.h \ | |
144 | 147 | Dlg/DlgErrorReport.h \ |
145 | 148 | Dlg/DlgFilterCommand.h \ |
146 | 149 | Dlg/DlgFilterThread.h \ |
147 | 150 | Dlg/DlgFilterWorker.h \ |
148 | 151 | Dlg/DlgImportAdvanced.h \ |
152 | Dlg/DlgImportCroppingNonPdf.h \ | |
149 | 153 | Dlg/DlgRequiresTransform.h \ |
150 | 154 | Dlg/DlgSettingsAbstractBase.h \ |
151 | 155 | Dlg/DlgSettingsAxesChecker.h \ |
222 | 226 | Format/FormatDegreesMinutesSecondsNonPolarTheta.h \ |
223 | 227 | Format/FormatDegreesMinutesSecondsPolarTheta.h \ |
224 | 228 | Callback/functor.h \ |
229 | Geometry/GeometryModel.h \ | |
230 | Geometry/GeometryStrategyAbstractBase.h \ | |
231 | Geometry/GeometryStrategyContext.h \ | |
232 | Geometry/GeometryStrategyFunctionSmooth.h \ | |
233 | Geometry/GeometryStrategyFunctionStraight.h \ | |
234 | Geometry/GeometryStrategyRelationSmooth.h \ | |
235 | Geometry/GeometryStrategyRelationStraight.h \ | |
236 | Geometry/GeometryWindow.h \ | |
225 | 237 | Ghosts/GhostEllipse.h \ |
226 | 238 | Ghosts/GhostPath.h \ |
227 | 239 | Ghosts/GhostPolygon.h \ |
228 | 240 | Ghosts/Ghosts.h \ |
229 | 241 | Graphics/GraphicsArcItem.h \ |
242 | Graphics/GraphicsItemsExtractor.h \ | |
230 | 243 | Graphics/GraphicsItemType.h \ |
231 | 244 | Graphics/GraphicsLinesForCurve.h \ |
232 | 245 | Graphics/GraphicsLinesForCurves.h \ |
243 | 256 | Grid/GridInitializer.h \ |
244 | 257 | Grid/GridLine.h \ |
245 | 258 | Grid/GridLineFactory.h \ |
259 | Grid/GridLineLimiter.h \ | |
246 | 260 | Grid/GridLines.h \ |
247 | 261 | Grid/GridLineStyle.h \ |
248 | 262 | Grid/GridRemoval.h \ |
249 | 263 | Help/HelpBrowser.h \ |
250 | 264 | Help/HelpWindow.h \ |
265 | Import/ImportCropping.h \ | |
266 | Import/ImportCroppingUtilBase.h \ | |
267 | Import/ImportCroppingUtilNonPdf.h \ | |
251 | 268 | Line/LineStyle.h \ |
252 | 269 | Load/LoadFileInfo.h \ |
253 | 270 | Load/LoadImageFromUrl.h \ |
260 | 277 | Mime/MimePoints.h \ |
261 | 278 | util/mmsubs.h \ |
262 | 279 | Network/NetworkClient.h \ |
280 | NonPdf/NonPdf.h \ | |
281 | NonPdf/NonPdfCropping.h \ | |
282 | NonPdf/NonPdfFrameHandle.h \ | |
263 | 283 | Ordinal/OrdinalGenerator.h \ |
264 | 284 | Ordinal/OrdinalToGraphicsPoint.h \ |
265 | 285 | Pdf/PdfResolution.h \ |
362 | 382 | Cmd/CmdCut.cpp \ |
363 | 383 | Cmd/CmdDelete.cpp \ |
364 | 384 | Cmd/CmdEditPointAxis.cpp \ |
385 | Cmd/CmdEditPointGraph.cpp \ | |
365 | 386 | Cmd/CmdFactory.cpp \ |
366 | 387 | Cmd/CmdMediator.cpp \ |
367 | 388 | Cmd/CmdMoveBy.cpp \ |
432 | 453 | DigitizeState/DigitizeStateSegment.cpp \ |
433 | 454 | DigitizeState/DigitizeStateSelect.cpp \ |
434 | 455 | Dlg/DlgAbout.cpp \ |
435 | Dlg/DlgEditPoint.cpp \ | |
456 | Dlg/DlgEditPointAxis.cpp \ | |
457 | Dlg/DlgEditPointGraph.cpp \ | |
458 | Dlg/DlgEditPointGraphLineEdit.cpp \ | |
436 | 459 | Dlg/DlgErrorReport.cpp \ |
437 | 460 | Dlg/DlgFilterCommand.cpp \ |
438 | 461 | Dlg/DlgFilterThread.cpp \ |
439 | 462 | Dlg/DlgFilterWorker.cpp \ |
440 | 463 | Dlg/DlgImportAdvanced.cpp \ |
464 | Dlg/DlgImportCroppingNonPdf.cpp \ | |
441 | 465 | Dlg/DlgRequiresTransform.cpp \ |
442 | 466 | Dlg/DlgSettingsAbstractBase.cpp \ |
443 | 467 | Dlg/DlgSettingsAxesChecker.cpp \ |
507 | 531 | Format/FormatDegreesMinutesSecondsBase.cpp \ |
508 | 532 | Format/FormatDegreesMinutesSecondsNonPolarTheta.cpp \ |
509 | 533 | Format/FormatDegreesMinutesSecondsPolarTheta.cpp \ |
534 | Geometry/GeometryModel.cpp \ | |
535 | Geometry/GeometryStrategyAbstractBase.cpp \ | |
536 | Geometry/GeometryStrategyContext.cpp \ | |
537 | Geometry/GeometryStrategyFunctionSmooth.cpp \ | |
538 | Geometry/GeometryStrategyFunctionStraight.cpp \ | |
539 | Geometry/GeometryStrategyRelationSmooth.cpp \ | |
540 | Geometry/GeometryStrategyRelationStraight.cpp \ | |
541 | Geometry/GeometryWindow.cpp \ | |
510 | 542 | Ghosts/GhostEllipse.cpp \ |
511 | 543 | Ghosts/GhostPath.cpp \ |
512 | 544 | Ghosts/GhostPolygon.cpp \ |
513 | 545 | Ghosts/Ghosts.cpp \ |
514 | 546 | Graphics/GraphicsArcItem.cpp \ |
547 | Graphics/GraphicsItemsExtractor.cpp \ | |
515 | 548 | Graphics/GraphicsLinesForCurve.cpp \ |
516 | 549 | Graphics/GraphicsLinesForCurves.cpp \ |
517 | 550 | Graphics/GraphicsPoint.cpp \ |
527 | 560 | Grid/GridInitializer.cpp \ |
528 | 561 | Grid/GridLine.cpp \ |
529 | 562 | Grid/GridLineFactory.cpp \ |
563 | Grid/GridLineLimiter.cpp \ | |
530 | 564 | Grid/GridLines.cpp \ |
531 | 565 | Grid/GridRemoval.cpp \ |
532 | 566 | Help/HelpBrowser.cpp \ |
533 | 567 | Help/HelpWindow.cpp \ |
568 | Import/ImportCroppingUtilBase.cpp \ | |
569 | Import/ImportCroppingUtilNonPdf.cpp \ | |
534 | 570 | Line/LineStyle.cpp \ |
535 | 571 | Load/LoadFileInfo.cpp \ |
536 | 572 | Load/LoadImageFromUrl.cpp \ |
542 | 578 | Mime/MimePoints.cpp \ |
543 | 579 | util/mmsubs.cpp \ |
544 | 580 | Network/NetworkClient.cpp \ |
581 | NonPdf/NonPdf.cpp \ | |
582 | NonPdf/NonPdfCropping.cpp \ | |
583 | NonPdf/NonPdfFrameHandle.cpp \ | |
545 | 584 | Ordinal/OrdinalGenerator.cpp \ |
546 | 585 | Pdf/PdfResolution.cpp \ |
547 | 586 | Point/Point.cpp \ |
628 | 667 | FileCmd \ |
629 | 668 | Filter \ |
630 | 669 | Format \ |
670 | Geometry \ | |
631 | 671 | Ghosts \ |
632 | 672 | Graphics \ |
633 | 673 | Grid \ |
634 | 674 | Help \ |
635 | 675 | img \ |
676 | Import \ | |
636 | 677 | include \ |
637 | 678 | Line \ |
638 | 679 | Load \ |
640 | 681 | main \ |
641 | 682 | Mime \ |
642 | 683 | Network \ |
684 | NonPdf \ | |
643 | 685 | Ordinal \ |
644 | 686 | Pdf \ |
645 | 687 | Plot \ |
720 | 762 | DEFINES += "ENGAUGE_PDF" |
721 | 763 | INCLUDEPATH += $$(POPPLER_INCLUDE) |
722 | 764 | LIBS += -L$$(POPPLER_LIB) -lpoppler -lpoppler-qt5 |
723 | HEADERS += Dlg/DlgPdfFrame.h \ | |
765 | HEADERS += Dlg/DlgImportCroppingPdf.h \ | |
766 | Import/ImportCroppingUtilPdf.h \ | |
724 | 767 | Pdf/Pdf.h \ |
725 | Pdf/PdfFrame.h \ | |
768 | Pdf/PdfCropping.h \ | |
726 | 769 | Pdf/PdfFrameHandle.h |
727 | SOURCES += Dlg/DlgPdfFrame.cpp \ | |
770 | SOURCES += Dlg/DlgImportCroppingPdf.cpp \ | |
771 | Import/ImportCroppingUtilPdf.cpp \ | |
728 | 772 | Pdf/Pdf.cpp \ |
729 | Pdf/PdfFrame.cpp \ | |
773 | Pdf/PdfCropping.cpp \ | |
730 | 774 | Pdf/PdfFrameHandle.cpp |
731 | 775 | |
732 | 776 | } else { |
51 | 51 | #include "ExportImageForRegression.h" |
52 | 52 | #include "ExportToFile.h" |
53 | 53 | #include "FileCmdScript.h" |
54 | #include "GeometryWindow.h" | |
54 | 55 | #include "Ghosts.h" |
56 | #include "GraphicsItemsExtractor.h" | |
55 | 57 | #include "GraphicsItemType.h" |
56 | 58 | #include "GraphicsScene.h" |
57 | 59 | #include "GraphicsView.h" |
58 | 60 | #include "GridLineFactory.h" |
61 | #include "GridLineLimiter.h" | |
59 | 62 | #include "HelpWindow.h" |
60 | 63 | #ifdef ENGAUGE_JPEG2000 |
61 | 64 | #include "Jpeg2000.h" |
66 | 69 | #include "MainTitleBarFormat.h" |
67 | 70 | #include "MainWindow.h" |
68 | 71 | #include "NetworkClient.h" |
72 | #include "NonPdf.h" | |
69 | 73 | #ifdef ENGAUGE_PDF |
70 | 74 | #include "Pdf.h" |
71 | 75 | #endif // ENGAUGE_PDF |
123 | 127 | const QString &fileCmdScriptFile, |
124 | 128 | bool isRegressionTest, |
125 | 129 | bool isGnuplot, |
130 | bool isReset, | |
126 | 131 | QStringList loadStartupFiles, |
127 | 132 | QWidget *parent) : |
128 | 133 | QMainWindow(parent), |
165 | 170 | createStatusBar (); |
166 | 171 | createMenus (); |
167 | 172 | createToolBars (); |
173 | createDockableWidgets (); | |
168 | 174 | createHelpWindow (); |
169 | 175 | createTutorial (); |
170 | 176 | createScene (); |
178 | 184 | createZoomMap (); |
179 | 185 | updateControls (); |
180 | 186 | |
181 | settingsRead (); // This changes the current directory when not regression testing | |
187 | settingsRead (isReset); // This changes the current directory when not regression testing | |
182 | 188 | setCurrentFile (""); |
183 | 189 | setUnifiedTitleAndToolBarOnMac(true); |
184 | 190 | |
209 | 215 | { |
210 | 216 | } |
211 | 217 | |
218 | void MainWindow::addDockWindow (QDockWidget *dockWidget, | |
219 | QSettings &settings, | |
220 | const QString &settingsTokenArea, | |
221 | const QString &settingsTokenGeometry, | |
222 | Qt::DockWidgetArea dockWidgetArea) | |
223 | { | |
224 | // Checklist guide is docked or undocked. Default is docked so it does not get overlooked by the user (which | |
225 | // can happen if it opens elsewhere). The user may not know it can be undocked, but at least can resize or | |
226 | // hide it if he/she needs more room for the main window. | |
227 | const bool DOCKED_EQUALS_NOT_FLOATING = false; | |
228 | Qt::DockWidgetArea area = (Qt::DockWidgetArea) settings.value (settingsTokenArea, | |
229 | Qt::NoDockWidgetArea).toInt(); | |
230 | ||
231 | if (area == Qt::NoDockWidgetArea) { | |
232 | ||
233 | addDockWidget (dockWidgetArea, | |
234 | dockWidget); // Add on the right to prevent error message, then immediately make undocked | |
235 | dockWidget->setFloating(DOCKED_EQUALS_NOT_FLOATING); | |
236 | if (settings.contains (settingsTokenGeometry)) { | |
237 | dockWidget->restoreGeometry (settings.value (settingsTokenGeometry).toByteArray()); | |
238 | } | |
239 | ||
240 | } else { | |
241 | ||
242 | addDockWidget (area, | |
243 | dockWidget); | |
244 | ||
245 | } | |
246 | } | |
247 | ||
212 | 248 | void MainWindow::applyZoomFactorAfterLoad() |
213 | 249 | { |
214 | 250 | ZoomFactor zoomFactor; |
662 | 698 | m_actionViewChecklistGuide = new QAction (tr ("Checklist Guide Toolbar"), this); |
663 | 699 | m_actionViewChecklistGuide->setCheckable (true); |
664 | 700 | m_actionViewChecklistGuide->setChecked (false); |
665 | m_actionViewChecklistGuide->setStatusTip (tr ("Show or hide the checklist guide toolbar.")); | |
666 | m_actionViewChecklistGuide->setWhatsThis (tr ("View Checklist Guide ToolBar\n\n" | |
667 | "Show or hide the checklist guide toolbar")); | |
701 | m_actionViewChecklistGuide->setStatusTip (tr ("Show or hide the checklist guide.")); | |
702 | m_actionViewChecklistGuide->setWhatsThis (tr ("View Checklist Guide\n\n" | |
703 | "Show or hide the checklist guide")); | |
668 | 704 | connect (m_actionViewChecklistGuide, SIGNAL (changed ()), this, SLOT (slotViewToolBarChecklistGuide())); |
705 | ||
706 | m_actionViewGeometryWindow = new QAction (tr ("Geometry Window"), this); | |
707 | m_actionViewGeometryWindow->setCheckable (true); | |
708 | m_actionViewGeometryWindow->setChecked (false); | |
709 | m_actionViewGeometryWindow->setStatusTip (tr ("Show or hide the geometry window.")); | |
710 | m_actionViewGeometryWindow->setWhatsThis (tr ("View Geometry Window\n\n" | |
711 | "Show or hide the geometry window")); | |
712 | connect (m_actionViewGeometryWindow, SIGNAL (changed ()), this, SLOT (slotViewToolBarGeometryWindow())); | |
669 | 713 | |
670 | 714 | m_actionViewDigitize = new QAction (tr ("Digitizing Tools Toolbar"), this); |
671 | 715 | m_actionViewDigitize->setCheckable (true); |
877 | 921 | LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::createCommandStackShadow"; |
878 | 922 | |
879 | 923 | m_cmdStackShadow = new CmdStackShadow; |
924 | } | |
925 | ||
926 | void MainWindow::createDockableWidgets () | |
927 | { | |
928 | LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::createDockableWidgets"; | |
929 | ||
930 | // Checklist guide starts out hidden. It will be positioned in settingsRead | |
931 | m_dockChecklistGuide = new ChecklistGuide (this); | |
932 | connect (m_dockChecklistGuide, SIGNAL (signalChecklistClosed()), this, SLOT (slotChecklistClosed())); | |
933 | ||
934 | // Geometry window starts out hidden since there is nothing to show initially. It will be positioned in settingsRead | |
935 | m_dockGeometryWindow = new GeometryWindow (this); | |
936 | connect (m_dockGeometryWindow, SIGNAL (signalGeometryWindowClosed()), this, SLOT (slotGeometryWindowClosed())); | |
880 | 937 | } |
881 | 938 | |
882 | 939 | void MainWindow::createHelpWindow () |
970 | 1027 | m_menuView->addAction (m_actionViewBackground); |
971 | 1028 | m_menuView->addAction (m_actionViewDigitize); |
972 | 1029 | m_menuView->addAction (m_actionViewChecklistGuide); |
1030 | m_menuView->addAction (m_actionViewGeometryWindow); | |
973 | 1031 | m_menuView->addAction (m_actionViewSettingsViews); |
974 | 1032 | m_menuView->addAction (m_actionViewCoordSystem); |
975 | 1033 | m_menuView->insertSeparator (m_actionViewToolTips); |
1225 | 1283 | m_toolCoordSystem->addWidget (m_btnShowAll); |
1226 | 1284 | m_toolCoordSystem->addWidget (m_btnPrintAll); |
1227 | 1285 | addToolBar (m_toolCoordSystem); |
1228 | ||
1229 | // Checklist guide starts out hidden. It will be positioned in settingsRead | |
1230 | m_dockChecklistGuide = new ChecklistGuide (this); | |
1231 | connect (m_dockChecklistGuide, SIGNAL (signalChecklistClosed()), this, SLOT (slotChecklistClosed())); | |
1232 | 1286 | } |
1233 | 1287 | |
1234 | 1288 | void MainWindow::createTutorial () |
1370 | 1424 | transformation (), |
1371 | 1425 | str); |
1372 | 1426 | |
1373 | // Update checklist guide status | |
1374 | m_isDocumentExported = true; // Set for next line and for all checklist guide updates after this | |
1375 | m_dockChecklistGuide->update (*m_cmdMediator, | |
1376 | m_isDocumentExported); | |
1427 | updateChecklistGuide (); | |
1377 | 1428 | |
1378 | 1429 | } else { |
1379 | 1430 | |
1426 | 1477 | PdfReturn pdfReturn = pdf.load (fileName, |
1427 | 1478 | image, |
1428 | 1479 | m_modelMainWindow.pdfResolution(), |
1480 | m_modelMainWindow.importCropping(), | |
1429 | 1481 | m_isErrorReportRegressionTest); |
1430 | 1482 | if (pdfReturn == PDF_RETURN_CANCELED) { |
1431 | 1483 | |
1439 | 1491 | #endif // ENGAUGE_PDF |
1440 | 1492 | |
1441 | 1493 | if (!loaded) { |
1442 | loaded = image.load (fileName); | |
1494 | NonPdf nonPdf; | |
1495 | NonPdfReturn nonPdfReturn = nonPdf.load (fileName, | |
1496 | image, | |
1497 | m_modelMainWindow.importCropping(), | |
1498 | m_isErrorReportRegressionTest); | |
1499 | if (nonPdfReturn == NON_PDF_RETURN_CANCELED) { | |
1500 | ||
1501 | // User canceled so exit immediately | |
1502 | return; | |
1503 | ||
1504 | } | |
1505 | ||
1506 | loaded = (nonPdfReturn == NON_PDF_RETURN_SUCCESS); | |
1443 | 1507 | } |
1444 | 1508 | |
1445 | 1509 | if (!loaded) { |
2297 | 2361 | curveSelected); |
2298 | 2362 | } |
2299 | 2363 | |
2300 | void MainWindow::settingsRead () | |
2364 | void MainWindow::settingsRead (bool isReset) | |
2301 | 2365 | { |
2302 | 2366 | QSettings settings (SETTINGS_ENGAUGE, SETTINGS_DIGITIZER); |
2367 | ||
2368 | if (isReset) { | |
2369 | // Delete all settings. Default values are specified, later, for each settings as it is loaded | |
2370 | settings.clear (); | |
2371 | } | |
2303 | 2372 | |
2304 | 2373 | settingsReadEnvironment (settings); |
2305 | 2374 | settingsReadMainWindow (settings); |
2324 | 2393 | QPoint (200, 200)).toPoint ()); |
2325 | 2394 | |
2326 | 2395 | // Help window geometry |
2396 | #ifndef OSX_RELEASE | |
2327 | 2397 | QSize helpSize = settings.value (SETTINGS_HELP_SIZE, |
2328 | 2398 | QSize (900, 600)).toSize(); |
2329 | #ifndef OSX_RELEASE | |
2330 | 2399 | m_helpWindow->resize (helpSize); |
2331 | 2400 | if (settings.contains (SETTINGS_HELP_POS)) { |
2332 | 2401 | QPoint helpPos = settings.value (SETTINGS_HELP_POS).toPoint(); |
2380 | 2449 | m_actionStatusTemporary->setChecked (statusBarMode == STATUS_BAR_MODE_TEMPORARY); |
2381 | 2450 | m_actionStatusAlways->setChecked (statusBarMode == STATUS_BAR_MODE_ALWAYS); |
2382 | 2451 | |
2383 | // Checklist guide is docked or undocked. Default is docked so it does not get overlooked by the user (which | |
2384 | // can happen if it opens elsewhere). The user may not know it can be undocked, but at least can resize or | |
2385 | // hide it if he/she needs more room for the main window. | |
2386 | const bool DOCKED_EQUALS_NOT_FLOATING = false; | |
2387 | Qt::DockWidgetArea area = (Qt::DockWidgetArea) settings.value (SETTINGS_CHECKLIST_GUIDE_DOCK_AREA, | |
2388 | Qt::NoDockWidgetArea).toInt(); | |
2389 | ||
2390 | if (area == Qt::NoDockWidgetArea) { | |
2391 | ||
2392 | addDockWidget (Qt::RightDockWidgetArea, | |
2393 | m_dockChecklistGuide); // Add on the right to prevent error message, then immediately make undocked | |
2394 | m_dockChecklistGuide->setFloating(DOCKED_EQUALS_NOT_FLOATING); | |
2395 | if (settings.contains (SETTINGS_CHECKLIST_GUIDE_DOCK_GEOMETRY)) { | |
2396 | m_dockChecklistGuide->restoreGeometry (settings.value (SETTINGS_CHECKLIST_GUIDE_DOCK_GEOMETRY).toByteArray()); | |
2397 | } | |
2398 | ||
2399 | } else { | |
2400 | ||
2401 | addDockWidget (area, | |
2402 | m_dockChecklistGuide); | |
2403 | ||
2404 | } | |
2452 | addDockWindow (m_dockChecklistGuide, | |
2453 | settings, | |
2454 | SETTINGS_CHECKLIST_GUIDE_DOCK_AREA, | |
2455 | SETTINGS_CHECKLIST_GUIDE_DOCK_GEOMETRY, | |
2456 | Qt::RightDockWidgetArea); | |
2457 | addDockWindow (m_dockGeometryWindow, | |
2458 | settings, | |
2459 | SETTINGS_GEOMETRY_WINDOW_DOCK_AREA, | |
2460 | SETTINGS_GEOMETRY_WINDOW_DOCK_GEOMETRY, | |
2461 | Qt::RightDockWidgetArea); | |
2405 | 2462 | |
2406 | 2463 | // Main window settings. Preference for initial zoom factor is 100%, rather than fill mode, for issue #25. Some or all |
2407 | 2464 | // settings are saved to the application AND saved to m_modelMainWindow for use in DlgSettingsMainWindow. Note that |
2424 | 2481 | QVariant (MAIN_TITLE_BAR_FORMAT_PATH)).toInt()); |
2425 | 2482 | m_modelMainWindow.setPdfResolution (settings.value (SETTINGS_IMPORT_PDF_RESOLUTION, |
2426 | 2483 | QVariant (DEFAULT_IMPORT_PDF_RESOLUTION)).toInt ()); |
2484 | m_modelMainWindow.setImportCropping ((ImportCropping) settings.value (SETTINGS_IMPORT_CROPPING, | |
2485 | QVariant (DEFAULT_IMPORT_CROPPING)).toInt ()); | |
2486 | m_modelMainWindow.setMaximumGridLines (settings.value (SETTINGS_MAXIMUM_GRID_LINES, | |
2487 | QVariant (DEFAULT_MAXIMUM_GRID_LINES)).toInt ()); | |
2488 | m_modelMainWindow.setHighlightOpacity (settings.value (SETTINGS_HIGHLIGHT_OPACITY, | |
2489 | QVariant (DEFAULT_HIGHLIGHT_OPACITY)).toDouble ()); | |
2427 | 2490 | |
2428 | 2491 | updateSettingsMainWindow(); |
2429 | 2492 | |
2455 | 2518 | settings.setValue (SETTINGS_CHECKLIST_GUIDE_DOCK_AREA, dockWidgetArea (m_dockChecklistGuide)); |
2456 | 2519 | |
2457 | 2520 | } |
2521 | if (m_dockGeometryWindow->isFloating()) { | |
2522 | ||
2523 | settings.setValue (SETTINGS_GEOMETRY_WINDOW_DOCK_AREA, Qt::NoDockWidgetArea); | |
2524 | settings.setValue (SETTINGS_GEOMETRY_WINDOW_DOCK_GEOMETRY, m_dockGeometryWindow->saveGeometry ()); | |
2525 | ||
2526 | } else { | |
2527 | ||
2528 | settings.setValue (SETTINGS_GEOMETRY_WINDOW_DOCK_AREA, dockWidgetArea (m_dockGeometryWindow)); | |
2529 | ||
2530 | } | |
2531 | settings.setValue (SETTINGS_BACKGROUND_IMAGE, m_cmbBackground->currentData().toInt()); | |
2458 | 2532 | settings.setValue (SETTINGS_CHECKLIST_GUIDE_WIZARD, m_actionHelpChecklistGuideWizard->isChecked ()); |
2533 | settings.setValue (SETTINGS_HIGHLIGHT_OPACITY, m_modelMainWindow.highlightOpacity()); | |
2534 | settings.setValue (SETTINGS_IMPORT_CROPPING, m_modelMainWindow.importCropping()); | |
2459 | 2535 | settings.setValue (SETTINGS_IMPORT_PDF_RESOLUTION, m_modelMainWindow.pdfResolution ()); |
2460 | 2536 | settings.setValue (SETTINGS_LOCALE_LANGUAGE, m_modelMainWindow.locale().language()); |
2461 | 2537 | settings.setValue (SETTINGS_LOCALE_COUNTRY, m_modelMainWindow.locale().country()); |
2538 | settings.setValue (SETTINGS_MAIN_TITLE_BAR_FORMAT, m_modelMainWindow.mainTitleBarFormat()); | |
2539 | settings.setValue (SETTINGS_MAXIMUM_GRID_LINES, m_modelMainWindow.maximumGridLines()); | |
2462 | 2540 | settings.setValue (SETTINGS_VIEW_BACKGROUND_TOOLBAR, m_actionViewBackground->isChecked()); |
2463 | settings.setValue (SETTINGS_BACKGROUND_IMAGE, m_cmbBackground->currentData().toInt()); | |
2464 | 2541 | settings.setValue (SETTINGS_VIEW_DIGITIZE_TOOLBAR, m_actionViewDigitize->isChecked ()); |
2465 | 2542 | settings.setValue (SETTINGS_VIEW_STATUS_BAR, m_statusBar->statusBarMode ()); |
2466 | 2543 | settings.setValue (SETTINGS_VIEW_SETTINGS_VIEWS_TOOLBAR, m_actionViewSettingsViews->isChecked ()); |
2469 | 2546 | settings.setValue (SETTINGS_ZOOM_CONTROL, m_modelMainWindow.zoomControl()); |
2470 | 2547 | settings.setValue (SETTINGS_ZOOM_FACTOR, currentZoomFactor ()); |
2471 | 2548 | settings.setValue (SETTINGS_ZOOM_FACTOR_INITIAL, m_modelMainWindow.zoomFactorInitial()); |
2472 | settings.setValue (SETTINGS_MAIN_TITLE_BAR_FORMAT, m_modelMainWindow.mainTitleBarFormat()); | |
2473 | 2549 | settings.endGroup (); |
2474 | 2550 | } |
2475 | 2551 | |
2724 | 2800 | |
2725 | 2801 | updateViewedCurves(); |
2726 | 2802 | updateViewsOfSettings(); |
2727 | } | |
2728 | ||
2729 | void MainWindow::slotContextMenuEvent (QString pointIdentifier) | |
2730 | { | |
2731 | LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotContextMenuEvent point=" << pointIdentifier.toLatin1 ().data (); | |
2732 | ||
2733 | m_digitizeStateContext->handleContextMenuEvent (m_cmdMediator, | |
2734 | pointIdentifier); | |
2803 | updateGeometryWindow(); | |
2804 | } | |
2805 | ||
2806 | void MainWindow::slotContextMenuEventAxis (QString pointIdentifier) | |
2807 | { | |
2808 | LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotContextMenuEventAxis point=" << pointIdentifier.toLatin1 ().data (); | |
2809 | ||
2810 | m_digitizeStateContext->handleContextMenuEventAxis (m_cmdMediator, | |
2811 | pointIdentifier); | |
2812 | } | |
2813 | ||
2814 | void MainWindow::slotContextMenuEventGraph (QStringList pointIdentifiers) | |
2815 | { | |
2816 | LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotContextMenuEventGraph point=" << pointIdentifiers.join(",").toLatin1 ().data (); | |
2817 | ||
2818 | m_digitizeStateContext->handleContextMenuEventGraph (m_cmdMediator, | |
2819 | pointIdentifiers); | |
2735 | 2820 | } |
2736 | 2821 | |
2737 | 2822 | void MainWindow::slotDigitizeAxis () |
2804 | 2889 | { |
2805 | 2890 | LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotEditCopy"; |
2806 | 2891 | |
2892 | GraphicsItemsExtractor graphicsItemsExtractor; | |
2893 | const QList<QGraphicsItem*> &items = m_scene->selectedItems(); | |
2894 | QStringList pointIdentifiers = graphicsItemsExtractor.selectedPointIdentifiers (items); | |
2895 | ||
2807 | 2896 | CmdCopy *cmd = new CmdCopy (*this, |
2808 | 2897 | m_cmdMediator->document(), |
2809 | m_scene->selectedPointIdentifiers ()); | |
2898 | pointIdentifiers); | |
2810 | 2899 | m_digitizeStateContext->appendNewCmd (m_cmdMediator, |
2811 | 2900 | cmd); |
2812 | 2901 | } |
2815 | 2904 | { |
2816 | 2905 | LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotEditCut"; |
2817 | 2906 | |
2907 | GraphicsItemsExtractor graphicsItemsExtractor; | |
2908 | const QList<QGraphicsItem*> &items = m_scene->selectedItems(); | |
2909 | QStringList pointIdentifiers = graphicsItemsExtractor.selectedPointIdentifiers (items); | |
2910 | ||
2818 | 2911 | CmdCut *cmd = new CmdCut (*this, |
2819 | 2912 | m_cmdMediator->document(), |
2820 | m_scene->selectedPointIdentifiers ()); | |
2913 | pointIdentifiers); | |
2821 | 2914 | m_digitizeStateContext->appendNewCmd (m_cmdMediator, |
2822 | 2915 | cmd); |
2823 | 2916 | } |
2826 | 2919 | { |
2827 | 2920 | LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotEditDelete"; |
2828 | 2921 | |
2922 | GraphicsItemsExtractor graphicsItemsExtractor; | |
2923 | const QList<QGraphicsItem*> &items = m_scene->selectedItems(); | |
2924 | QStringList pointIdentifiers = graphicsItemsExtractor.selectedPointIdentifiers (items); | |
2925 | ||
2829 | 2926 | CmdDelete *cmd = new CmdDelete (*this, |
2830 | 2927 | m_cmdMediator->document(), |
2831 | m_scene->selectedPointIdentifiers ()); | |
2928 | pointIdentifiers); | |
2832 | 2929 | m_digitizeStateContext->appendNewCmd (m_cmdMediator, |
2833 | 2930 | cmd); |
2834 | 2931 | } |
2886 | 2983 | |
2887 | 2984 | // Remove scroll bars if they exist |
2888 | 2985 | m_scene->setSceneRect (QRectF (0, 0, 1, 1)); |
2986 | ||
2987 | // Remove stale data from geometry window | |
2988 | m_dockGeometryWindow->clear (); | |
2889 | 2989 | |
2890 | 2990 | // Deallocate Document |
2891 | 2991 | delete m_cmdMediator; |
3083 | 3183 | return false; |
3084 | 3184 | } |
3085 | 3185 | |
3186 | void MainWindow::slotGeometryWindowClosed() | |
3187 | { | |
3188 | LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotGeometryWindowClosed"; | |
3189 | ||
3190 | m_actionViewGeometryWindow->setChecked (false); | |
3191 | } | |
3192 | ||
3086 | 3193 | void MainWindow::slotHelpAbout() |
3087 | 3194 | { |
3088 | 3195 | LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotHelpAbout"; |
3109 | 3216 | m_digitizeStateContext->handleKeyPress (m_cmdMediator, |
3110 | 3217 | key, |
3111 | 3218 | atLeastOneSelectedItem); |
3112 | } | |
3113 | ||
3114 | void MainWindow::slotLeave () | |
3115 | { | |
3116 | LOG4CPP_DEBUG_S ((*mainCat)) << "MainWindow::slotLeave"; | |
3117 | ||
3118 | m_digitizeStateContext->handleLeave (m_cmdMediator); | |
3119 | 3219 | } |
3120 | 3220 | |
3121 | 3221 | void MainWindow::slotLoadStartupFiles () |
3238 | 3338 | completeText += QString (" \"%1\"").arg (text); |
3239 | 3339 | } |
3240 | 3340 | m_actionEditRedo->setText (completeText); |
3241 | } | |
3242 | ||
3243 | void MainWindow::slotSetOverrideCursor (QCursor cursor) | |
3244 | { | |
3245 | LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotSetOverrideCursor"; | |
3246 | ||
3247 | m_digitizeStateContext->handleSetOverrideCursor (m_cmdMediator, | |
3248 | cursor); | |
3249 | 3341 | } |
3250 | 3342 | |
3251 | 3343 | void MainWindow::slotSettingsAxesChecker () |
3531 | 3623 | m_toolDigitize->show(); |
3532 | 3624 | } else { |
3533 | 3625 | m_toolDigitize->hide(); |
3626 | } | |
3627 | } | |
3628 | ||
3629 | void MainWindow::slotViewToolBarGeometryWindow () | |
3630 | { | |
3631 | LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewToolBarGeometryWindow"; | |
3632 | ||
3633 | if (m_actionViewGeometryWindow->isChecked ()) { | |
3634 | m_dockGeometryWindow->show(); | |
3635 | } else { | |
3636 | m_dockGeometryWindow->hide(); | |
3534 | 3637 | } |
3535 | 3638 | } |
3536 | 3639 | |
3933 | 4036 | // status bar are up to date. Point coordinates in Document are also updated |
3934 | 4037 | updateAfterCommandStatusBarCoords (); |
3935 | 4038 | |
3936 | // Update the QGraphicsScene with the populated Curves. This requires the points in the Document to be already updated | |
3937 | // by updateAfterCommandStatusBarCoords | |
3938 | m_scene->updateAfterCommand (*m_cmdMediator); | |
4039 | updateHighlightOpacity (); | |
4040 | ||
4041 | // Update graphics. Effectively, these steps do very little (just needed for highlight opacity) | |
4042 | m_digitizeStateContext->updateAfterPointAddition (); // May or may not be needed due to point addition | |
3939 | 4043 | |
3940 | 4044 | updateControls (); |
3941 | ||
3942 | // Update checklist guide status | |
3943 | m_dockChecklistGuide->update (*m_cmdMediator, | |
3944 | m_isDocumentExported); | |
4045 | updateChecklistGuide (); | |
4046 | updateGeometryWindow(); | |
3945 | 4047 | |
3946 | 4048 | // Final action at the end of a redo/undo is to checkpoint the Document and GraphicsScene to log files |
3947 | 4049 | // so proper state can be verified |
3948 | 4050 | writeCheckpointToLogFile (); |
4051 | ||
4052 | // Since focus may have drifted over to Geometry Window or some other control we se focus on the GraphicsView | |
4053 | // so the cursor is appropriate for the current state (otherwise it often ends up as default arrow) | |
4054 | m_view->setFocus (); | |
3949 | 4055 | } |
3950 | 4056 | |
3951 | 4057 | void MainWindow::updateAfterCommandStatusBarCoords () |
3953 | 4059 | LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateAfterCommandStatusBarCoords"; |
3954 | 4060 | |
3955 | 4061 | // For some reason, mapFromGlobal(QCursor::pos) differs from event->pos by a little bit. We must compensate for |
3956 | // this so cursor coordinates in status bar match the DlgEditPoint inputs initially. After the mouse moves | |
4062 | // this so cursor coordinates in status bar match the DlgEditPointAxis inputs initially. After the mouse moves | |
3957 | 4063 | // the problem disappears since event->pos is available and QCursor::pos is no longer needed |
3958 | 4064 | const QPoint HACK_SO_GRAPH_COORDINATE_MATCHES_INPUT (1, 1); |
3959 | 4065 | |
3998 | 4104 | LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateAfterMouseRelease"; |
3999 | 4105 | |
4000 | 4106 | updateControls (); |
4107 | } | |
4108 | ||
4109 | void MainWindow::updateChecklistGuide () | |
4110 | { | |
4111 | LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateChecklistGuide"; | |
4112 | ||
4113 | m_isDocumentExported = true; // Set for next line and for all checklist guide updates after this | |
4114 | m_dockChecklistGuide->update (*m_cmdMediator, | |
4115 | m_isDocumentExported); | |
4001 | 4116 | } |
4002 | 4117 | |
4003 | 4118 | void MainWindow::updateControls () |
4132 | 4247 | } |
4133 | 4248 | } |
4134 | 4249 | |
4250 | void MainWindow::updateGeometryWindow () | |
4251 | { | |
4252 | LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateGeometryWindow"; | |
4253 | ||
4254 | // Update geometry window | |
4255 | m_dockGeometryWindow->update (*m_cmdMediator, | |
4256 | m_modelMainWindow, | |
4257 | m_cmbCurve->currentText (), | |
4258 | m_transformation); | |
4259 | } | |
4260 | ||
4135 | 4261 | void MainWindow::updateGraphicsLinesToMatchGraphicsPoints() |
4136 | 4262 | { |
4137 | 4263 | LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateGraphicsLinesToMatchGraphicsPoints"; |
4149 | 4275 | |
4150 | 4276 | // Create new grid lines |
4151 | 4277 | GridLineFactory factory (*m_scene, |
4152 | m_cmdMediator->document().modelCoords(), | |
4153 | m_transformation); | |
4278 | m_cmdMediator->document().modelCoords()); | |
4154 | 4279 | factory.createGridLinesForEvenlySpacedGrid (m_cmdMediator->document().modelGridDisplay(), |
4280 | m_modelMainWindow, | |
4281 | m_transformation, | |
4155 | 4282 | m_gridLines); |
4156 | 4283 | |
4157 | 4284 | m_gridLines.setVisible (m_actionViewGridLines->isChecked()); |
4285 | } | |
4286 | ||
4287 | void MainWindow::updateHighlightOpacity () | |
4288 | { | |
4289 | if (m_cmdMediator != 0) { | |
4290 | ||
4291 | // Update the QGraphicsScene with the populated Curves. This requires the points in the Document to be already updated | |
4292 | // by updateAfterCommandStatusBarCoords | |
4293 | m_scene->updateAfterCommand (*m_cmdMediator, | |
4294 | m_modelMainWindow.highlightOpacity(), | |
4295 | m_dockGeometryWindow); | |
4296 | } | |
4158 | 4297 | } |
4159 | 4298 | |
4160 | 4299 | void MainWindow::updateRecentFileList() |
4297 | 4436 | |
4298 | 4437 | } |
4299 | 4438 | |
4439 | if ((m_scene != 0) && | |
4440 | (m_cmdMediator != 0)) { | |
4441 | m_scene->updateCurveStyles(m_cmdMediator->document().modelCurveStyles()); | |
4442 | } | |
4443 | ||
4444 | updateHighlightOpacity(); | |
4300 | 4445 | updateWindowTitle(); |
4301 | 4446 | } |
4302 | 4447 |
52 | 52 | class DocumentModelSegments; |
53 | 53 | class ExportToFile; |
54 | 54 | class FileCmdScript; |
55 | class GeometryWindow; | |
55 | 56 | class Ghosts; |
56 | 57 | class GraphicsScene; |
57 | 58 | class GraphicsView; |
88 | 89 | /// \param fileCmdScriptFile Optional file command script file to be read at startup. Empty if unused. Incompatible with errorReportFile |
89 | 90 | /// \param isRegressionTest True if errorReportFile or fileCmdScript is for regression testing, in which case it is executed and the program exits |
90 | 91 | /// \param isGnuplot True if diagnostic gnuplot files are generated for math-intense sections of the code. Used for development and debugging |
92 | /// \param isReset True to reset all settings that would otherwise be restored from the previous execution of Engauge | |
91 | 93 | /// \param loadStartupFiles Zero or more Engauge document files to load at startup. A separate instance of Engauge is created for each file |
92 | 94 | /// \param parent Optional parent widget for this widget |
93 | 95 | MainWindow(const QString &errorReportFile, |
94 | 96 | const QString &fileCmdScriptFile, |
95 | 97 | bool isRegressionTest, |
96 | 98 | bool isGnuplot, |
99 | bool isReset, | |
97 | 100 | QStringList loadStartupFiles, |
98 | 101 | QWidget *parent = 0); |
99 | 102 | ~MainWindow(); |
231 | 234 | void slotCmbBackground(int); |
232 | 235 | void slotCmbCoordSystem(int); |
233 | 236 | void slotCmbCurve(int); |
234 | void slotContextMenuEvent (QString); | |
237 | void slotContextMenuEventAxis (QString); | |
238 | void slotContextMenuEventGraph (QStringList); | |
235 | 239 | void slotDigitizeAxis (); |
236 | 240 | void slotDigitizeColorPicker (); |
237 | 241 | void slotDigitizeCurve (); |
258 | 262 | void slotFilePrint(); |
259 | 263 | bool slotFileSave(); /// Slot method that is sometimes called directly with return value expected |
260 | 264 | bool slotFileSaveAs(); /// Slot method that is sometimes called directly with return value expected |
265 | void slotGeometryWindowClosed(); | |
261 | 266 | void slotHelpAbout(); |
262 | 267 | void slotHelpTutorial(); |
263 | 268 | void slotKeyPress (Qt::Key, bool); |
264 | void slotLeave (); | |
265 | 269 | void slotLoadStartupFiles (); |
266 | 270 | void slotMouseMove (QPointF); |
267 | 271 | void slotMousePress (QPointF); |
269 | 273 | void slotRecentFileAction (); |
270 | 274 | void slotRecentFileClear (); |
271 | 275 | void slotRedoTextChanged (const QString &); |
272 | void slotSetOverrideCursor (QCursor); | |
273 | 276 | void slotSettingsAxesChecker (); |
274 | 277 | void slotSettingsColorFilter (); |
275 | 278 | void slotSettingsCoords (); |
294 | 297 | void slotViewToolBarChecklistGuide (); |
295 | 298 | void slotViewToolBarCoordSystem (); |
296 | 299 | void slotViewToolBarDigitize (); |
300 | void slotViewToolBarGeometryWindow (); | |
297 | 301 | void slotViewToolBarSettingsViews (); |
298 | 302 | void slotViewToolTips (); |
299 | 303 | void slotViewZoom16To1 (); |
325 | 329 | IMPORT_TYPE_IMAGE_REPLACE |
326 | 330 | }; |
327 | 331 | |
332 | void addDockWindow (QDockWidget *dockWidget, | |
333 | QSettings &settings, | |
334 | const QString &settingsTokenArea, | |
335 | const QString &settingsTokenGeometry, | |
336 | Qt::DockWidgetArea dockWidgetArea); | |
328 | 337 | void applyZoomFactorAfterLoad(); |
329 | 338 | virtual void closeEvent(QCloseEvent *event); |
330 | 339 | void createActions(); |
336 | 345 | void createActionsView (); |
337 | 346 | void createCentralWidget (); |
338 | 347 | void createCommandStackShadow (); |
348 | void createDockableWidgets (); | |
339 | 349 | void createHelpWindow (); |
340 | 350 | void createIcons(); |
341 | 351 | void createLoadImageFromUrl (); |
393 | 403 | void setCurrentPathFromFile (const QString &fileName); |
394 | 404 | void setPixmap (const QString &curveSelected, |
395 | 405 | const QPixmap &pixmap); |
396 | void settingsRead (); | |
406 | void settingsRead (bool isReset); | |
397 | 407 | void settingsReadEnvironment (QSettings &settings); |
398 | 408 | void settingsReadMainWindow (QSettings &settings); |
399 | 409 | void settingsWrite (); |
406 | 416 | void startRegressionTestErrorReport (const QString ®ressionInputFile); |
407 | 417 | void startRegressionTestFileCmdScript (); |
408 | 418 | void updateAfterCommandStatusBarCoords (); |
419 | void updateChecklistGuide (); | |
409 | 420 | void updateControls (); // Update the widgets (typically in terms of show/hide state) depending on the application state. |
421 | void updateGeometryWindow (); | |
410 | 422 | void updateGridLines(); |
423 | void updateHighlightOpacity(); | |
411 | 424 | void updateRecentFileList(); |
412 | 425 | void updateSettingsMainWindow(); |
413 | 426 | void updateTransformationAndItsDependencies(); |
462 | 475 | QAction *m_actionViewChecklistGuide; |
463 | 476 | QAction *m_actionViewCoordSystem; |
464 | 477 | QAction *m_actionViewDigitize; |
478 | QAction *m_actionViewGeometryWindow; | |
465 | 479 | QAction *m_actionViewSettingsViews; |
466 | 480 | QAction *m_actionViewToolTips; |
467 | 481 | QAction *m_actionViewGridLines; |
535 | 549 | ViewSegmentFilter *m_viewSegmentFilter; |
536 | 550 | QToolBar *m_toolSettingsViews; |
537 | 551 | ChecklistGuide *m_dockChecklistGuide; |
552 | GeometryWindow *m_dockGeometryWindow; | |
538 | 553 | |
539 | 554 | QComboBox *m_cmbCoordSystem; |
540 | 555 | QPushButton *m_btnPrintAll; |
5 | 5 | |
6 | 6 | #include "CmdMediator.h" |
7 | 7 | #include "DocumentSerialize.h" |
8 | #include "GraphicsPoint.h" | |
9 | #include "GridLineLimiter.h" | |
10 | #include "ImportCroppingUtilBase.h" | |
8 | 11 | #include "Logger.h" |
9 | 12 | #include "MainWindowModel.h" |
10 | 13 | #include "PdfResolution.h" |
23 | 26 | m_zoomControl (ZOOM_CONTROL_MENU_WHEEL_PLUSMINUS), |
24 | 27 | m_zoomFactorInitial (DEFAULT_ZOOM_FACTOR_INITIAL), |
25 | 28 | m_mainTitleBarFormat (MAIN_TITLE_BAR_FORMAT_PATH), |
26 | m_pdfResolution (DEFAULT_IMPORT_PDF_RESOLUTION) | |
29 | m_pdfResolution (DEFAULT_IMPORT_PDF_RESOLUTION), | |
30 | m_importCropping (DEFAULT_IMPORT_CROPPING), | |
31 | m_maximumGridLines (DEFAULT_MAXIMUM_GRID_LINES), | |
32 | m_highlightOpacity (DEFAULT_HIGHLIGHT_OPACITY) | |
27 | 33 | { |
28 | 34 | // Locale member variable m_locale is initialized to default locale when default constructor is called |
29 | 35 | } |
33 | 39 | m_zoomControl (other.zoomControl()), |
34 | 40 | m_zoomFactorInitial (other.zoomFactorInitial()), |
35 | 41 | m_mainTitleBarFormat (other.mainTitleBarFormat()), |
36 | m_pdfResolution (other.pdfResolution()) | |
42 | m_pdfResolution (other.pdfResolution()), | |
43 | m_importCropping (other.importCropping()), | |
44 | m_maximumGridLines (other.maximumGridLines()), | |
45 | m_highlightOpacity (other.highlightOpacity()) | |
37 | 46 | { |
38 | 47 | } |
39 | 48 | |
44 | 53 | m_zoomFactorInitial = other.zoomFactorInitial(); |
45 | 54 | m_mainTitleBarFormat = other.mainTitleBarFormat(); |
46 | 55 | m_pdfResolution = other.pdfResolution(); |
56 | m_importCropping = other.importCropping(); | |
57 | m_maximumGridLines = other.maximumGridLines(); | |
58 | m_highlightOpacity = other.highlightOpacity(); | |
47 | 59 | |
48 | 60 | return *this; |
61 | } | |
62 | ||
63 | double MainWindowModel::highlightOpacity() const | |
64 | { | |
65 | return m_highlightOpacity; | |
66 | } | |
67 | ||
68 | ImportCropping MainWindowModel::importCropping() const | |
69 | { | |
70 | return m_importCropping; | |
49 | 71 | } |
50 | 72 | |
51 | 73 | void MainWindowModel::loadXml(QXmlStreamReader &reader) |
79 | 101 | return m_mainTitleBarFormat; |
80 | 102 | } |
81 | 103 | |
104 | int MainWindowModel::maximumGridLines() const | |
105 | { | |
106 | return m_maximumGridLines; | |
107 | } | |
108 | ||
82 | 109 | int MainWindowModel::pdfResolution() const |
83 | 110 | { |
84 | 111 | return m_pdfResolution; |
98 | 125 | "NoPath" : |
99 | 126 | "Path") << "\n"; |
100 | 127 | str << indentation << "pdfResolution=" << m_pdfResolution << "\n"; |
128 | str << indentation << "importCropping=" << ImportCroppingUtilBase::importCroppingToString (m_importCropping).toLatin1().data() << "\n"; | |
129 | str << indentation << "maximumGridLines=" << m_maximumGridLines << "\n"; | |
130 | str << indentation << "highlightOpacity=" << m_highlightOpacity << "\n"; | |
101 | 131 | } |
102 | 132 | |
103 | 133 | void MainWindowModel::saveXml(QXmlStreamWriter &writer) const |
106 | 136 | |
107 | 137 | writer.writeStartElement(DOCUMENT_SERIALIZE_MAIN_WINDOW); |
108 | 138 | writer.writeEndElement(); |
139 | } | |
140 | ||
141 | void MainWindowModel::setHighlightOpacity(double highlightOpacity) | |
142 | { | |
143 | m_highlightOpacity = highlightOpacity; | |
144 | } | |
145 | ||
146 | void MainWindowModel::setImportCropping (ImportCropping importCropping) | |
147 | { | |
148 | m_importCropping = importCropping; | |
109 | 149 | } |
110 | 150 | |
111 | 151 | void MainWindowModel::setLocale (QLocale::Language language, |
129 | 169 | m_mainTitleBarFormat = mainTitleBarFormat; |
130 | 170 | } |
131 | 171 | |
172 | void MainWindowModel::setMaximumGridLines(int maximumGridLines) | |
173 | { | |
174 | m_maximumGridLines = maximumGridLines; | |
175 | } | |
176 | ||
132 | 177 | void MainWindowModel::setPdfResolution(int resolution) |
133 | 178 | { |
134 | 179 | m_pdfResolution = resolution; |
7 | 7 | #define MAIN_WINDOW_MODEL_H |
8 | 8 | |
9 | 9 | #include "DocumentModelAbstractBase.h" |
10 | #include "ImportCropping.h" | |
10 | 11 | #include "MainTitleBarFormat.h" |
11 | 12 | #include <QLocale> |
12 | 13 | #include <QString> |
33 | 34 | |
34 | 35 | virtual void loadXml(QXmlStreamReader &reader); |
35 | 36 | |
37 | /// Get method for highlight opacity | |
38 | double highlightOpacity() const; | |
39 | ||
40 | /// Get method for import cropping | |
41 | ImportCropping importCropping () const; | |
42 | ||
36 | 43 | /// Get method for locale |
37 | 44 | QLocale locale() const; |
38 | 45 | |
39 | 46 | /// Get method for MainWindow titlebar filename format |
40 | 47 | MainTitleBarFormat mainTitleBarFormat () const; |
48 | ||
49 | /// Maximum number of grid lines | |
50 | int maximumGridLines () const; | |
41 | 51 | |
42 | 52 | /// Get method for resolution of imported PDF files, in dots per inch |
43 | 53 | int pdfResolution () const; |
48 | 58 | |
49 | 59 | virtual void saveXml(QXmlStreamWriter &writer) const; |
50 | 60 | |
61 | /// Set method for highlight opacity | |
62 | void setHighlightOpacity (double highlightOpacity); | |
63 | ||
51 | 64 | /// Set method for locale given attributes |
52 | 65 | void setLocale (QLocale::Language language, |
53 | 66 | QLocale::Country country); |
55 | 68 | /// Set method for locale given locale object |
56 | 69 | void setLocale (const QLocale &locale); |
57 | 70 | |
71 | /// Set method for import cropping | |
72 | void setImportCropping (ImportCropping importCropping); | |
73 | ||
58 | 74 | /// Set method for MainWindow titlebar filename format |
59 | 75 | void setMainTitleBarFormat (MainTitleBarFormat mainTitleBarFormat); |
76 | ||
77 | /// Set method for maximum number of grid lines | |
78 | void setMaximumGridLines (int maximumGridLines); | |
60 | 79 | |
61 | 80 | /// Set method for resolution of imported PDF files, in dots per inch |
62 | 81 | void setPdfResolution (int resolution); |
80 | 99 | ZoomFactorInitial m_zoomFactorInitial; |
81 | 100 | MainTitleBarFormat m_mainTitleBarFormat; |
82 | 101 | int m_pdfResolution; |
102 | ImportCropping m_importCropping; | |
103 | int m_maximumGridLines; | |
104 | double m_highlightOpacity; | |
83 | 105 | |
84 | 106 | }; |
85 | 107 |
24 | 24 | const QString CMD_GNUPLOT ("gnuplot"); |
25 | 25 | const QString CMD_HELP ("help"); |
26 | 26 | const QString CMD_REGRESSION ("regression"); |
27 | const QString CMD_RESET ("reset"); | |
27 | 28 | const QString DASH ("-"); |
28 | 29 | const QString DASH_DEBUG ("-" + CMD_DEBUG); |
29 | 30 | const QString DASH_ERROR_REPORT ("-" + CMD_ERROR_REPORT); |
31 | 32 | const QString DASH_GNUPLOT ("-" + CMD_GNUPLOT); |
32 | 33 | const QString DASH_HELP ("-" + CMD_HELP); |
33 | 34 | const QString DASH_REGRESSION ("-" + CMD_REGRESSION); |
35 | const QString DASH_RESET ("-" + CMD_RESET); | |
34 | 36 | const QString ENGAUGE_LOG_FILE ("engauge.log"); |
35 | 37 | |
36 | 38 | // Prototypes |
41 | 43 | void parseCmdLine (int argc, |
42 | 44 | char **argv, |
43 | 45 | bool &isDebug, |
46 | bool &isReset, | |
44 | 47 | QString &errorReportFile, |
45 | 48 | QString &fileCmdScriptFile, |
46 | 49 | bool &isErrorReportRegressionTest, |
58 | 61 | { |
59 | 62 | QString pathAndFile; // Return empty value in OSX which is unused |
60 | 63 | |
61 | #ifndef OSX_RELEASE | |
64 | #if !defined(OSX_RELEASE) && !defined(WIN_RELEASE) | |
62 | 65 | QProcessEnvironment env; |
63 | 66 | |
64 | 67 | // Make multiple attempts until a directory is found where the log file can be written |
104 | 107 | TranslatorContainer translatorContainer (app); // Must exist until execution terminates |
105 | 108 | |
106 | 109 | // Command line |
107 | bool isDebug, isGnuplot, isErrorReportRegressionTest; | |
110 | bool isDebug, isReset, isGnuplot, isErrorReportRegressionTest; | |
108 | 111 | QString errorReportFile, fileCmdScriptFile; |
109 | 112 | QStringList loadStartupFiles; |
110 | 113 | parseCmdLine (argc, |
111 | 114 | argv, |
112 | 115 | isDebug, |
116 | isReset, | |
113 | 117 | errorReportFile, |
114 | 118 | fileCmdScriptFile, |
115 | 119 | isErrorReportRegressionTest, |
127 | 131 | fileCmdScriptFile, |
128 | 132 | isErrorReportRegressionTest, |
129 | 133 | isGnuplot, |
134 | isReset, | |
130 | 135 | loadStartupFiles); |
131 | 136 | w.show(); |
132 | 137 | |
137 | 142 | void parseCmdLine (int argc, |
138 | 143 | char **argv, |
139 | 144 | bool &isDebug, |
145 | bool &isReset, | |
140 | 146 | QString &errorReportFile, |
141 | 147 | QString &fileCmdScriptFile, |
142 | 148 | bool &isErrorReportRegressionTest, |
152 | 158 | |
153 | 159 | // Defaults |
154 | 160 | isDebug = false; |
161 | isReset = false; | |
155 | 162 | errorReportFile = ""; |
156 | 163 | fileCmdScriptFile = ""; |
157 | 164 | isErrorReportRegressionTest = false; |
179 | 186 | showUsage = true; // User requested help |
180 | 187 | } else if (strcmp (argv [i], DASH_REGRESSION.toLatin1().data()) == 0) { |
181 | 188 | isErrorReportRegressionTest = true; |
189 | } else if (strcmp (argv [i], DASH_RESET.toLatin1().data()) == 0) { | |
190 | isReset = true; | |
182 | 191 | } else if (strncmp (argv [i], DASH.toLatin1().data(), 1) == 0) { |
183 | 192 | showUsage = true; // User entered an unrecognized token |
184 | 193 | } else { |
202 | 211 | << "[" << DASH_GNUPLOT.toLatin1().data() << "] " |
203 | 212 | << "[" << DASH_HELP.toLatin1().data() << "] " |
204 | 213 | << "[" << DASH_REGRESSION.toLatin1().data() << "] " |
214 | << "[" << DASH_RESET.toLatin1().data () << "] " | |
205 | 215 | << "[<load_file1>] [<load_file2>] ..." << endl |
206 | 216 | << " " << DASH_DEBUG.leftJustified(COLUMN_WIDTH, ' ').toLatin1().data() |
207 | 217 | << QObject::tr ("Enables extra debug information. Used for debugging").toLatin1().data() << endl |
215 | 225 | << QObject::tr ("Show this help information").toLatin1().data() << endl |
216 | 226 | << " " << DASH_REGRESSION.leftJustified(COLUMN_WIDTH, ' ').toLatin1().data() |
217 | 227 | << QObject::tr ("Executes the error report file or file command script. Used for regression testing").toLatin1().data() << endl |
228 | << " " << DASH_RESET.leftJustified(COLUMN_WIDTH, ' ').toLatin1().data() | |
229 | << QObject::tr ("Removes all stored settings, including window positions. Used when windows start up offscreen").toLatin1().data() << endl | |
218 | 230 | << " " << QString ("<load file> ").leftJustified(COLUMN_WIDTH, ' ').toLatin1().data() |
219 | 231 | << QObject::tr ("File(s) to be imported or opened at startup").toLatin1().data() << endl; |
220 | 232 |
5 | 5 | |
6 | 6 | #include "Version.h" |
7 | 7 | |
8 | const char *VERSION_NUMBER = "8.3"; | |
8 | const char *VERSION_NUMBER = "9.0"; | |
9 | 9 | |
10 | 10 | QString engaugeWindowTitle() |
11 | 11 | { |
6 | 6 | #include "ZValues.h" |
7 | 7 | |
8 | 8 | const int Z_VALUE_BACKGROUND = 0; |
9 | const int Z_VALUE_GRID_LINE = 100; | |
10 | 9 | const int Z_VALUE_CURVE = 200; |
11 | 10 | const int Z_VALUE_POINT = 300; |
12 | 11 |
0 | -errorreport ../test/cartesian_linear_linear.xml -regression | |
0 | -errorreport ../test/cartesian_linear_linear.xml -regression -reset |
0 | -errorreport ../test/cartesian_linear_log.xml -regression | |
0 | -errorreport ../test/cartesian_linear_log.xml -regression -reset |
0 | -errorreport ../test/cartesian_log_linear.xml -regression | |
0 | -errorreport ../test/cartesian_log_linear.xml -regression -reset |
0 | -errorreport ../test/extrapolate_functions_smooth.xml -regression | |
0 | -errorreport ../test/extrapolate_functions_smooth.xml -regression -reset |
0 | -errorreport ../test/extrapolate_functions_straight.xml -regression | |
0 | -errorreport ../test/extrapolate_functions_straight.xml -regression -reset |
0 | -errorreport ../test/extrapolate_relations_smooth.xml -regression | |
0 | -errorreport ../test/extrapolate_relations_smooth.xml -regression -reset |
0 | -errorreport ../test/extrapolate_relations_straight.xml -regression | |
0 | -errorreport ../test/extrapolate_relations_straight.xml -regression -reset |
0 | -errorreport ../test/floating_axes.xml -regression | |
0 | -errorreport ../test/floating_axes.xml -regression -reset |
0 | -errorreport ../test/gnuplot_format.xml -regression | |
0 | -errorreport ../test/gnuplot_format.xml -regression -reset |
0 | x,red,green,blue | |
1 | 0.1052,-4.98,-8.2267,-14.5509 | |
2 | 0.1087,-4.9347,-8.1743,-14.137 | |
3 | 0.1203,-4.7818,-7.9873,-12.9622 | |
4 | 0.1212,-4.7689,-7.9679,-12.8781 | |
5 | 0.1287,-4.666,-7.7698,-12.2725 | |
6 | 0.1354,-4.5754,-7.6279,-11.8019 | |
7 | 0.1387,-4.533,-7.5634,-11.5938 | |
8 | 0.1486,-4.4031,-7.357,-11.0357 | |
9 | 0.1505,-4.3773,-7.32,-10.9436 | |
10 | 0.1586,-4.2486,-7.1589,-10.2968 | |
11 | 0.163,-4.1791,-7.0697,-10.1802 | |
12 | 0.1686,-4.0984,-6.9525,-10.0632 | |
13 | 0.172,-4.053,-6.8815,-9.9982 | |
14 | 0.1781,-3.9727,-6.7557,-9.8769 | |
15 | 0.1786,-3.9663,-6.7461,-9.8666 | |
16 | 0.1819,-3.9235,-6.6827,-9.7918 | |
17 | 0.1886,-3.8373,-6.5479,-9.6079 | |
18 | 0.1894,-3.8269,-6.5289,-9.5855 | |
19 | 0.1932,-3.7745,-6.422,-9.482 | |
20 | 0.196,-3.7342,-6.3416,-9.4082 | |
21 | 0.1968,-3.7228,-6.3208,-9.3873 | |
22 | 0.2042,-3.6224,-6.1646,-9.1809 | |
23 | 0.206,-3.6015,-6.1352,-9.1297 | |
24 | 0.2083,-3.5764,-6.0998,-9.0639 | |
25 | 0.2117,-3.5429,-6.0523,-8.9746 | |
26 | 0.2211,-3.4622,-5.937,-8.7779 | |
27 | 0.2217,-3.4578,-5.9307,-8.7682 | |
28 | 0.2311,-3.3864,-5.8269,-8.6189 | |
29 | 0.2342,-3.3633,-5.7918,-8.57 | |
30 | 0.2388,-3.3299,-5.7388,-8.496 | |
31 | 0.2467,-3.2708,-5.6353,-8.3636 | |
32 | 0.2539,-3.2165,-5.5407,-8.2513 | |
33 | 0.2564,-3.1965,-5.5088,-8.2116 | |
34 | 0.2593,-3.1729,-5.4733,-8.1655 | |
35 | 0.2715,-3.0678,-5.3342,-7.9644 | |
36 | 0.2718,-3.0648,-5.3306,-7.9591 | |
37 | 0.2791,-2.9983,-5.2515,-7.8431 | |
38 | 0.2844,-2.9503,-5.1933,-7.7609 | |
39 | 0.2892,-2.9079,-5.1361,-7.6844 | |
40 | 0.2969,-2.8445,-5.0311,-7.5545 | |
41 | 0.3019,-2.8084,-4.9656,-7.4678 | |
42 | 0.3043,-2.7926,-4.9379,-7.4299 | |
43 | 0.3095,-2.7596,-4.8832,-7.3564 | |
44 | 0.3245,-2.672,-4.748,-7.1887 | |
45 | 0.3271,-2.6569,-4.7249,-7.1582 | |
46 | 0.3323,-2.6266,-4.6791,-7.0918 | |
47 | 0.3422,-2.5678,-4.593,-6.96 | |
48 | 0.3472,-2.5373,-4.5498,-6.9005 | |
49 | 0.3599,-2.4617,-4.4435,-6.7619 | |
50 | 0.3628,-2.4449,-4.4193,-6.7297 | |
51 | 0.37,-2.4048,-4.3599,-6.6488 | |
52 | 0.3775,-2.3645,-4.2975,-6.5637 | |
53 | 0.3927,-2.2866,-4.1617,-6.3929 | |
54 | 0.3952,-2.2745,-4.1373,-6.3655 | |
55 | 0.3958,-2.2715,-4.1311,-6.3586 | |
56 | 0.4128,-2.1873,-3.9728,-6.1673 | |
57 | 0.413,-2.1866,-3.9717,-6.1658 | |
58 | 0.4313,-2.098,-3.8597,-5.9844 | |
59 | 0.433,-2.0899,-3.8501,-5.9692 | |
60 | 0.4434,-2.0409,-3.79,-5.8811 | |
61 | 0.4558,-1.9834,-3.7091,-5.7792 | |
62 | 0.4669,-1.9328,-3.6309,-5.6848 | |
63 | 0.4713,-1.913,-3.6001,-5.6463 | |
64 | 0.4785,-1.8805,-3.5505,-5.581 | |
65 | 0.4988,-1.7933,-3.4208,-5.3911 | |
66 | 0.4991,-1.7916,-3.4184,-5.3874 | |
67 | 0.505,-1.7675,-3.3822,-5.332 | |
68 | 0.5215,-1.702,-3.2829,-5.1929 | |
69 | 0.5296,-1.6711,-3.2367,-5.1377 | |
70 | 0.5457,-1.6105,-3.148,-5.0358 | |
71 | 0.5494,-1.5965,-3.1276,-5.0112 | |
72 | 0.5626,-1.5476,-3.0549,-4.9161 | |
73 | 0.5747,-1.5034,-2.9851,-4.8213 | |
74 | 0.5889,-1.4535,-2.9041,-4.7123 | |
75 | 0.593,-1.4394,-2.8815,-4.6818 | |
76 | 0.6,-1.4159,-2.8442,-4.6313 | |
77 | 0.6279,-1.326,-2.7108,-4.4496 | |
78 | 0.6285,-1.324,-2.708,-4.4457 | |
79 | 0.6347,-1.3048,-2.6815,-4.409 | |
80 | 0.6583,-1.2312,-2.5806,-4.2679 | |
81 | 0.6667,-1.2058,-2.5427,-4.2165 | |
82 | 0.6805,-1.1643,-2.4742,-4.1297 | |
83 | 0.6888,-1.1397,-2.4322,-4.0779 | |
84 | 0.7022,-1.1007,-2.3693,-3.9965 | |
85 | 0.7192,-1.0521,-2.302,-3.8962 | |
86 | 0.7263,-1.032,-2.2757,-3.8548 | |
87 | 0.7429,-0.9852,-2.2123,-3.7597 | |
88 | 0.7496,-0.9664,-2.184,-3.7228 | |
89 | 0.7746,-0.8997,-2.0736,-3.5925 | |
90 | 0.781,-0.8836,-2.047,-3.5584 | |
91 | 0.7826,-0.8795,-2.0404,-3.5493 | |
92 | 0.8156,-0.7996,-1.9203,-3.3676 | |
93 | 0.8242,-0.7789,-1.89,-3.3276 | |
94 | 0.8255,-0.7757,-1.8853,-3.3217 | |
95 | 0.8537,-0.7067,-1.7821,-3.2023 | |
96 | 0.8649,-0.6795,-1.7413,-3.1525 | |
97 | 0.8765,-0.6517,-1.7001,-3.0983 | |
98 | 0.8893,-0.6216,-1.6557,-3.0371 | |
99 | 0.9081,-0.5787,-1.5925,-2.9489 | |
100 | 0.9274,-0.5359,-1.5298,-2.8636 | |
101 | 0.9274,-0.5359,-1.5298,-2.8636 | |
102 | 0.9539,-0.4779,-1.4438,-2.755 | |
103 | 0.9655,-0.4529,-1.4056,-2.7066 | |
104 | 0.9809,-0.4202,-1.3551,-2.6387 | |
105 | 0.9997,-0.3809,-1.295,-2.5572 | |
106 | 1.0036,-0.3729,-1.283,-2.5414 | |
107 | 1.0344,-0.3126,-1.1937,-2.4292 | |
108 | 1.0455,-0.2921,-1.1628,-2.3893 | |
109 | 1.0468,-0.2897,-1.1591,-2.3844 | |
110 | 1.0875,-0.2184,-1.0479,-2.2274 | |
111 | 1.0904,-0.2134,-1.04,-2.2165 | |
112 | 1.0939,-0.2074,-1.0305,-2.2036 | |
113 | 1.1307,-0.1423,-0.9289,-2.0704 | |
114 | 1.1422,-0.1217,-0.8982,-2.0289 | |
115 | 1.1465,-0.1141,-0.8871,-2.0135 | |
116 | 1.1714,-0.069,-0.8234,-1.9216 | |
117 | 1.1906,-0.0351,-0.7742,-1.8507 | |
118 | 1.2025,-0.0148,-0.7427,-1.8074 | |
119 | 1.2146,0.0051,-0.7105,-1.7646 | |
120 | 1.2415,0.0469,-0.642,-1.6755 | |
121 | 1.2604,0.0752,-0.5981,-1.6159 | |
122 | 1.2611,0.0762,-0.5966,-1.6137 | |
123 | 1.2924,0.1219,-0.5262,-1.5177 | |
124 | 1.3062,0.1424,-0.493,-1.4754 | |
125 | 1.3172,0.159,-0.4659,-1.4414 | |
126 | 1.3433,0.1999,-0.4022,-1.3609 | |
127 | 1.352,0.2135,-0.3821,-1.3349 | |
128 | 1.3758,0.25,-0.3301,-1.266 | |
129 | 1.3968,0.2803,-0.2864,-1.2055 | |
130 | 1.3978,0.2817,-0.2844,-1.2026 | |
131 | 1.4344,0.3328,-0.2106,-1.0951 | |
132 | 1.4462,0.3496,-0.1871,-1.0621 | |
133 | 1.4503,0.3556,-0.1789,-1.0509 | |
134 | 1.493,0.4156,-0.093,-0.9418 | |
135 | 1.4945,0.4175,-0.0901,-0.9381 | |
136 | 1.5038,0.4295,-0.0714,-0.9145 | |
137 | 1.5454,0.4818,0.0126,-0.8058 | |
138 | 1.5517,0.4901,0.025,-0.7895 | |
139 | 1.5573,0.4978,0.0362,-0.7748 | |
140 | 1.5938,0.5502,0.1073,-0.6818 | |
141 | 1.6103,0.5729,0.1381,-0.6417 | |
142 | 1.6133,0.5768,0.1437,-0.6344 | |
143 | 1.6447,0.6137,0.1996,-0.5578 | |
144 | 1.6689,0.6392,0.2422,-0.4954 | |
145 | 1.6694,0.6396,0.243,-0.4943 | |
146 | 1.6931,0.664,0.2856,-0.4338 | |
147 | 1.7254,0.6997,0.3422,-0.3584 | |
148 | 1.7301,0.7054,0.35,-0.3481 | |
149 | 1.744,0.7231,0.3725,-0.318 | |
150 | 1.7815,0.7716,0.4333,-0.2382 | |
151 | 1.7888,0.78,0.4459,-0.2221 | |
152 | 1.7975,0.7893,0.4615,-0.2022 | |
153 | 1.8375,0.8264,0.5325,-0.1044 | |
154 | 1.8484,0.8365,0.5503,-0.0782 | |
155 | 1.85,0.838,0.5527,-0.0746 | |
156 | 1.8961,0.8872,0.6236,0.0258 | |
157 | 1.9019,0.8937,0.6326,0.0376 | |
158 | 1.9112,0.9043,0.6474,0.0563 | |
159 | 1.9522,0.9507,0.7146,0.1387 | |
160 | 1.9554,0.9543,0.7197,0.1451 | |
161 | 1.9698,0.9705,0.7428,0.1743 | |
162 | 2.0089,1.0139,0.8027,0.2526 | |
163 | 2.0108,1.016,0.8056,0.2564 | |
164 | 2.031,1.0368,0.8351,0.2949 | |
165 | 2.0649,1.069,0.8853,0.3601 | |
166 | 2.0669,1.0708,0.8884,0.3641 | |
167 | 2.0922,1.0949,0.9286,0.4157 | |
168 | 2.1184,1.1221,0.9692,0.4676 | |
169 | 2.1255,1.1297,0.9794,0.4808 | |
170 | 2.1483,1.1529,1.0095,0.5211 | |
171 | 2.1745,1.1763,1.0417,0.5669 | |
172 | 2.1841,1.1843,1.054,0.5846 | |
173 | 2.2069,1.2026,1.0846,0.6275 | |
174 | 2.228,1.2195,1.1148,0.6662 | |
175 | 2.2428,1.2318,1.1367,0.6919 | |
176 | 2.2656,1.2524,1.1708,0.7303 | |
177 | 2.2866,1.2732,1.2005,0.7655 | |
178 | 2.3014,1.2883,1.2195,0.791 | |
179 | 2.3242,1.3104,1.2451,0.8316 | |
180 | 2.3426,1.3261,1.2643,0.8648 | |
181 | 2.3626,1.3419,1.2858,0.9008 | |
182 | 2.3855,1.3602,1.3135,0.9414 | |
183 | 2.3987,1.3714,1.3307,0.964 | |
184 | 2.4212,1.3911,1.3603,1.0012 | |
185 | 2.4441,1.4099,1.3896,1.038 | |
186 | 2.4547,1.4173,1.403,1.0551 | |
187 | 2.4798,1.4335,1.4348,1.0961 | |
188 | 2.4926,1.4432,1.4514,1.1169 | |
189 | 2.5108,1.4595,1.4751,1.1461 | |
190 | 2.5385,1.4865,1.5094,1.1891 | |
191 | 2.5538,1.5012,1.5268,1.2127 | |
192 | 2.5694,1.5152,1.5438,1.2371 | |
193 | 2.5997,1.5396,1.5757,1.286 | |
194 | 2.615,1.551,1.5921,1.3111 | |
195 | 2.6255,1.5584,1.6036,1.3281 | |
196 | 2.6583,1.5808,1.6419,1.3802 | |
197 | 2.6762,1.5925,1.6642,1.4075 | |
198 | 2.6841,1.5975,1.674,1.4192 | |
199 | 2.7195,1.6209,1.7165,1.4697 | |
200 | 2.7374,1.634,1.7353,1.4947 | |
201 | 2.7427,1.6381,1.7404,1.5019 | |
202 | 2.7781,1.6672,1.7745,1.5516 | |
203 | 2.7986,1.6838,1.7956,1.5809 | |
204 | 2.8013,1.6858,1.7984,1.5847 | |
205 | 2.8393,1.7128,1.8408,1.6406 | |
206 | 2.8573,1.7253,1.8617,1.6674 | |
207 | 2.8574,1.7253,1.8618,1.6675 | |
208 | 2.898,1.7546,1.907,1.7263 | |
209 | 2.916,1.7668,1.9249,1.7503 | |
210 | 2.916,1.7668,1.9249,1.7503 | |
211 | 2.9491,1.7834,1.9557,1.7903 | |
212 | 2.9592,1.7896,1.9651,1.8022 | |
213 | 2.9772,1.8016,1.9824,1.8248 | |
214 | 3.0104,1.8249,2.0156,1.8715 | |
215 | 3.0178,1.8303,2.0231,1.8823 | |
216 | 3.0358,1.8431,2.041,1.9076 | |
217 | 3.0716,1.8665,2.0763,1.953 | |
218 | 3.0765,1.8693,2.0811,1.959 | |
219 | 3.0944,1.8789,2.0989,1.9821 | |
220 | 3.1328,1.8997,2.1369,2.0363 | |
221 | 3.1351,1.9011,2.1391,2.0396 | |
222 | 3.1531,1.913,2.1568,2.0649 | |
223 | 3.1915,1.9412,2.1948,2.1145 | |
224 | 3.1938,1.9429,2.1971,2.1173 | |
225 | 3.2117,1.9559,2.2153,2.1394 | |
226 | 3.2524,1.9826,2.2551,2.1897 | |
227 | 3.2527,1.9828,2.2554,2.1901 | |
228 | 3.2729,1.9939,2.2733,2.214 | |
229 | 3.3085,2.0129,2.3049,2.2536 | |
230 | 3.3139,2.016,2.3101,2.2596 | |
231 | 3.3315,2.027,2.3275,2.2802 | |
232 | 3.3672,2.0518,2.3629,2.3262 | |
233 | 3.3752,2.0575,2.3702,2.3365 | |
234 | 3.3901,2.0683,2.383,2.3548 | |
235 | 3.4258,2.0925,2.4127,2.3931 | |
236 | 3.4364,2.0991,2.4218,2.4043 | |
237 | 3.4513,2.1078,2.4349,2.421 | |
238 | 3.4976,2.1323,2.4759,2.4802 | |
239 | 3.51,2.1389,2.4867,2.4956 | |
240 | 3.5202,2.1444,2.4956,2.5074 | |
241 | 3.5588,2.1656,2.5276,2.5487 | |
242 | 3.5712,2.1723,2.5373,2.5618 | |
243 | 3.5814,2.1779,2.5454,2.5731 | |
244 | 3.6201,2.1989,2.5767,2.6172 | |
245 | 3.6298,2.2041,2.5847,2.6281 | |
246 | 3.6426,2.2111,2.5951,2.6421 | |
247 | 3.6813,2.2321,2.6267,2.6836 | |
248 | 3.691,2.2374,2.6346,2.6944 | |
249 | 3.7038,2.2443,2.6449,2.7091 | |
250 | 3.7425,2.2654,2.6762,2.7532 | |
251 | 3.7496,2.2693,2.682,2.7607 | |
252 | 3.765,2.2777,2.6947,2.7757 | |
253 | 3.8037,2.2987,2.7273,2.8117 | |
254 | 3.8108,2.3024,2.7334,2.8187 | |
255 | 3.8237,2.3093,2.7445,2.8322 | |
256 | 3.865,2.3319,2.7792,2.8797 | |
257 | 3.8695,2.3345,2.7827,2.885 | |
258 | 3.8849,2.3434,2.7942,2.9025 | |
259 | 3.9262,2.3652,2.8216,2.9467 | |
260 | 3.9307,2.3671,2.8246,2.9512 | |
261 | 3.9461,2.3733,2.8357,2.9664 | |
262 | 3.99,2.3902,2.8732,3.0075 | |
263 | 3.9919,2.391,2.8748,3.0093 | |
264 | 4.0048,2.3972,2.8855,3.0214 | |
265 | 4.0505,2.4231,2.9173,3.0673 | |
266 | 4.0512,2.4235,2.9178,3.068 | |
267 | 4.066,2.4322,2.927,3.0841 | |
268 | 4.1117,2.4564,2.9571,3.1336 | |
269 | 4.1124,2.4567,2.9577,3.1343 | |
270 | 4.1272,2.463,2.9686,3.149 | |
271 | 4.1729,2.4814,3.0058,3.1916 | |
272 | 4.1737,2.4817,3.0065,3.1923 | |
273 | 4.1884,2.4889,3.0183,3.206 | |
274 | 4.2341,2.5145,3.0511,3.2496 | |
275 | 4.2349,2.515,3.0516,3.2504 | |
276 | 4.2471,2.5221,3.0598,3.2624 | |
277 | 4.2953,2.5479,3.0925,3.3077 | |
278 | 4.2961,2.5483,3.0931,3.3084 | |
279 | 4.3083,2.5537,3.1014,3.3184 | |
280 | 4.3565,2.5721,3.1341,3.3574 | |
281 | 4.3599,2.5733,3.1364,3.3605 | |
282 | 4.3695,2.5768,3.1429,3.3693 | |
283 | 4.4152,2.5954,3.1738,3.4154 | |
284 | 4.4212,2.5983,3.1779,3.4215 | |
285 | 4.4307,2.6033,3.1844,3.4311 | |
286 | 4.4764,2.6285,3.2154,3.4735 | |
287 | 4.4824,2.6316,3.2195,3.4785 | |
288 | 4.492,2.6361,3.2259,3.4862 | |
289 | 4.5376,2.6543,3.2567,3.5232 | |
290 | 4.5436,2.6566,3.2608,3.5287 | |
291 | 4.5532,2.6603,3.2674,3.5376 | |
292 | 4.5988,2.6791,3.2998,3.5813 | |
293 | 4.6049,2.6816,3.3041,3.5866 | |
294 | 4.6118,2.6844,3.3089,3.5926 | |
295 | 4.66,2.7033,3.3415,3.631 | |
296 | 4.6687,2.7066,3.3474,3.6382 | |
297 | 4.6731,2.7083,3.3505,3.6419 | |
298 | 4.7187,2.7263,3.3819,3.6808 | |
299 | 4.7299,2.7316,3.3892,3.6901 | |
300 | 4.7343,2.7338,3.392,3.6937 | |
301 | 4.7799,2.759,3.4173,3.7306 | |
302 | 4.7911,2.7649,3.423,3.7398 | |
303 | 4.7955,2.767,3.4252,3.7435 | |
304 | 4.8411,2.7857,3.4493,3.7804 | |
305 | 4.8524,2.7899,3.4559,3.789 | |
306 | 4.8567,2.7916,3.4585,3.7923 | |
307 | 4.9048,2.8104,3.4906,3.8301 | |
308 | 4.9162,2.8149,3.4987,3.8402 | |
309 | 4.918,2.8157,3.5,3.8419 | |
310 | 4.966,2.8353,3.5335,3.8882 | |
311 | 4.9774,2.8399,3.5405,3.8988 | |
312 | 4.9792,2.8407,3.5415,3.9005 | |
313 | 5.0247,2.8594,3.5657,3.9379 | |
314 | 5.0386,2.8649,3.5737,3.9476 | |
315 | 5.0404,2.8657,3.5748,3.9487 | |
316 | 5.0859,2.8834,3.6061,3.9794 | |
317 | 5.1016,2.8897,3.6163,3.9918 | |
318 | 5.1024,2.89,3.6168,3.9924 | |
319 | 5.1446,2.9072,3.6394,4.0292 | |
320 | 5.1629,2.9147,3.6496,4.045 | |
321 | 5.1637,2.915,3.6501,4.0457 | |
322 | 5.2058,2.9319,3.6788,4.079 | |
323 | 5.2241,2.9396,3.6911,4.0916 | |
324 | 5.2249,2.94,3.6916,4.0921 | |
325 | 5.267,2.9582,3.715,4.1205 | |
326 | 5.2853,2.9647,3.7244,4.1343 | |
327 | 5.2861,2.965,3.7248,4.135 | |
328 | 5.3282,2.9758,3.7475,4.1703 | |
329 | 5.3465,2.9807,3.7576,4.1864 | |
330 | 5.3499,2.9818,3.7595,4.1894 | |
331 | 5.3869,2.9962,3.7796,4.22 | |
332 | 5.4078,3.0053,3.7909,4.235 | |
333 | 5.4112,3.0068,3.7928,4.2373 | |
334 | 5.4481,3.0215,3.8128,4.2616 | |
335 | 5.469,3.0295,3.8242,4.2757 | |
336 | 5.475,3.0318,3.8274,4.2798 | |
337 | 5.5093,3.0457,3.8461,4.3031 | |
338 | 5.5302,3.0543,3.8574,4.3166 | |
339 | 5.5362,3.0568,3.8607,4.3205 | |
340 | 5.5705,3.0708,3.8793,4.3446 | |
341 | 5.5915,3.0794,3.8907,4.3621 | |
342 | 5.5974,3.0818,3.894,4.3673 | |
343 | 5.6292,3.0949,3.9113,4.3944 | |
344 | 5.6527,3.1039,3.924,4.4114 | |
345 | 5.6612,3.1068,3.9285,4.4171 | |
346 | 5.6904,3.1156,3.9442,4.4359 | |
347 | 5.7139,3.1216,3.9572,4.4515 | |
348 | 5.7225,3.1236,3.9622,4.4573 | |
349 | 5.7516,3.1306,3.9788,4.4774 | |
350 | 5.7751,3.1374,3.9905,4.4935 | |
351 | 5.7837,3.1404,3.9941,4.4994 | |
352 | 5.8129,3.152,4.0049,4.5189 | |
353 | 5.8364,3.1614,4.0155,4.5346 | |
354 | 5.8475,3.1654,4.022,4.5423 | |
355 | 5.8715,3.1721,4.0385,4.5604 | |
356 | 5.8976,3.1787,4.057,4.5825 | |
357 | 5.9088,3.1821,4.0643,4.5919 | |
358 | 5.9327,3.1914,4.0779,4.6102 | |
359 | 5.9588,3.2022,4.0903,4.6253 | |
360 | 5.9726,3.2072,4.096,4.6322 | |
361 | 5.994,3.2132,4.1043,4.6435 | |
362 | 6.0201,3.2197,4.1153,4.6601 | |
363 | 6.0338,3.2239,4.122,4.6697 | |
364 | 6.0552,3.2325,4.1336,4.685 | |
365 | 6.0813,3.2438,4.1486,4.7029 | |
366 | 6.095,3.2489,4.1564,4.7121 | |
367 | 6.1164,3.2548,4.168,4.7265 | |
368 | 6.1451,3.2616,4.1818,4.7465 | |
369 | 6.1588,3.2657,4.1875,4.7563 | |
370 | 6.1751,3.2719,4.1938,4.768 | |
371 | 6.2063,3.2855,4.2069,4.7902 | |
372 | 6.2201,3.2907,4.2139,4.7995 | |
373 | 6.2363,3.2954,4.223,4.8095 | |
374 | 6.2675,3.3028,4.2401,4.8265 | |
375 | 6.2839,3.3075,4.2477,4.8351 | |
376 | 6.2975,3.3126,4.2534,4.8428 | |
377 | 6.3288,3.3262,4.2651,4.863 | |
378 | 6.3451,3.3325,4.2713,4.8745 | |
379 | 6.3587,3.3365,4.2766,4.8843 | |
380 | 6.39,3.3439,4.2901,4.9067 | |
381 | 6.4089,3.3493,4.2993,4.9192 | |
382 | 6.42,3.3533,4.305,4.9258 | |
383 | 6.4538,3.3678,4.3234,4.9438 | |
384 | 6.4702,3.3743,4.3327,4.9526 | |
385 | 6.4812,3.3777,4.3389,4.9591 | |
386 | 6.515,3.3863,4.3567,4.9822 | |
387 | 6.5314,3.391,4.3641,4.9936 | |
388 | 6.5424,3.3949,4.3687,5.0006 | |
389 | 6.5763,3.4086,4.3817,5.0189 | |
390 | 6.5952,3.416,4.3887,5.029 | |
391 | 6.6036,3.4189,4.3919,5.0339 | |
392 | 6.6375,3.4283,4.4067,5.0568 | |
393 | 6.6564,3.4328,4.4169,5.0699 | |
394 | 6.6648,3.4349,4.4216,5.0754 | |
395 | 6.6987,3.4436,4.44,5.0944 | |
396 | 6.7202,3.4496,4.4495,5.1056 | |
397 | 6.7261,3.4512,4.4518,5.1087 | |
398 | 6.7625,3.4615,4.465,5.1294 | |
399 | 6.7815,3.4663,4.4718,5.1402 | |
400 | 6.7848,3.4671,4.473,5.1419 | |
401 | 6.8238,3.4762,4.49,5.1622 | |
402 | 6.8453,3.4831,4.5018,5.1747 | |
403 | 6.846,3.4834,4.5022,5.1752 | |
404 | 6.885,3.5007,4.5233,5.203 | |
405 | 6.9047,3.5076,4.5316,5.2167 | |
406 | 6.9065,3.5081,4.5323,5.2179 | |
407 | 6.9462,3.513,4.5483,5.24 | |
408 | 6.9659,3.5156,4.5586,5.25 | |
409 | 6.9703,3.5166,4.5611,5.2523 | |
410 | 7.0075,3.5311,4.5815,5.2722 | |
411 | 7.0271,3.5399,4.5902,5.2832 | |
412 | 7.0316,3.5416,4.592,5.2858 | |
413 | 7.0712,3.5529,4.6066,5.3083 | |
414 | 7.0858,3.5561,4.6122,5.3165 | |
415 | 7.0954,3.5584,4.6161,5.3218 | |
416 | 7.1325,3.5686,4.6316,5.342 | |
417 | 7.147,3.5727,4.6376,5.3497 | |
418 | 7.1566,3.5751,4.6415,5.3548 | |
419 | 7.1937,3.5838,4.6566,5.3755 | |
420 | 7.2057,3.5871,4.6615,5.383 | |
421 | 7.2204,3.5919,4.6676,5.3929 | |
422 | 7.255,3.607,4.6816,5.4168 | |
423 | 7.2669,3.612,4.6863,5.4245 | |
424 | 7.2817,3.6169,4.6921,5.4332 | |
425 | 7.3188,3.6224,4.7066,5.4528 | |
426 | 7.3281,3.6233,4.7104,5.4578 | |
427 | 7.3455,3.6254,4.7174,5.4674 | |
428 | 7.38,3.6342,4.7316,5.4863 | |
429 | 7.3894,3.6371,4.7355,5.4911 | |
430 | 7.4067,3.6422,4.7427,5.4989 | |
431 | 7.4412,3.6507,4.7566,5.5131 | |
432 | 7.4481,3.6524,4.7593,5.5161 | |
433 | 7.4705,3.659,4.7681,5.5267 | |
434 | 7.505,3.6731,4.7817,5.5465 | |
435 | 7.5093,3.675,4.7834,5.5493 | |
436 | 7.5318,3.684,4.7926,5.5653 | |
437 | 7.5663,3.6938,4.8067,5.5885 | |
438 | 7.5705,3.6948,4.8084,5.5908 | |
439 | 7.5956,3.7007,4.8184,5.6019 | |
440 | 7.6275,3.7093,4.8317,5.614 | |
441 | 7.6317,3.7105,4.8336,5.6158 | |
442 | 7.6568,3.7175,4.8448,5.629 | |
443 | 7.6887,3.7257,4.8567,5.6481 | |
444 | 7.6904,3.7262,4.8572,5.6491 | |
445 | 7.7206,3.7343,4.8642,5.6655 | |
446 | 7.7516,3.7436,4.8731,5.6824 | |
447 | 7.7525,3.7438,4.8735,5.6829 | |
448 | 7.7818,3.751,4.8884,5.7004 | |
449 | 7.8103,3.7549,4.9049,5.7156 | |
450 | 7.8138,3.7553,4.9067,5.7172 | |
451 | 7.8457,3.7595,4.9207,5.7295 | |
452 | 7.8741,3.7661,4.9314,5.7406 | |
453 | 7.875,3.7663,4.9317,5.741 | |
454 | 7.9095,3.7763,4.9458,5.7596 | |
455 | 7.9328,3.7829,4.9548,5.7739 | |
456 | 7.9388,3.7846,4.9568,5.7775 | |
457 | 7.9707,3.7931,4.9654,5.7957 | |
458 | 7.994,3.7991,4.9716,5.8072 | |
459 | 8,3.8007,4.9735,5.8098 | |
460 | 8.0345,3.8098,4.987,5.8235 | |
461 | 8.0553,3.8155,4.996,5.8322 | |
462 | 8.0613,3.8172,4.9985,5.835 | |
463 | 8.0957,3.8266,5.0121,5.8533 | |
464 | 8.1165,3.8319,5.0201,5.8654 | |
465 | 8.1251,3.8341,5.0236,5.8706 | |
466 | 8.1595,3.8434,5.0382,5.8906 | |
467 | 8.1752,3.848,5.0445,5.8987 | |
468 | 8.1863,3.8514,5.0486,5.9039 | |
469 | 8.2208,3.8601,5.0585,5.9179 | |
470 | 8.2364,3.8625,5.0622,5.9237 | |
471 | 8.2501,3.8642,5.0653,5.9288 | |
472 | 8.2846,3.8686,5.0734,5.9427 | |
473 | 8.3484,3.8854,5.097,5.9812 |
0 | <ErrorReport> | |
1 | <Application VersionNumber="9.0"/> | |
2 | <Document VersionNumber="9.0" AxesPointsRequired="0"> | |
3 | <Image Height="2000" Width="4000"><![CDATA[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]]></Image> | |
4 | <CoordSystem> | |
5 | <General ExtraPrecision="1" CursorSize="3"/> | |
6 | <Coords UnitsTime="2" ScaleYRadius="0" ScaleYRadiusString="Linear" TypeString="Cartesian" UnitsX="0" Type="0" UnitsY="0" UnitsRadius="0" UnitsThetaString="Degrees (DDD.DDDDD)" UnitsRadiusString="Number" ScaleXThetaString="Linear" Coords="0" UnitsDate="3" UnitsDateString="YYYY/MM/DD" ScaleXTheta="0" UnitsYString="Number" UnitsXString="Number" UnitsTheta="0" UnitsTimeString="HH:MM:SS"/> | |
7 | <DigitizeCurve CursorInnerRadius="5" CursorLineWidth="2" CursorSize="1" CursorStandardCross="True"/> | |
8 | <Export LayoutFunctions="0" Delimiter="0" XLabel="x" DelimiterString="Commas" PointsIntervalUnitsRelations="1" Header="1" PointsSelectionRelationsString="Interpolate" PointsSelectionFunctions="0" PointsIntervalFunctions="10" HeaderString="Simple" PointsSelectionFunctionsString="InterpolateAllCurves" LayoutFunctionsString="AllPerLine" OverrideCsvTsv="True" PointsIntervalUnitsFunctions="1" PointsSelectionRelations="0" PointsIntervalRelations="10"> | |
9 | <CurveNamesNotExported/> | |
10 | </Export> | |
11 | <AxesChecker Mode="1" LineColor="6" Seconds="3"/> | |
12 | <GridDisplay StopX="1" StopY="1" Stable="False" DisableX="0" ColorString="Black" DisableY="0" CountX="2" StartX="0" StepX="1" CountY="2" StartY="0" StepY="1" Color="0"/> | |
13 | <GridRemoval StopX="0" CoordDisableY="0" StopY="0" CloseDistance="10" CoordDisableYString="Count" CoordDisableXString="Count" Stable="False" DefinedGridLines="False" CountX="2" StartX="0" StepX="0" CountY="2" StartY="0" StepY="0" CoordDisableX="0"/> | |
14 | <PointMatch ColorAccepted="4" ColorCandidate="7" ColorAcceptedString="Green" ColorRejectedString="Red" ColorCandidateString="Yellow" PointSize="48" ColorRejected="6"/> | |
15 | <Segments LineColor="4" MinLength="2" LineWidth="4" FillCorners="False" LineColorString="Green" PointSeparation="25"/> | |
16 | <Curve CurveName="Axes"> | |
17 | <ColorFilter Mode="2" HueHigh="360" CurveName="Axes" ModeString="Intensity" IntensityLow="0" ForegroundHigh="10" SaturationLow="50" ValueHigh="50" ForegroundLow="0" SaturationHigh="100" ValueLow="0" IntensityHigh="50" HueLow="180"/> | |
18 | <CurveStyle CurveName="Axes"> | |
19 | <LineStyle ColorString="Transparent" ConnectAsString="ConnectSkipForAxisCurve" ConnectAs="4" Color="8" Width="0"/> | |
20 | <PointStyle Radius="10" LineWidth="1" Shape="1" ShapeString="Cross" ColorString="Red" Color="6"/> | |
21 | </CurveStyle> | |
22 | <CurvePoints/> | |
23 | </Curve> | |
24 | <CurvesGraphs> | |
25 | <Curve CurveName="Curve1"> | |
26 | <ColorFilter Mode="2" HueHigh="360" CurveName="Curve1" ModeString="Intensity" IntensityLow="0" ForegroundHigh="10" SaturationLow="50" ValueHigh="50" ForegroundLow="0" SaturationHigh="100" ValueLow="0" IntensityHigh="50" HueLow="180"/> | |
27 | <CurveStyle CurveName="Curve1"> | |
28 | <LineStyle ColorString="Blue" ConnectAsString="FunctionSmooth" ConnectAs="0" Color="1" Width="1"/> | |
29 | <PointStyle Radius="10" LineWidth="1" Shape="1" ShapeString="Cross" ColorString="Blue" Color="1"/> | |
30 | </CurveStyle> | |
31 | <CurvePoints/> | |
32 | </Curve> | |
33 | </CurvesGraphs> | |
34 | </CoordSystem> | |
35 | <OperatingSystem WordSize="32" Endian="LittleEndian"/> | |
36 | <File Imported="True"/> | |
37 | <CmdMediator> | |
38 | <Cmd Type="CmdSettingsCurveAddRemove" Description="Curve add/remove"> | |
39 | <CurvesGraphs> | |
40 | <Curve CurveName="Curve1"> | |
41 | <ColorFilter Mode="2" HueHigh="360" CurveName="Curve1" ModeString="Intensity" IntensityLow="0" ForegroundHigh="10" SaturationLow="50" ValueHigh="50" ForegroundLow="0" SaturationHigh="100" ValueLow="0" IntensityHigh="50" HueLow="180"/> | |
42 | <CurveStyle CurveName="Curve1"> | |
43 | <LineStyle ColorString="Blue" ConnectAsString="FunctionSmooth" ConnectAs="0" Color="1" Width="1"/> | |
44 | <PointStyle Radius="10" LineWidth="1" Shape="1" ShapeString="Cross" ColorString="Blue" Color="1"/> | |
45 | </CurveStyle> | |
46 | <CurvePoints/> | |
47 | </Curve> | |
48 | </CurvesGraphs> | |
49 | <CurvesGraphs> | |
50 | <Curve CurveName="red"> | |
51 | <ColorFilter Mode="2" HueHigh="360" CurveName="red" ModeString="Intensity" IntensityLow="0" ForegroundHigh="10" SaturationLow="50" ValueHigh="50" ForegroundLow="0" SaturationHigh="100" ValueLow="0" IntensityHigh="50" HueLow="180"/> | |
52 | <CurveStyle CurveName="red"> | |
53 | <LineStyle ColorString="Blue" ConnectAsString="FunctionSmooth" ConnectAs="0" Color="1" Width="1"/> | |
54 | <PointStyle Radius="10" LineWidth="1" Shape="1" ShapeString="Cross" ColorString="Blue" Color="1"/> | |
55 | </CurveStyle> | |
56 | <CurvePoints/> | |
57 | </Curve> | |
58 | <Curve CurveName="green"> | |
59 | <ColorFilter Mode="2" HueHigh="360" CurveName="green" ModeString="Intensity" IntensityLow="0" ForegroundHigh="10" SaturationLow="50" ValueHigh="50" ForegroundLow="0" SaturationHigh="100" ValueLow="0" IntensityHigh="50" HueLow="180"/> | |
60 | <CurveStyle CurveName="green"> | |
61 | <LineStyle ColorString="Blue" ConnectAsString="FunctionSmooth" ConnectAs="0" Color="1" Width="1"/> | |
62 | <PointStyle Radius="10" LineWidth="1" Shape="5" ShapeString="X" ColorString="Blue" Color="1"/> | |
63 | </CurveStyle> | |
64 | <CurvePoints/> | |
65 | </Curve> | |
66 | <Curve CurveName="blue"> | |
67 | <ColorFilter Mode="2" HueHigh="360" CurveName="blue" ModeString="Intensity" IntensityLow="0" ForegroundHigh="10" SaturationLow="50" ValueHigh="50" ForegroundLow="0" SaturationHigh="100" ValueLow="0" IntensityHigh="50" HueLow="180"/> | |
68 | <CurveStyle CurveName="blue"> | |
69 | <LineStyle ColorString="Blue" ConnectAsString="FunctionSmooth" ConnectAs="0" Color="1" Width="1"/> | |
70 | <PointStyle Radius="10" LineWidth="1" Shape="2" ShapeString="Diamond" ColorString="Blue" Color="1"/> | |
71 | </CurveStyle> | |
72 | <CurvePoints/> | |
73 | </Curve> | |
74 | </CurvesGraphs> | |
75 | </Cmd> | |
76 | <Cmd Type="CmdAddPointAxis" IsXOnly="False" Identifier="Axes	point	1" Description="Add axis point" ScreenX="51.6351" ScreenY="1958.13" GraphX="0" GraphY="-10" Ordinal="1"/> | |
77 | <Cmd Type="CmdAddPointAxis" IsXOnly="False" Identifier="Axes	point	3" Description="Add axis point" ScreenX="3969.02" ScreenY="1963.05" GraphX="10" GraphY="-10" Ordinal="2"/> | |
78 | <Cmd Type="CmdAddPointAxis" IsXOnly="False" Identifier="Axes	point	5" Description="Add axis point" ScreenX="58.5198" ScreenY="19.7044" GraphX="0" GraphY="6" Ordinal="3"/> | |
79 | <Cmd Type="CmdSettingsColorFilter" Description="Filter settings"> | |
80 | <Filter> | |
81 | <ColorFilter Mode="2" HueHigh="360" CurveName="red" ModeString="Intensity" IntensityLow="0" ForegroundHigh="10" SaturationLow="50" ValueHigh="50" ForegroundLow="0" SaturationHigh="100" ValueLow="0" IntensityHigh="50" HueLow="180"/> | |
82 | <ColorFilter Mode="2" HueHigh="360" CurveName="blue" ModeString="Intensity" IntensityLow="0" ForegroundHigh="10" SaturationLow="50" ValueHigh="50" ForegroundLow="0" SaturationHigh="100" ValueLow="0" IntensityHigh="50" HueLow="180"/> | |
83 | <ColorFilter Mode="2" HueHigh="360" CurveName="green" ModeString="Intensity" IntensityLow="0" ForegroundHigh="10" SaturationLow="50" ValueHigh="50" ForegroundLow="0" SaturationHigh="100" ValueLow="0" IntensityHigh="50" HueLow="180"/> | |
84 | <ColorFilter Mode="2" HueHigh="360" CurveName="Axes" ModeString="Intensity" IntensityLow="0" ForegroundHigh="10" SaturationLow="50" ValueHigh="50" ForegroundLow="0" SaturationHigh="100" ValueLow="0" IntensityHigh="50" HueLow="180"/> | |
85 | </Filter> | |
86 | <Filter> | |
87 | <ColorFilter Mode="1" HueHigh="3" CurveName="red" ModeString="Hue" IntensityLow="0" ForegroundHigh="10" SaturationLow="50" ValueHigh="50" ForegroundLow="0" SaturationHigh="100" ValueLow="0" IntensityHigh="50" HueLow="0"/> | |
88 | <ColorFilter Mode="2" HueHigh="360" CurveName="blue" ModeString="Intensity" IntensityLow="0" ForegroundHigh="10" SaturationLow="50" ValueHigh="50" ForegroundLow="0" SaturationHigh="100" ValueLow="0" IntensityHigh="50" HueLow="180"/> | |
89 | <ColorFilter Mode="2" HueHigh="360" CurveName="green" ModeString="Intensity" IntensityLow="0" ForegroundHigh="10" SaturationLow="50" ValueHigh="50" ForegroundLow="0" SaturationHigh="100" ValueLow="0" IntensityHigh="50" HueLow="180"/> | |
90 | <ColorFilter Mode="2" HueHigh="360" CurveName="Axes" ModeString="Intensity" IntensityLow="0" ForegroundHigh="10" SaturationLow="50" ValueHigh="50" ForegroundLow="0" SaturationHigh="100" ValueLow="0" IntensityHigh="50" HueLow="180"/> | |
91 | </Filter> | |
92 | </Cmd> | |
93 | <Cmd Type="CmdSettingsColorFilter" Description="Filter settings"> | |
94 | <Filter> | |
95 | <ColorFilter Mode="1" HueHigh="3" CurveName="red" ModeString="Hue" IntensityLow="0" ForegroundHigh="10" SaturationLow="50" ValueHigh="50" ForegroundLow="0" SaturationHigh="100" ValueLow="0" IntensityHigh="50" HueLow="0"/> | |
96 | <ColorFilter Mode="2" HueHigh="360" CurveName="blue" ModeString="Intensity" IntensityLow="0" ForegroundHigh="10" SaturationLow="50" ValueHigh="50" ForegroundLow="0" SaturationHigh="100" ValueLow="0" IntensityHigh="50" HueLow="180"/> | |
97 | <ColorFilter Mode="2" HueHigh="360" CurveName="green" ModeString="Intensity" IntensityLow="0" ForegroundHigh="10" SaturationLow="50" ValueHigh="50" ForegroundLow="0" SaturationHigh="100" ValueLow="0" IntensityHigh="50" HueLow="180"/> | |
98 | <ColorFilter Mode="2" HueHigh="360" CurveName="Axes" ModeString="Intensity" IntensityLow="0" ForegroundHigh="10" SaturationLow="50" ValueHigh="50" ForegroundLow="0" SaturationHigh="100" ValueLow="0" IntensityHigh="50" HueLow="180"/> | |
99 | </Filter> | |
100 | <Filter> | |
101 | <ColorFilter Mode="1" HueHigh="3" CurveName="red" ModeString="Hue" IntensityLow="0" ForegroundHigh="10" SaturationLow="50" ValueHigh="50" ForegroundLow="0" SaturationHigh="100" ValueLow="0" IntensityHigh="50" HueLow="0"/> | |
102 | <ColorFilter Mode="2" HueHigh="360" CurveName="blue" ModeString="Intensity" IntensityLow="0" ForegroundHigh="10" SaturationLow="50" ValueHigh="50" ForegroundLow="0" SaturationHigh="100" ValueLow="0" IntensityHigh="50" HueLow="180"/> | |
103 | <ColorFilter Mode="2" HueHigh="360" CurveName="green" ModeString="Intensity" IntensityLow="0" ForegroundHigh="10" SaturationLow="50" ValueHigh="50" ForegroundLow="0" SaturationHigh="100" ValueLow="0" IntensityHigh="50" HueLow="180"/> | |
104 | <ColorFilter Mode="2" HueHigh="360" CurveName="Axes" ModeString="Intensity" IntensityLow="0" ForegroundHigh="10" SaturationLow="50" ValueHigh="50" ForegroundLow="0" SaturationHigh="100" ValueLow="0" IntensityHigh="50" HueLow="180"/> | |
105 | </Filter> | |
106 | </Cmd> | |
107 | <Cmd Type="CmdAddPointsGraph" CurveName="red" Description="Add graph points"> | |
108 | <Point Identifier="red	point	6" ScreenX="95" ScreenY="1350" Ordinal="1"/> | |
109 | <Point Identifier="red	point	7" ScreenX="101" ScreenY="1326" Ordinal="1"/> | |
110 | <Point Identifier="red	point	8" ScreenX="107" ScreenY="1301" Ordinal="1"/> | |
111 | <Point Identifier="red	point	9" ScreenX="113" ScreenY="1277" Ordinal="1"/> | |
112 | <Point Identifier="red	point	10" ScreenX="118" ScreenY="1253" Ordinal="1"/> | |
113 | <Point Identifier="red	point	11" ScreenX="124" ScreenY="1228" Ordinal="1"/> | |
114 | <Point Identifier="red	point	12" ScreenX="130" ScreenY="1204" Ordinal="1"/> | |
115 | <Point Identifier="red	point	13" ScreenX="136" ScreenY="1180" Ordinal="1"/> | |
116 | <Point Identifier="red	point	14" ScreenX="145" ScreenY="1157" Ordinal="1"/> | |
117 | <Point Identifier="red	point	15" ScreenX="155" ScreenY="1134" Ordinal="1"/> | |
118 | <Point Identifier="red	point	16" ScreenX="164" ScreenY="1110" Ordinal="1"/> | |
119 | <Point Identifier="red	point	17" ScreenX="173" ScreenY="1087" Ordinal="1"/> | |
120 | <Point Identifier="red	point	18" ScreenX="185" ScreenY="1065" Ordinal="1"/> | |
121 | <Point Identifier="red	point	19" ScreenX="197" ScreenY="1043" Ordinal="1"/> | |
122 | <Point Identifier="red	point	20" ScreenX="210" ScreenY="1022" Ordinal="1"/> | |
123 | <Point Identifier="red	point	21" ScreenX="224" ScreenY="1001" Ordinal="1"/> | |
124 | <Point Identifier="red	point	22" ScreenX="238" ScreenY="981" Ordinal="1"/> | |
125 | <Point Identifier="red	point	23" ScreenX="253" ScreenY="961" Ordinal="1"/> | |
126 | <Point Identifier="red	point	24" ScreenX="269" ScreenY="942" Ordinal="1"/> | |
127 | <Point Identifier="red	point	25" ScreenX="286" ScreenY="923" Ordinal="1"/> | |
128 | <Point Identifier="red	point	26" ScreenX="304" ScreenY="905" Ordinal="1"/> | |
129 | <Point Identifier="red	point	27" ScreenX="322" ScreenY="888" Ordinal="1"/> | |
130 | <Point Identifier="red	point	28" ScreenX="340" ScreenY="872" Ordinal="1"/> | |
131 | <Point Identifier="red	point	29" ScreenX="359" ScreenY="856" Ordinal="1"/> | |
132 | <Point Identifier="red	point	30" ScreenX="379" ScreenY="841" Ordinal="1"/> | |
133 | <Point Identifier="red	point	31" ScreenX="399" ScreenY="826" Ordinal="1"/> | |
134 | <Point Identifier="red	point	32" ScreenX="419" ScreenY="812" Ordinal="1"/> | |
135 | <Point Identifier="red	point	33" ScreenX="440" ScreenY="798" Ordinal="1"/> | |
136 | <Point Identifier="red	point	34" ScreenX="461" ScreenY="785" Ordinal="1"/> | |
137 | <Point Identifier="red	point	35" ScreenX="483" ScreenY="773" Ordinal="1"/> | |
138 | <Point Identifier="red	point	36" ScreenX="505" ScreenY="761" Ordinal="1"/> | |
139 | <Point Identifier="red	point	37" ScreenX="527" ScreenY="749" Ordinal="1"/> | |
140 | <Point Identifier="red	point	38" ScreenX="550" ScreenY="738" Ordinal="1"/> | |
141 | <Point Identifier="red	point	39" ScreenX="572" ScreenY="728" Ordinal="1"/> | |
142 | <Point Identifier="red	point	40" ScreenX="595" ScreenY="717" Ordinal="1"/> | |
143 | <Point Identifier="red	point	41" ScreenX="618" ScreenY="707" Ordinal="1"/> | |
144 | <Point Identifier="red	point	42" ScreenX="641" ScreenY="697" Ordinal="1"/> | |
145 | <Point Identifier="red	point	43" ScreenX="664" ScreenY="688" Ordinal="1"/> | |
146 | <Point Identifier="red	point	44" ScreenX="687" ScreenY="678" Ordinal="1"/> | |
147 | <Point Identifier="red	point	45" ScreenX="710" ScreenY="670" Ordinal="1"/> | |
148 | <Point Identifier="red	point	46" ScreenX="734" ScreenY="662" Ordinal="1"/> | |
149 | <Point Identifier="red	point	47" ScreenX="757" ScreenY="653" Ordinal="1"/> | |
150 | <Point Identifier="red	point	48" ScreenX="781" ScreenY="646" Ordinal="1"/> | |
151 | <Point Identifier="red	point	49" ScreenX="805" ScreenY="638" Ordinal="1"/> | |
152 | <Point Identifier="red	point	50" ScreenX="828" ScreenY="630" Ordinal="1"/> | |
153 | <Point Identifier="red	point	51" ScreenX="852" ScreenY="622" Ordinal="1"/> | |
154 | <Point Identifier="red	point	52" ScreenX="876" ScreenY="615" Ordinal="1"/> | |
155 | <Point Identifier="red	point	53" ScreenX="898" ScreenY="608" Ordinal="1"/> | |
156 | <Point Identifier="red	point	54" ScreenX="921" ScreenY="602" Ordinal="1"/> | |
157 | <Point Identifier="red	point	55" ScreenX="944" ScreenY="596" Ordinal="1"/> | |
158 | <Point Identifier="red	point	56" ScreenX="967" ScreenY="589" Ordinal="1"/> | |
159 | <Point Identifier="red	point	57" ScreenX="991" ScreenY="583" Ordinal="1"/> | |
160 | <Point Identifier="red	point	58" ScreenX="1014" ScreenY="577" Ordinal="1"/> | |
161 | </Cmd> | |
162 | <Cmd Type="CmdAddPointsGraph" CurveName="red" Description="Add graph points"> | |
163 | <Point Identifier="red	point	59" ScreenX="1212" ScreenY="532" Ordinal="53.5"/> | |
164 | <Point Identifier="red	point	60" ScreenX="1236" ScreenY="527" Ordinal="53.5"/> | |
165 | <Point Identifier="red	point	61" ScreenX="1260" ScreenY="522" Ordinal="53.5"/> | |
166 | <Point Identifier="red	point	62" ScreenX="1284" ScreenY="518" Ordinal="53.5"/> | |
167 | <Point Identifier="red	point	63" ScreenX="1307" ScreenY="513" Ordinal="53.5"/> | |
168 | <Point Identifier="red	point	64" ScreenX="1331" ScreenY="508" Ordinal="53.5"/> | |
169 | <Point Identifier="red	point	65" ScreenX="1355" ScreenY="504" Ordinal="53.5"/> | |
170 | <Point Identifier="red	point	66" ScreenX="1379" ScreenY="499" Ordinal="53.5"/> | |
171 | <Point Identifier="red	point	67" ScreenX="1403" ScreenY="494" Ordinal="53.5"/> | |
172 | <Point Identifier="red	point	68" ScreenX="1427" ScreenY="490" Ordinal="53.5"/> | |
173 | <Point Identifier="red	point	69" ScreenX="1451" ScreenY="486" Ordinal="53.5"/> | |
174 | <Point Identifier="red	point	70" ScreenX="1475" ScreenY="482" Ordinal="53.5"/> | |
175 | <Point Identifier="red	point	71" ScreenX="1499" ScreenY="478" Ordinal="53.5"/> | |
176 | <Point Identifier="red	point	72" ScreenX="1523" ScreenY="474" Ordinal="53.5"/> | |
177 | <Point Identifier="red	point	73" ScreenX="1547" ScreenY="470" Ordinal="53.5"/> | |
178 | <Point Identifier="red	point	74" ScreenX="1571" ScreenY="466" Ordinal="53.5"/> | |
179 | <Point Identifier="red	point	75" ScreenX="1595" ScreenY="462" Ordinal="53.5"/> | |
180 | <Point Identifier="red	point	76" ScreenX="1620" ScreenY="459" Ordinal="53.5"/> | |
181 | <Point Identifier="red	point	77" ScreenX="1644" ScreenY="455" Ordinal="53.5"/> | |
182 | <Point Identifier="red	point	78" ScreenX="1668" ScreenY="451" Ordinal="53.5"/> | |
183 | <Point Identifier="red	point	79" ScreenX="1692" ScreenY="448" Ordinal="53.5"/> | |
184 | <Point Identifier="red	point	80" ScreenX="1716" ScreenY="444" Ordinal="53.5"/> | |
185 | <Point Identifier="red	point	81" ScreenX="1740" ScreenY="440" Ordinal="53.5"/> | |
186 | <Point Identifier="red	point	82" ScreenX="1765" ScreenY="437" Ordinal="53.5"/> | |
187 | <Point Identifier="red	point	83" ScreenX="1789" ScreenY="434" Ordinal="53.5"/> | |
188 | <Point Identifier="red	point	84" ScreenX="1813" ScreenY="430" Ordinal="53.5"/> | |
189 | <Point Identifier="red	point	85" ScreenX="1837" ScreenY="427" Ordinal="53.5"/> | |
190 | <Point Identifier="red	point	86" ScreenX="1861" ScreenY="424" Ordinal="53.5"/> | |
191 | <Point Identifier="red	point	87" ScreenX="1886" ScreenY="421" Ordinal="53.5"/> | |
192 | <Point Identifier="red	point	88" ScreenX="1910" ScreenY="418" Ordinal="53.5"/> | |
193 | <Point Identifier="red	point	89" ScreenX="1934" ScreenY="414" Ordinal="53.5"/> | |
194 | <Point Identifier="red	point	90" ScreenX="1958" ScreenY="411" Ordinal="53.5"/> | |
195 | <Point Identifier="red	point	91" ScreenX="1983" ScreenY="408" Ordinal="53.5"/> | |
196 | <Point Identifier="red	point	92" ScreenX="2007" ScreenY="405" Ordinal="53.5"/> | |
197 | <Point Identifier="red	point	93" ScreenX="2031" ScreenY="402" Ordinal="53.5"/> | |
198 | <Point Identifier="red	point	94" ScreenX="2056" ScreenY="399" Ordinal="53.5"/> | |
199 | <Point Identifier="red	point	95" ScreenX="2080" ScreenY="396" Ordinal="53.5"/> | |
200 | <Point Identifier="red	point	96" ScreenX="2104" ScreenY="393" Ordinal="53.5"/> | |
201 | <Point Identifier="red	point	97" ScreenX="2128" ScreenY="390" Ordinal="53.5"/> | |
202 | <Point Identifier="red	point	98" ScreenX="2153" ScreenY="388" Ordinal="53.5"/> | |
203 | <Point Identifier="red	point	99" ScreenX="2177" ScreenY="385" Ordinal="53.5"/> | |
204 | <Point Identifier="red	point	100" ScreenX="2202" ScreenY="382" Ordinal="53.5"/> | |
205 | <Point Identifier="red	point	101" ScreenX="2226" ScreenY="379" Ordinal="53.5"/> | |
206 | <Point Identifier="red	point	102" ScreenX="2250" ScreenY="376" Ordinal="53.5"/> | |
207 | <Point Identifier="red	point	103" ScreenX="2275" ScreenY="373" Ordinal="53.5"/> | |
208 | <Point Identifier="red	point	104" ScreenX="2299" ScreenY="371" Ordinal="53.5"/> | |
209 | <Point Identifier="red	point	105" ScreenX="2323" ScreenY="369" Ordinal="53.5"/> | |
210 | <Point Identifier="red	point	106" ScreenX="2348" ScreenY="366" Ordinal="53.5"/> | |
211 | <Point Identifier="red	point	107" ScreenX="2372" ScreenY="364" Ordinal="53.5"/> | |
212 | <Point Identifier="red	point	108" ScreenX="2397" ScreenY="361" Ordinal="53.5"/> | |
213 | <Point Identifier="red	point	109" ScreenX="2421" ScreenY="359" Ordinal="53.5"/> | |
214 | <Point Identifier="red	point	110" ScreenX="2445" ScreenY="356" Ordinal="53.5"/> | |
215 | <Point Identifier="red	point	111" ScreenX="2470" ScreenY="354" Ordinal="53.5"/> | |
216 | <Point Identifier="red	point	112" ScreenX="2494" ScreenY="351" Ordinal="53.5"/> | |
217 | <Point Identifier="red	point	113" ScreenX="2519" ScreenY="349" Ordinal="53.5"/> | |
218 | <Point Identifier="red	point	114" ScreenX="2543" ScreenY="346" Ordinal="53.5"/> | |
219 | <Point Identifier="red	point	115" ScreenX="2568" ScreenY="344" Ordinal="53.5"/> | |
220 | <Point Identifier="red	point	116" ScreenX="2592" ScreenY="341" Ordinal="53.5"/> | |
221 | <Point Identifier="red	point	117" ScreenX="2616" ScreenY="339" Ordinal="53.5"/> | |
222 | <Point Identifier="red	point	118" ScreenX="2641" ScreenY="336" Ordinal="53.5"/> | |
223 | <Point Identifier="red	point	119" ScreenX="2665" ScreenY="334" Ordinal="53.5"/> | |
224 | <Point Identifier="red	point	120" ScreenX="2690" ScreenY="332" Ordinal="53.5"/> | |
225 | <Point Identifier="red	point	121" ScreenX="2714" ScreenY="330" Ordinal="53.5"/> | |
226 | <Point Identifier="red	point	122" ScreenX="2739" ScreenY="328" Ordinal="53.5"/> | |
227 | <Point Identifier="red	point	123" ScreenX="2763" ScreenY="325" Ordinal="53.5"/> | |
228 | <Point Identifier="red	point	124" ScreenX="2788" ScreenY="324" Ordinal="53.5"/> | |
229 | <Point Identifier="red	point	125" ScreenX="2812" ScreenY="321" Ordinal="53.5"/> | |
230 | <Point Identifier="red	point	126" ScreenX="2837" ScreenY="319" Ordinal="53.5"/> | |
231 | <Point Identifier="red	point	127" ScreenX="2861" ScreenY="317" Ordinal="53.5"/> | |
232 | <Point Identifier="red	point	128" ScreenX="2886" ScreenY="315" Ordinal="53.5"/> | |
233 | <Point Identifier="red	point	129" ScreenX="2910" ScreenY="312" Ordinal="53.5"/> | |
234 | <Point Identifier="red	point	130" ScreenX="2935" ScreenY="311" Ordinal="53.5"/> | |
235 | <Point Identifier="red	point	131" ScreenX="2959" ScreenY="309" Ordinal="53.5"/> | |
236 | <Point Identifier="red	point	132" ScreenX="2984" ScreenY="307" Ordinal="53.5"/> | |
237 | <Point Identifier="red	point	133" ScreenX="3008" ScreenY="304" Ordinal="53.5"/> | |
238 | <Point Identifier="red	point	134" ScreenX="3033" ScreenY="302" Ordinal="53.5"/> | |
239 | <Point Identifier="red	point	135" ScreenX="3057" ScreenY="300" Ordinal="53.5"/> | |
240 | <Point Identifier="red	point	136" ScreenX="3082" ScreenY="298" Ordinal="53.5"/> | |
241 | <Point Identifier="red	point	137" ScreenX="3106" ScreenY="296" Ordinal="53.5"/> | |
242 | <Point Identifier="red	point	138" ScreenX="3131" ScreenY="295" Ordinal="53.5"/> | |
243 | <Point Identifier="red	point	139" ScreenX="3156" ScreenY="293" Ordinal="53.5"/> | |
244 | <Point Identifier="red	point	140" ScreenX="3180" ScreenY="291" Ordinal="53.5"/> | |
245 | <Point Identifier="red	point	141" ScreenX="3205" ScreenY="289" Ordinal="53.5"/> | |
246 | <Point Identifier="red	point	142" ScreenX="3229" ScreenY="287" Ordinal="53.5"/> | |
247 | <Point Identifier="red	point	143" ScreenX="3254" ScreenY="285" Ordinal="53.5"/> | |
248 | <Point Identifier="red	point	144" ScreenX="3278" ScreenY="283" Ordinal="53.5"/> | |
249 | <Point Identifier="red	point	145" ScreenX="3303" ScreenY="282" Ordinal="53.5"/> | |
250 | <Point Identifier="red	point	146" ScreenX="3328" ScreenY="280" Ordinal="53.5"/> | |
251 | </Cmd> | |
252 | <Cmd Type="CmdAddPointsGraph" CurveName="red" Description="Add graph points"> | |
253 | <Point Identifier="red	point	173" ScreenX="1033" ScreenY="573" Ordinal="53.5"/> | |
254 | <Point Identifier="red	point	174" ScreenX="1057" ScreenY="566" Ordinal="53.5"/> | |
255 | <Point Identifier="red	point	175" ScreenX="1081" ScreenY="560" Ordinal="53.5"/> | |
256 | <Point Identifier="red	point	176" ScreenX="1105" ScreenY="555" Ordinal="53.5"/> | |
257 | <Point Identifier="red	point	177" ScreenX="1129" ScreenY="550" Ordinal="53.5"/> | |
258 | <Point Identifier="red	point	178" ScreenX="1153" ScreenY="544" Ordinal="53.5"/> | |
259 | <Point Identifier="red	point	179" ScreenX="1176" ScreenY="539" Ordinal="53.5"/> | |
260 | <Point Identifier="red	point	180" ScreenX="1199" ScreenY="534" Ordinal="53.5"/> | |
261 | </Cmd> | |
262 | <Cmd Type="CmdSettingsColorFilter" Description="Filter settings"> | |
263 | <Filter> | |
264 | <ColorFilter Mode="1" HueHigh="3" CurveName="red" ModeString="Hue" IntensityLow="0" ForegroundHigh="10" SaturationLow="50" ValueHigh="50" ForegroundLow="0" SaturationHigh="100" ValueLow="0" IntensityHigh="50" HueLow="0"/> | |
265 | <ColorFilter Mode="2" HueHigh="360" CurveName="blue" ModeString="Intensity" IntensityLow="0" ForegroundHigh="10" SaturationLow="50" ValueHigh="50" ForegroundLow="0" SaturationHigh="100" ValueLow="0" IntensityHigh="50" HueLow="180"/> | |
266 | <ColorFilter Mode="2" HueHigh="360" CurveName="green" ModeString="Intensity" IntensityLow="0" ForegroundHigh="10" SaturationLow="50" ValueHigh="50" ForegroundLow="0" SaturationHigh="100" ValueLow="0" IntensityHigh="50" HueLow="180"/> | |
267 | <ColorFilter Mode="2" HueHigh="360" CurveName="Axes" ModeString="Intensity" IntensityLow="0" ForegroundHigh="10" SaturationLow="50" ValueHigh="50" ForegroundLow="0" SaturationHigh="100" ValueLow="0" IntensityHigh="50" HueLow="180"/> | |
268 | </Filter> | |
269 | <Filter> | |
270 | <ColorFilter Mode="1" HueHigh="3" CurveName="red" ModeString="Hue" IntensityLow="0" ForegroundHigh="10" SaturationLow="50" ValueHigh="50" ForegroundLow="0" SaturationHigh="100" ValueLow="0" IntensityHigh="50" HueLow="0"/> | |
271 | <ColorFilter Mode="2" HueHigh="360" CurveName="blue" ModeString="Intensity" IntensityLow="0" ForegroundHigh="10" SaturationLow="50" ValueHigh="50" ForegroundLow="0" SaturationHigh="100" ValueLow="0" IntensityHigh="50" HueLow="180"/> | |
272 | <ColorFilter Mode="1" HueHigh="122" CurveName="green" ModeString="Hue" IntensityLow="0" ForegroundHigh="10" SaturationLow="50" ValueHigh="50" ForegroundLow="0" SaturationHigh="100" ValueLow="0" IntensityHigh="50" HueLow="115"/> | |
273 | <ColorFilter Mode="2" HueHigh="360" CurveName="Axes" ModeString="Intensity" IntensityLow="0" ForegroundHigh="10" SaturationLow="50" ValueHigh="50" ForegroundLow="0" SaturationHigh="100" ValueLow="0" IntensityHigh="50" HueLow="180"/> | |
274 | </Filter> | |
275 | </Cmd> | |
276 | <Cmd Type="CmdAddPointsGraph" CurveName="green" Description="Add graph points"> | |
277 | <Point Identifier="green	point	181" ScreenX="95" ScreenY="1737" Ordinal="1"/> | |
278 | <Point Identifier="green	point	182" ScreenX="100" ScreenY="1712" Ordinal="1"/> | |
279 | <Point Identifier="green	point	183" ScreenX="103" ScreenY="1688" Ordinal="1"/> | |
280 | <Point Identifier="green	point	184" ScreenX="107" ScreenY="1663" Ordinal="1"/> | |
281 | <Point Identifier="green	point	185" ScreenX="111" ScreenY="1638" Ordinal="1"/> | |
282 | <Point Identifier="green	point	186" ScreenX="115" ScreenY="1614" Ordinal="1"/> | |
283 | <Point Identifier="green	point	187" ScreenX="119" ScreenY="1589" Ordinal="1"/> | |
284 | <Point Identifier="green	point	188" ScreenX="123" ScreenY="1564" Ordinal="1"/> | |
285 | <Point Identifier="green	point	189" ScreenX="127" ScreenY="1540" Ordinal="1"/> | |
286 | <Point Identifier="green	point	190" ScreenX="130" ScreenY="1515" Ordinal="1"/> | |
287 | <Point Identifier="green	point	191" ScreenX="134" ScreenY="1490" Ordinal="1"/> | |
288 | <Point Identifier="green	point	192" ScreenX="140" ScreenY="1466" Ordinal="1"/> | |
289 | <Point Identifier="green	point	193" ScreenX="147" ScreenY="1442" Ordinal="1"/> | |
290 | <Point Identifier="green	point	194" ScreenX="153" ScreenY="1418" Ordinal="1"/> | |
291 | <Point Identifier="green	point	195" ScreenX="160" ScreenY="1393" Ordinal="1"/> | |
292 | <Point Identifier="green	point	196" ScreenX="167" ScreenY="1369" Ordinal="1"/> | |
293 | <Point Identifier="green	point	197" ScreenX="173" ScreenY="1345" Ordinal="1"/> | |
294 | <Point Identifier="green	point	198" ScreenX="181" ScreenY="1322" Ordinal="1"/> | |
295 | <Point Identifier="green	point	199" ScreenX="190" ScreenY="1298" Ordinal="1"/> | |
296 | <Point Identifier="green	point	200" ScreenX="199" ScreenY="1275" Ordinal="1"/> | |
297 | <Point Identifier="green	point	201" ScreenX="208" ScreenY="1251" Ordinal="1"/> | |
298 | <Point Identifier="green	point	202" ScreenX="216" ScreenY="1228" Ordinal="1"/> | |
299 | <Point Identifier="green	point	203" ScreenX="228" ScreenY="1206" Ordinal="1"/> | |
300 | <Point Identifier="green	point	204" ScreenX="239" ScreenY="1183" Ordinal="1"/> | |
301 | <Point Identifier="green	point	205" ScreenX="250" ScreenY="1161" Ordinal="1"/> | |
302 | <Point Identifier="green	point	206" ScreenX="262" ScreenY="1139" Ordinal="1"/> | |
303 | <Point Identifier="green	point	207" ScreenX="275" ScreenY="1117" Ordinal="1"/> | |
304 | <Point Identifier="green	point	208" ScreenX="287" ScreenY="1096" Ordinal="1"/> | |
305 | <Point Identifier="green	point	209" ScreenX="301" ScreenY="1075" Ordinal="1"/> | |
306 | <Point Identifier="green	point	210" ScreenX="316" ScreenY="1055" Ordinal="1"/> | |
307 | <Point Identifier="green	point	211" ScreenX="330" ScreenY="1034" Ordinal="1"/> | |
308 | <Point Identifier="green	point	212" ScreenX="346" ScreenY="1015" Ordinal="1"/> | |
309 | <Point Identifier="green	point	213" ScreenX="361" ScreenY="995" Ordinal="1"/> | |
310 | <Point Identifier="green	point	214" ScreenX="378" ScreenY="976" Ordinal="1"/> | |
311 | <Point Identifier="green	point	215" ScreenX="394" ScreenY="958" Ordinal="1"/> | |
312 | <Point Identifier="green	point	216" ScreenX="411" ScreenY="940" Ordinal="1"/> | |
313 | <Point Identifier="green	point	217" ScreenX="429" ScreenY="922" Ordinal="1"/> | |
314 | <Point Identifier="green	point	218" ScreenX="447" ScreenY="904" Ordinal="1"/> | |
315 | <Point Identifier="green	point	219" ScreenX="465" ScreenY="888" Ordinal="1"/> | |
316 | <Point Identifier="green	point	220" ScreenX="484" ScreenY="872" Ordinal="1"/> | |
317 | <Point Identifier="green	point	221" ScreenX="503" ScreenY="856" Ordinal="1"/> | |
318 | <Point Identifier="green	point	222" ScreenX="522" ScreenY="841" Ordinal="1"/> | |
319 | <Point Identifier="green	point	223" ScreenX="542" ScreenY="825" Ordinal="1"/> | |
320 | <Point Identifier="green	point	224" ScreenX="562" ScreenY="811" Ordinal="1"/> | |
321 | <Point Identifier="green	point	225" ScreenX="582" ScreenY="796" Ordinal="1"/> | |
322 | <Point Identifier="green	point	226" ScreenX="603" ScreenY="782" Ordinal="1"/> | |
323 | <Point Identifier="green	point	227" ScreenX="624" ScreenY="769" Ordinal="1"/> | |
324 | <Point Identifier="green	point	228" ScreenX="645" ScreenY="756" Ordinal="1"/> | |
325 | <Point Identifier="green	point	229" ScreenX="666" ScreenY="743" Ordinal="1"/> | |
326 | <Point Identifier="green	point	230" ScreenX="688" ScreenY="730" Ordinal="1"/> | |
327 | <Point Identifier="green	point	231" ScreenX="710" ScreenY="718" Ordinal="1"/> | |
328 | <Point Identifier="green	point	232" ScreenX="732" ScreenY="706" Ordinal="1"/> | |
329 | <Point Identifier="green	point	233" ScreenX="754" ScreenY="695" Ordinal="1"/> | |
330 | <Point Identifier="green	point	234" ScreenX="776" ScreenY="683" Ordinal="1"/> | |
331 | <Point Identifier="green	point	235" ScreenX="799" ScreenY="672" Ordinal="1"/> | |
332 | <Point Identifier="green	point	236" ScreenX="821" ScreenY="661" Ordinal="1"/> | |
333 | <Point Identifier="green	point	237" ScreenX="844" ScreenY="650" Ordinal="1"/> | |
334 | <Point Identifier="green	point	238" ScreenX="866" ScreenY="640" Ordinal="1"/> | |
335 | <Point Identifier="green	point	239" ScreenX="889" ScreenY="629" Ordinal="1"/> | |
336 | <Point Identifier="green	point	240" ScreenX="912" ScreenY="620" Ordinal="1"/> | |
337 | <Point Identifier="green	point	241" ScreenX="935" ScreenY="610" Ordinal="1"/> | |
338 | <Point Identifier="green	point	242" ScreenX="958" ScreenY="600" Ordinal="1"/> | |
339 | <Point Identifier="green	point	243" ScreenX="982" ScreenY="592" Ordinal="1"/> | |
340 | <Point Identifier="green	point	244" ScreenX="1005" ScreenY="583" Ordinal="1"/> | |
341 | <Point Identifier="green	point	245" ScreenX="1028" ScreenY="574" Ordinal="1"/> | |
342 | <Point Identifier="green	point	246" ScreenX="1051" ScreenY="565" Ordinal="1"/> | |
343 | <Point Identifier="green	point	247" ScreenX="1075" ScreenY="557" Ordinal="1"/> | |
344 | <Point Identifier="green	point	248" ScreenX="1098" ScreenY="549" Ordinal="1"/> | |
345 | <Point Identifier="green	point	249" ScreenX="1122" ScreenY="540" Ordinal="1"/> | |
346 | <Point Identifier="green	point	250" ScreenX="1145" ScreenY="533" Ordinal="1"/> | |
347 | <Point Identifier="green	point	251" ScreenX="1169" ScreenY="525" Ordinal="1"/> | |
348 | <Point Identifier="green	point	252" ScreenX="1192" ScreenY="517" Ordinal="1"/> | |
349 | <Point Identifier="green	point	253" ScreenX="1216" ScreenY="510" Ordinal="1"/> | |
350 | <Point Identifier="green	point	254" ScreenX="1239" ScreenY="503" Ordinal="1"/> | |
351 | <Point Identifier="green	point	255" ScreenX="1262" ScreenY="496" Ordinal="1"/> | |
352 | <Point Identifier="green	point	256" ScreenX="1285" ScreenY="489" Ordinal="1"/> | |
353 | <Point Identifier="green	point	257" ScreenX="1308" ScreenY="482" Ordinal="1"/> | |
354 | <Point Identifier="green	point	258" ScreenX="1331" ScreenY="475" Ordinal="1"/> | |
355 | <Point Identifier="green	point	259" ScreenX="1353" ScreenY="469" Ordinal="1"/> | |
356 | <Point Identifier="green	point	260" ScreenX="1376" ScreenY="462" Ordinal="1"/> | |
357 | <Point Identifier="green	point	261" ScreenX="1399" ScreenY="456" Ordinal="1"/> | |
358 | </Cmd> | |
359 | <Cmd Type="CmdAddPointsGraph" CurveName="green" Description="Add graph points"> | |
360 | <Point Identifier="green	point	262" ScreenX="1436" ScreenY="446" Ordinal="81.5"/> | |
361 | <Point Identifier="green	point	263" ScreenX="1460" ScreenY="440" Ordinal="81.5"/> | |
362 | <Point Identifier="green	point	264" ScreenX="1484" ScreenY="434" Ordinal="81.5"/> | |
363 | <Point Identifier="green	point	265" ScreenX="1508" ScreenY="428" Ordinal="81.5"/> | |
364 | <Point Identifier="green	point	266" ScreenX="1532" ScreenY="422" Ordinal="81.5"/> | |
365 | <Point Identifier="green	point	267" ScreenX="1555" ScreenY="416" Ordinal="81.5"/> | |
366 | <Point Identifier="green	point	268" ScreenX="1579" ScreenY="410" Ordinal="81.5"/> | |
367 | <Point Identifier="green	point	269" ScreenX="1603" ScreenY="405" Ordinal="81.5"/> | |
368 | <Point Identifier="green	point	270" ScreenX="1626" ScreenY="399" Ordinal="81.5"/> | |
369 | <Point Identifier="green	point	271" ScreenX="1650" ScreenY="394" Ordinal="81.5"/> | |
370 | <Point Identifier="green	point	272" ScreenX="1674" ScreenY="389" Ordinal="81.5"/> | |
371 | <Point Identifier="green	point	273" ScreenX="1698" ScreenY="383" Ordinal="81.5"/> | |
372 | <Point Identifier="green	point	274" ScreenX="1721" ScreenY="378" Ordinal="81.5"/> | |
373 | <Point Identifier="green	point	275" ScreenX="1745" ScreenY="373" Ordinal="81.5"/> | |
374 | <Point Identifier="green	point	276" ScreenX="1769" ScreenY="368" Ordinal="81.5"/> | |
375 | <Point Identifier="green	point	277" ScreenX="1793" ScreenY="363" Ordinal="81.5"/> | |
376 | <Point Identifier="green	point	278" ScreenX="1817" ScreenY="358" Ordinal="81.5"/> | |
377 | <Point Identifier="green	point	279" ScreenX="1841" ScreenY="353" Ordinal="81.5"/> | |
378 | <Point Identifier="green	point	280" ScreenX="1864" ScreenY="348" Ordinal="81.5"/> | |
379 | <Point Identifier="green	point	281" ScreenX="1888" ScreenY="343" Ordinal="81.5"/> | |
380 | <Point Identifier="green	point	282" ScreenX="1912" ScreenY="338" Ordinal="81.5"/> | |
381 | <Point Identifier="green	point	283" ScreenX="1936" ScreenY="334" Ordinal="81.5"/> | |
382 | <Point Identifier="green	point	284" ScreenX="1960" ScreenY="330" Ordinal="81.5"/> | |
383 | <Point Identifier="green	point	285" ScreenX="1984" ScreenY="325" Ordinal="81.5"/> | |
384 | <Point Identifier="green	point	286" ScreenX="2008" ScreenY="320" Ordinal="81.5"/> | |
385 | <Point Identifier="green	point	287" ScreenX="2032" ScreenY="316" Ordinal="81.5"/> | |
386 | <Point Identifier="green	point	288" ScreenX="2056" ScreenY="311" Ordinal="81.5"/> | |
387 | <Point Identifier="green	point	289" ScreenX="2080" ScreenY="307" Ordinal="81.5"/> | |
388 | <Point Identifier="green	point	290" ScreenX="2104" ScreenY="302" Ordinal="81.5"/> | |
389 | <Point Identifier="green	point	291" ScreenX="2128" ScreenY="298" Ordinal="81.5"/> | |
390 | <Point Identifier="green	point	292" ScreenX="2152" ScreenY="294" Ordinal="81.5"/> | |
391 | <Point Identifier="green	point	293" ScreenX="2176" ScreenY="290" Ordinal="81.5"/> | |
392 | <Point Identifier="green	point	294" ScreenX="2200" ScreenY="286" Ordinal="81.5"/> | |
393 | <Point Identifier="green	point	295" ScreenX="2224" ScreenY="282" Ordinal="81.5"/> | |
394 | <Point Identifier="green	point	296" ScreenX="2248" ScreenY="278" Ordinal="81.5"/> | |
395 | <Point Identifier="green	point	297" ScreenX="2272" ScreenY="274" Ordinal="81.5"/> | |
396 | <Point Identifier="green	point	298" ScreenX="2296" ScreenY="270" Ordinal="81.5"/> | |
397 | <Point Identifier="green	point	299" ScreenX="2320" ScreenY="266" Ordinal="81.5"/> | |
398 | <Point Identifier="green	point	300" ScreenX="2344" ScreenY="263" Ordinal="81.5"/> | |
399 | <Point Identifier="green	point	301" ScreenX="2368" ScreenY="258" Ordinal="81.5"/> | |
400 | <Point Identifier="green	point	302" ScreenX="2392" ScreenY="254" Ordinal="81.5"/> | |
401 | <Point Identifier="green	point	303" ScreenX="2416" ScreenY="251" Ordinal="81.5"/> | |
402 | <Point Identifier="green	point	304" ScreenX="2440" ScreenY="247" Ordinal="81.5"/> | |
403 | <Point Identifier="green	point	305" ScreenX="2465" ScreenY="243" Ordinal="81.5"/> | |
404 | <Point Identifier="green	point	306" ScreenX="2489" ScreenY="240" Ordinal="81.5"/> | |
405 | <Point Identifier="green	point	307" ScreenX="2513" ScreenY="236" Ordinal="81.5"/> | |
406 | <Point Identifier="green	point	308" ScreenX="2537" ScreenY="233" Ordinal="81.5"/> | |
407 | <Point Identifier="green	point	309" ScreenX="2561" ScreenY="230" Ordinal="81.5"/> | |
408 | <Point Identifier="green	point	310" ScreenX="2586" ScreenY="226" Ordinal="81.5"/> | |
409 | <Point Identifier="green	point	311" ScreenX="2610" ScreenY="222" Ordinal="81.5"/> | |
410 | <Point Identifier="green	point	312" ScreenX="2634" ScreenY="219" Ordinal="81.5"/> | |
411 | <Point Identifier="green	point	313" ScreenX="2658" ScreenY="216" Ordinal="81.5"/> | |
412 | <Point Identifier="green	point	314" ScreenX="2682" ScreenY="212" Ordinal="81.5"/> | |
413 | <Point Identifier="green	point	315" ScreenX="2707" ScreenY="209" Ordinal="81.5"/> | |
414 | <Point Identifier="green	point	316" ScreenX="2731" ScreenY="206" Ordinal="81.5"/> | |
415 | <Point Identifier="green	point	317" ScreenX="2755" ScreenY="202" Ordinal="81.5"/> | |
416 | <Point Identifier="green	point	318" ScreenX="2779" ScreenY="199" Ordinal="81.5"/> | |
417 | <Point Identifier="green	point	319" ScreenX="2803" ScreenY="195" Ordinal="81.5"/> | |
418 | <Point Identifier="green	point	320" ScreenX="2828" ScreenY="192" Ordinal="81.5"/> | |
419 | <Point Identifier="green	point	321" ScreenX="2852" ScreenY="189" Ordinal="81.5"/> | |
420 | <Point Identifier="green	point	322" ScreenX="2876" ScreenY="186" Ordinal="81.5"/> | |
421 | <Point Identifier="green	point	323" ScreenX="2900" ScreenY="183" Ordinal="81.5"/> | |
422 | <Point Identifier="green	point	324" ScreenX="2925" ScreenY="180" Ordinal="81.5"/> | |
423 | <Point Identifier="green	point	325" ScreenX="2949" ScreenY="177" Ordinal="81.5"/> | |
424 | <Point Identifier="green	point	326" ScreenX="2973" ScreenY="174" Ordinal="81.5"/> | |
425 | <Point Identifier="green	point	327" ScreenX="2998" ScreenY="171" Ordinal="81.5"/> | |
426 | <Point Identifier="green	point	328" ScreenX="3022" ScreenY="168" Ordinal="81.5"/> | |
427 | <Point Identifier="green	point	329" ScreenX="3046" ScreenY="165" Ordinal="81.5"/> | |
428 | <Point Identifier="green	point	330" ScreenX="3070" ScreenY="162" Ordinal="81.5"/> | |
429 | <Point Identifier="green	point	331" ScreenX="3095" ScreenY="160" Ordinal="81.5"/> | |
430 | <Point Identifier="green	point	332" ScreenX="3119" ScreenY="156" Ordinal="81.5"/> | |
431 | <Point Identifier="green	point	333" ScreenX="3143" ScreenY="153" Ordinal="81.5"/> | |
432 | <Point Identifier="green	point	334" ScreenX="3168" ScreenY="150" Ordinal="81.5"/> | |
433 | <Point Identifier="green	point	335" ScreenX="3192" ScreenY="148" Ordinal="81.5"/> | |
434 | <Point Identifier="green	point	336" ScreenX="3216" ScreenY="145" Ordinal="81.5"/> | |
435 | <Point Identifier="green	point	337" ScreenX="3241" ScreenY="142" Ordinal="81.5"/> | |
436 | <Point Identifier="green	point	338" ScreenX="3265" ScreenY="139" Ordinal="81.5"/> | |
437 | <Point Identifier="green	point	339" ScreenX="3290" ScreenY="137" Ordinal="81.5"/> | |
438 | </Cmd> | |
439 | <Cmd Type="CmdSettingsColorFilter" Description="Filter settings"> | |
440 | <Filter> | |
441 | <ColorFilter Mode="1" HueHigh="3" CurveName="red" ModeString="Hue" IntensityLow="0" ForegroundHigh="10" SaturationLow="50" ValueHigh="50" ForegroundLow="0" SaturationHigh="100" ValueLow="0" IntensityHigh="50" HueLow="0"/> | |
442 | <ColorFilter Mode="2" HueHigh="360" CurveName="blue" ModeString="Intensity" IntensityLow="0" ForegroundHigh="10" SaturationLow="50" ValueHigh="50" ForegroundLow="0" SaturationHigh="100" ValueLow="0" IntensityHigh="50" HueLow="180"/> | |
443 | <ColorFilter Mode="1" HueHigh="122" CurveName="green" ModeString="Hue" IntensityLow="0" ForegroundHigh="10" SaturationLow="50" ValueHigh="50" ForegroundLow="0" SaturationHigh="100" ValueLow="0" IntensityHigh="50" HueLow="115"/> | |
444 | <ColorFilter Mode="2" HueHigh="360" CurveName="Axes" ModeString="Intensity" IntensityLow="0" ForegroundHigh="10" SaturationLow="50" ValueHigh="50" ForegroundLow="0" SaturationHigh="100" ValueLow="0" IntensityHigh="50" HueLow="180"/> | |
445 | </Filter> | |
446 | <Filter> | |
447 | <ColorFilter Mode="1" HueHigh="3" CurveName="red" ModeString="Hue" IntensityLow="0" ForegroundHigh="10" SaturationLow="50" ValueHigh="50" ForegroundLow="0" SaturationHigh="100" ValueLow="0" IntensityHigh="50" HueLow="0"/> | |
448 | <ColorFilter Mode="1" HueHigh="241" CurveName="blue" ModeString="Hue" IntensityLow="0" ForegroundHigh="10" SaturationLow="50" ValueHigh="50" ForegroundLow="0" SaturationHigh="100" ValueLow="0" IntensityHigh="50" HueLow="233"/> | |
449 | <ColorFilter Mode="1" HueHigh="122" CurveName="green" ModeString="Hue" IntensityLow="0" ForegroundHigh="10" SaturationLow="50" ValueHigh="50" ForegroundLow="0" SaturationHigh="100" ValueLow="0" IntensityHigh="50" HueLow="115"/> | |
450 | <ColorFilter Mode="2" HueHigh="360" CurveName="Axes" ModeString="Intensity" IntensityLow="0" ForegroundHigh="10" SaturationLow="50" ValueHigh="50" ForegroundLow="0" SaturationHigh="100" ValueLow="0" IntensityHigh="50" HueLow="180"/> | |
451 | </Filter> | |
452 | </Cmd> | |
453 | <Cmd Type="CmdAddPointsGraph" CurveName="blue" Description="Add graph points"> | |
454 | <Point Identifier="blue	point	368" ScreenX="119" ScreenY="1958" Ordinal="1"/> | |
455 | <Point Identifier="blue	point	369" ScreenX="123" ScreenY="1933" Ordinal="1"/> | |
456 | <Point Identifier="blue	point	370" ScreenX="126" ScreenY="1908" Ordinal="1"/> | |
457 | <Point Identifier="blue	point	371" ScreenX="129" ScreenY="1884" Ordinal="1"/> | |
458 | <Point Identifier="blue	point	372" ScreenX="132" ScreenY="1859" Ordinal="1"/> | |
459 | <Point Identifier="blue	point	373" ScreenX="135" ScreenY="1834" Ordinal="1"/> | |
460 | <Point Identifier="blue	point	374" ScreenX="139" ScreenY="1809" Ordinal="1"/> | |
461 | <Point Identifier="blue	point	375" ScreenX="144" ScreenY="1785" Ordinal="1"/> | |
462 | <Point Identifier="blue	point	376" ScreenX="149" ScreenY="1760" Ordinal="1"/> | |
463 | <Point Identifier="blue	point	377" ScreenX="154" ScreenY="1736" Ordinal="1"/> | |
464 | <Point Identifier="blue	point	378" ScreenX="159" ScreenY="1711" Ordinal="1"/> | |
465 | <Point Identifier="blue	point	379" ScreenX="164" ScreenY="1687" Ordinal="1"/> | |
466 | <Point Identifier="blue	point	380" ScreenX="169" ScreenY="1662" Ordinal="1"/> | |
467 | <Point Identifier="blue	point	381" ScreenX="174" ScreenY="1638" Ordinal="1"/> | |
468 | <Point Identifier="blue	point	382" ScreenX="181" ScreenY="1614" Ordinal="1"/> | |
469 | <Point Identifier="blue	point	383" ScreenX="187" ScreenY="1590" Ordinal="1"/> | |
470 | <Point Identifier="blue	point	384" ScreenX="194" ScreenY="1566" Ordinal="1"/> | |
471 | <Point Identifier="blue	point	385" ScreenX="201" ScreenY="1542" Ordinal="1"/> | |
472 | <Point Identifier="blue	point	386" ScreenX="208" ScreenY="1518" Ordinal="1"/> | |
473 | <Point Identifier="blue	point	387" ScreenX="215" ScreenY="1494" Ordinal="1"/> | |
474 | <Point Identifier="blue	point	388" ScreenX="223" ScreenY="1470" Ordinal="1"/> | |
475 | <Point Identifier="blue	point	389" ScreenX="232" ScreenY="1447" Ordinal="1"/> | |
476 | <Point Identifier="blue	point	390" ScreenX="241" ScreenY="1423" Ordinal="1"/> | |
477 | <Point Identifier="blue	point	391" ScreenX="249" ScreenY="1400" Ordinal="1"/> | |
478 | <Point Identifier="blue	point	392" ScreenX="258" ScreenY="1376" Ordinal="1"/> | |
479 | <Point Identifier="blue	point	393" ScreenX="269" ScreenY="1354" Ordinal="1"/> | |
480 | <Point Identifier="blue	point	394" ScreenX="279" ScreenY="1331" Ordinal="1"/> | |
481 | <Point Identifier="blue	point	395" ScreenX="289" ScreenY="1308" Ordinal="1"/> | |
482 | <Point Identifier="blue	point	396" ScreenX="300" ScreenY="1286" Ordinal="1"/> | |
483 | <Point Identifier="blue	point	397" ScreenX="312" ScreenY="1264" Ordinal="1"/> | |
484 | <Point Identifier="blue	point	398" ScreenX="324" ScreenY="1241" Ordinal="1"/> | |
485 | <Point Identifier="blue	point	399" ScreenX="336" ScreenY="1219" Ordinal="1"/> | |
486 | <Point Identifier="blue	point	400" ScreenX="348" ScreenY="1198" Ordinal="1"/> | |
487 | <Point Identifier="blue	point	401" ScreenX="361" ScreenY="1177" Ordinal="1"/> | |
488 | <Point Identifier="blue	point	402" ScreenX="374" ScreenY="1155" Ordinal="1"/> | |
489 | <Point Identifier="blue	point	403" ScreenX="389" ScreenY="1135" Ordinal="1"/> | |
490 | <Point Identifier="blue	point	404" ScreenX="403" ScreenY="1115" Ordinal="1"/> | |
491 | <Point Identifier="blue	point	405" ScreenX="418" ScreenY="1094" Ordinal="1"/> | |
492 | <Point Identifier="blue	point	406" ScreenX="433" ScreenY="1075" Ordinal="1"/> | |
493 | <Point Identifier="blue	point	407" ScreenX="448" ScreenY="1055" Ordinal="1"/> | |
494 | <Point Identifier="blue	point	408" ScreenX="465" ScreenY="1036" Ordinal="1"/> | |
495 | <Point Identifier="blue	point	409" ScreenX="481" ScreenY="1017" Ordinal="1"/> | |
496 | <Point Identifier="blue	point	410" ScreenX="498" ScreenY="998" Ordinal="1"/> | |
497 | <Point Identifier="blue	point	411" ScreenX="514" ScreenY="980" Ordinal="1"/> | |
498 | <Point Identifier="blue	point	412" ScreenX="531" ScreenY="961" Ordinal="1"/> | |
499 | <Point Identifier="blue	point	413" ScreenX="549" ScreenY="943" Ordinal="1"/> | |
500 | <Point Identifier="blue	point	414" ScreenX="567" ScreenY="926" Ordinal="1"/> | |
501 | <Point Identifier="blue	point	415" ScreenX="585" ScreenY="909" Ordinal="1"/> | |
502 | <Point Identifier="blue	point	416" ScreenX="603" ScreenY="893" Ordinal="1"/> | |
503 | <Point Identifier="blue	point	417" ScreenX="622" ScreenY="876" Ordinal="1"/> | |
504 | <Point Identifier="blue	point	418" ScreenX="641" ScreenY="861" Ordinal="1"/> | |
505 | <Point Identifier="blue	point	419" ScreenX="661" ScreenY="845" Ordinal="1"/> | |
506 | <Point Identifier="blue	point	420" ScreenX="680" ScreenY="830" Ordinal="1"/> | |
507 | <Point Identifier="blue	point	421" ScreenX="700" ScreenY="815" Ordinal="1"/> | |
508 | <Point Identifier="blue	point	422" ScreenX="719" ScreenY="800" Ordinal="1"/> | |
509 | <Point Identifier="blue	point	423" ScreenX="739" ScreenY="786" Ordinal="1"/> | |
510 | <Point Identifier="blue	point	424" ScreenX="760" ScreenY="772" Ordinal="1"/> | |
511 | <Point Identifier="blue	point	425" ScreenX="780" ScreenY="757" Ordinal="1"/> | |
512 | <Point Identifier="blue	point	426" ScreenX="801" ScreenY="743" Ordinal="1"/> | |
513 | <Point Identifier="blue	point	427" ScreenX="822" ScreenY="730" Ordinal="1"/> | |
514 | <Point Identifier="blue	point	428" ScreenX="843" ScreenY="717" Ordinal="1"/> | |
515 | <Point Identifier="blue	point	429" ScreenX="865" ScreenY="704" Ordinal="1"/> | |
516 | <Point Identifier="blue	point	430" ScreenX="886" ScreenY="691" Ordinal="1"/> | |
517 | <Point Identifier="blue	point	431" ScreenX="908" ScreenY="679" Ordinal="1"/> | |
518 | <Point Identifier="blue	point	432" ScreenX="929" ScreenY="667" Ordinal="1"/> | |
519 | <Point Identifier="blue	point	433" ScreenX="952" ScreenY="655" Ordinal="1"/> | |
520 | <Point Identifier="blue	point	434" ScreenX="974" ScreenY="643" Ordinal="1"/> | |
521 | <Point Identifier="blue	point	435" ScreenX="996" ScreenY="631" Ordinal="1"/> | |
522 | <Point Identifier="blue	point	436" ScreenX="1018" ScreenY="620" Ordinal="1"/> | |
523 | <Point Identifier="blue	point	437" ScreenX="1040" ScreenY="609" Ordinal="1"/> | |
524 | <Point Identifier="blue	point	438" ScreenX="1063" ScreenY="598" Ordinal="1"/> | |
525 | <Point Identifier="blue	point	439" ScreenX="1085" ScreenY="587" Ordinal="1"/> | |
526 | <Point Identifier="blue	point	440" ScreenX="1108" ScreenY="576" Ordinal="1"/> | |
527 | <Point Identifier="blue	point	441" ScreenX="1131" ScreenY="566" Ordinal="1"/> | |
528 | <Point Identifier="blue	point	442" ScreenX="1154" ScreenY="556" Ordinal="1"/> | |
529 | <Point Identifier="blue	point	443" ScreenX="1176" ScreenY="546" Ordinal="1"/> | |
530 | <Point Identifier="blue	point	444" ScreenX="1199" ScreenY="536" Ordinal="1"/> | |
531 | <Point Identifier="blue	point	445" ScreenX="1223" ScreenY="527" Ordinal="1"/> | |
532 | <Point Identifier="blue	point	446" ScreenX="1246" ScreenY="517" Ordinal="1"/> | |
533 | <Point Identifier="blue	point	447" ScreenX="1269" ScreenY="508" Ordinal="1"/> | |
534 | <Point Identifier="blue	point	448" ScreenX="1292" ScreenY="498" Ordinal="1"/> | |
535 | <Point Identifier="blue	point	449" ScreenX="1315" ScreenY="489" Ordinal="1"/> | |
536 | <Point Identifier="blue	point	450" ScreenX="1339" ScreenY="480" Ordinal="1"/> | |
537 | <Point Identifier="blue	point	451" ScreenX="1362" ScreenY="472" Ordinal="1"/> | |
538 | <Point Identifier="blue	point	452" ScreenX="1385" ScreenY="463" Ordinal="1"/> | |
539 | <Point Identifier="blue	point	453" ScreenX="1409" ScreenY="455" Ordinal="1"/> | |
540 | <Point Identifier="blue	point	454" ScreenX="1432" ScreenY="446" Ordinal="1"/> | |
541 | <Point Identifier="blue	point	455" ScreenX="1456" ScreenY="438" Ordinal="1"/> | |
542 | <Point Identifier="blue	point	456" ScreenX="1479" ScreenY="430" Ordinal="1"/> | |
543 | <Point Identifier="blue	point	457" ScreenX="1503" ScreenY="422" Ordinal="1"/> | |
544 | <Point Identifier="blue	point	458" ScreenX="1526" ScreenY="414" Ordinal="1"/> | |
545 | <Point Identifier="blue	point	459" ScreenX="1550" ScreenY="407" Ordinal="1"/> | |
546 | <Point Identifier="blue	point	460" ScreenX="1573" ScreenY="399" Ordinal="1"/> | |
547 | <Point Identifier="blue	point	461" ScreenX="1597" ScreenY="391" Ordinal="1"/> | |
548 | <Point Identifier="blue	point	462" ScreenX="1621" ScreenY="384" Ordinal="1"/> | |
549 | <Point Identifier="blue	point	463" ScreenX="1644" ScreenY="377" Ordinal="1"/> | |
550 | <Point Identifier="blue	point	464" ScreenX="1668" ScreenY="369" Ordinal="1"/> | |
551 | <Point Identifier="blue	point	465" ScreenX="1692" ScreenY="362" Ordinal="1"/> | |
552 | <Point Identifier="blue	point	466" ScreenX="1716" ScreenY="355" Ordinal="1"/> | |
553 | <Point Identifier="blue	point	467" ScreenX="1740" ScreenY="348" Ordinal="1"/> | |
554 | <Point Identifier="blue	point	468" ScreenX="1764" ScreenY="342" Ordinal="1"/> | |
555 | <Point Identifier="blue	point	469" ScreenX="1787" ScreenY="335" Ordinal="1"/> | |
556 | <Point Identifier="blue	point	470" ScreenX="1811" ScreenY="328" Ordinal="1"/> | |
557 | <Point Identifier="blue	point	471" ScreenX="1835" ScreenY="322" Ordinal="1"/> | |
558 | <Point Identifier="blue	point	472" ScreenX="1859" ScreenY="315" Ordinal="1"/> | |
559 | <Point Identifier="blue	point	473" ScreenX="1883" ScreenY="309" Ordinal="1"/> | |
560 | <Point Identifier="blue	point	474" ScreenX="1906" ScreenY="303" Ordinal="1"/> | |
561 | <Point Identifier="blue	point	475" ScreenX="1930" ScreenY="297" Ordinal="1"/> | |
562 | <Point Identifier="blue	point	476" ScreenX="1954" ScreenY="291" Ordinal="1"/> | |
563 | <Point Identifier="blue	point	477" ScreenX="1979" ScreenY="285" Ordinal="1"/> | |
564 | <Point Identifier="blue	point	478" ScreenX="2003" ScreenY="278" Ordinal="1"/> | |
565 | <Point Identifier="blue	point	479" ScreenX="2026" ScreenY="272" Ordinal="1"/> | |
566 | <Point Identifier="blue	point	480" ScreenX="2050" ScreenY="267" Ordinal="1"/> | |
567 | <Point Identifier="blue	point	481" ScreenX="2073" ScreenY="261" Ordinal="1"/> | |
568 | <Point Identifier="blue	point	482" ScreenX="2097" ScreenY="255" Ordinal="1"/> | |
569 | <Point Identifier="blue	point	483" ScreenX="2121" ScreenY="250" Ordinal="1"/> | |
570 | <Point Identifier="blue	point	484" ScreenX="2145" ScreenY="244" Ordinal="1"/> | |
571 | <Point Identifier="blue	point	485" ScreenX="2168" ScreenY="238" Ordinal="1"/> | |
572 | <Point Identifier="blue	point	486" ScreenX="2192" ScreenY="233" Ordinal="1"/> | |
573 | <Point Identifier="blue	point	487" ScreenX="2216" ScreenY="228" Ordinal="1"/> | |
574 | <Point Identifier="blue	point	488" ScreenX="2240" ScreenY="223" Ordinal="1"/> | |
575 | <Point Identifier="blue	point	489" ScreenX="2263" ScreenY="217" Ordinal="1"/> | |
576 | <Point Identifier="blue	point	490" ScreenX="2287" ScreenY="212" Ordinal="1"/> | |
577 | <Point Identifier="blue	point	491" ScreenX="2311" ScreenY="207" Ordinal="1"/> | |
578 | <Point Identifier="blue	point	492" ScreenX="2335" ScreenY="202" Ordinal="1"/> | |
579 | <Point Identifier="blue	point	493" ScreenX="2358" ScreenY="197" Ordinal="1"/> | |
580 | <Point Identifier="blue	point	494" ScreenX="2382" ScreenY="191" Ordinal="1"/> | |
581 | <Point Identifier="blue	point	495" ScreenX="2406" ScreenY="187" Ordinal="1"/> | |
582 | <Point Identifier="blue	point	496" ScreenX="2430" ScreenY="182" Ordinal="1"/> | |
583 | <Point Identifier="blue	point	497" ScreenX="2454" ScreenY="177" Ordinal="1"/> | |
584 | <Point Identifier="blue	point	498" ScreenX="2477" ScreenY="172" Ordinal="1"/> | |
585 | <Point Identifier="blue	point	499" ScreenX="2501" ScreenY="167" Ordinal="1"/> | |
586 | <Point Identifier="blue	point	500" ScreenX="2525" ScreenY="163" Ordinal="1"/> | |
587 | <Point Identifier="blue	point	501" ScreenX="2549" ScreenY="158" Ordinal="1"/> | |
588 | <Point Identifier="blue	point	502" ScreenX="2573" ScreenY="153" Ordinal="1"/> | |
589 | <Point Identifier="blue	point	503" ScreenX="2597" ScreenY="149" Ordinal="1"/> | |
590 | <Point Identifier="blue	point	504" ScreenX="2621" ScreenY="144" Ordinal="1"/> | |
591 | <Point Identifier="blue	point	505" ScreenX="2645" ScreenY="140" Ordinal="1"/> | |
592 | <Point Identifier="blue	point	506" ScreenX="2669" ScreenY="135" Ordinal="1"/> | |
593 | <Point Identifier="blue	point	507" ScreenX="2693" ScreenY="131" Ordinal="1"/> | |
594 | <Point Identifier="blue	point	508" ScreenX="2716" ScreenY="127" Ordinal="1"/> | |
595 | <Point Identifier="blue	point	509" ScreenX="2740" ScreenY="123" Ordinal="1"/> | |
596 | <Point Identifier="blue	point	510" ScreenX="2763" ScreenY="118" Ordinal="1"/> | |
597 | <Point Identifier="blue	point	511" ScreenX="2787" ScreenY="114" Ordinal="1"/> | |
598 | <Point Identifier="blue	point	512" ScreenX="2811" ScreenY="110" Ordinal="1"/> | |
599 | <Point Identifier="blue	point	513" ScreenX="2834" ScreenY="106" Ordinal="1"/> | |
600 | <Point Identifier="blue	point	514" ScreenX="2858" ScreenY="102" Ordinal="1"/> | |
601 | <Point Identifier="blue	point	515" ScreenX="2881" ScreenY="98" Ordinal="1"/> | |
602 | <Point Identifier="blue	point	516" ScreenX="2905" ScreenY="93" Ordinal="1"/> | |
603 | <Point Identifier="blue	point	517" ScreenX="2929" ScreenY="89" Ordinal="1"/> | |
604 | <Point Identifier="blue	point	518" ScreenX="2953" ScreenY="85" Ordinal="1"/> | |
605 | <Point Identifier="blue	point	519" ScreenX="2976" ScreenY="82" Ordinal="1"/> | |
606 | <Point Identifier="blue	point	520" ScreenX="3000" ScreenY="78" Ordinal="1"/> | |
607 | <Point Identifier="blue	point	521" ScreenX="3024" ScreenY="73" Ordinal="1"/> | |
608 | <Point Identifier="blue	point	522" ScreenX="3048" ScreenY="70" Ordinal="1"/> | |
609 | <Point Identifier="blue	point	523" ScreenX="3071" ScreenY="66" Ordinal="1"/> | |
610 | <Point Identifier="blue	point	524" ScreenX="3095" ScreenY="62" Ordinal="1"/> | |
611 | <Point Identifier="blue	point	525" ScreenX="3118" ScreenY="58" Ordinal="1"/> | |
612 | <Point Identifier="blue	point	526" ScreenX="3143" ScreenY="55" Ordinal="1"/> | |
613 | <Point Identifier="blue	point	527" ScreenX="3166" ScreenY="51" Ordinal="1"/> | |
614 | <Point Identifier="blue	point	528" ScreenX="3190" ScreenY="47" Ordinal="1"/> | |
615 | <Point Identifier="blue	point	529" ScreenX="3214" ScreenY="44" Ordinal="1"/> | |
616 | <Point Identifier="blue	point	530" ScreenX="3238" ScreenY="40" Ordinal="1"/> | |
617 | <Point Identifier="blue	point	531" ScreenX="3261" ScreenY="36" Ordinal="1"/> | |
618 | <Point Identifier="blue	point	532" ScreenX="3285" ScreenY="33" Ordinal="1"/> | |
619 | </Cmd> | |
620 | </CmdMediator> | |
621 | <Error Context="Shift+Control+E" Comment="userTriggered" File="src/main/MainWindow.cpp" Line="1355"/> | |
622 | </Document> | |
623 | </ErrorReport> |
0 | -filecmdscript ../test/jpeg2000/jpeg2000.test.xml -regression | |
0 | -filecmdscript ../test/jpeg2000/jpeg2000.xml -regression |
0 | -errorreport ../test/multi_coord_systems_curve_rename.xml -regression | |
0 | -errorreport ../test/multi_coord_systems_curve_rename.xml -regression -reset |
0 | -filecmdscript ../test/pdf/pdf_one_page.test.xml -regression | |
0 | -filecmdscript ../test/pdf/pdf_one_page.xml -regression |
0 | -errorreport ../test/points_along_axes.xml -regression -reset |
0 | <ErrorReport> | |
1 | <Application VersionNumber="9.0"/> | |
2 | <Document AxesPointsRequired="0" VersionNumber="9.0"> | |
3 | <Image Height="607" Width="1042"><![CDATA[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]]></Image> | |
4 | <CoordSystem> | |
5 | <General CursorSize="3" ExtraPrecision="1"/> | |
6 | <Coords UnitsYString="Number" UnitsRadius="0" UnitsXString="Number" UnitsTime="2" ScaleYRadius="0" UnitsTheta="0" ScaleXTheta="0" ScaleXThetaString="Linear" ScaleYRadiusString="Linear" TypeString="Cartesian" UnitsX="0" UnitsY="0" UnitsRadiusString="Number" UnitsDate="3" Type="0" UnitsDateString="YYYY/MM/DD" Coords="0" UnitsThetaString="Degrees (DDD.DDDDD)" UnitsTimeString="HH:MM:SS"/> | |
7 | <DigitizeCurve CursorLineWidth="2" CursorSize="1" CursorStandardCross="True" CursorInnerRadius="5"/> | |
8 | <Export PointsIntervalFunctions="10" PointsSelectionRelations="0" Header="1" PointsSelectionRelationsString="Interpolate" DelimiterString="Commas" PointsIntervalUnitsRelations="1" LayoutFunctionsString="AllPerLine" PointsSelectionFunctionsString="InterpolateAllCurves" PointsIntervalRelations="10" OverrideCsvTsv="True" HeaderString="Simple" PointsSelectionFunctions="0" XLabel="x" Delimiter="0" PointsIntervalUnitsFunctions="1" LayoutFunctions="0"> | |
9 | <CurveNamesNotExported/> | |
10 | </Export> | |
11 | <AxesChecker Mode="1" LineColor="6" Seconds="3"/> | |
12 | <GridDisplay DisableY="0" StopY="1" Stable="False" CountX="2" StartX="0" CountY="2" StartY="0" StepX="1" StepY="1" Color="0" ColorString="Black" DisableX="0" StopX="1"/> | |
13 | <GridRemoval CoordDisableY="0" StopY="0" CoordDisableXString="Count" Stable="False" CloseDistance="10" CountX="2" StartX="0" CountY="2" StartY="0" DefinedGridLines="False" StepX="0" StepY="0" CoordDisableX="0" StopX="0" CoordDisableYString="Count"/> | |
14 | <PointMatch ColorAccepted="4" ColorAcceptedString="Green" ColorCandidate="7" ColorCandidateString="Yellow" ColorRejectedString="Red" PointSize="48" ColorRejected="6"/> | |
15 | <Segments LineColor="4" MinLength="2" LineWidth="4" LineColorString="Green" FillCorners="False" PointSeparation="25"/> | |
16 | <Curve CurveName="Axes"> | |
17 | <ColorFilter ModeString="Intensity" Mode="2" CurveName="Axes" ValueLow="0" ForegroundHigh="10" SaturationHigh="100" ValueHigh="50" HueLow="180" SaturationLow="50" IntensityLow="0" ForegroundLow="0" HueHigh="360" IntensityHigh="50"/> | |
18 | <CurveStyle CurveName="Axes"> | |
19 | <LineStyle ConnectAs="4" ConnectAsString="ConnectSkipForAxisCurve" Color="8" ColorString="Transparent" Width="0"/> | |
20 | <PointStyle Radius="10" LineWidth="1" Shape="1" ShapeString="Cross" Color="6" ColorString="Red"/> | |
21 | </CurveStyle> | |
22 | <CurvePoints/> | |
23 | </Curve> | |
24 | <CurvesGraphs> | |
25 | <Curve CurveName="Curve1"> | |
26 | <ColorFilter ModeString="Intensity" Mode="2" CurveName="Curve1" ValueLow="0" ForegroundHigh="10" SaturationHigh="100" ValueHigh="50" HueLow="180" SaturationLow="50" IntensityLow="0" ForegroundLow="0" HueHigh="360" IntensityHigh="50"/> | |
27 | <CurveStyle CurveName="Curve1"> | |
28 | <LineStyle ConnectAs="0" ConnectAsString="FunctionSmooth" Color="1" ColorString="Blue" Width="1"/> | |
29 | <PointStyle Radius="10" LineWidth="1" Shape="1" ShapeString="Cross" Color="1" ColorString="Blue"/> | |
30 | </CurveStyle> | |
31 | <CurvePoints/> | |
32 | </Curve> | |
33 | </CurvesGraphs> | |
34 | </CoordSystem> | |
35 | <OperatingSystem Endian="LittleEndian" WordSize="32"/> | |
36 | <File Imported="True"/> | |
37 | <CmdMediator> | |
38 | <Cmd Type="CmdAddPointAxis" ScreenX="68.5817" ScreenY="356.569" GraphX="1" Ordinal="1" GraphY="0" Description="Add axis point" Identifier="Axes	point	1" IsXOnly="False"/> | |
39 | <Cmd Type="CmdAddPointAxis" ScreenX="1019.14" ScreenY="357.263" GraphX="121" Ordinal="2" GraphY="0" Description="Add axis point" Identifier="Axes	point	3" IsXOnly="False"/> | |
40 | <Cmd Type="CmdAddPointAxis" ScreenX="69.3192" ScreenY="27.7486" GraphX="1" Ordinal="3" GraphY="1.5" Description="Add axis point" Identifier="Axes	point	5" IsXOnly="False"/> | |
41 | <Cmd Type="CmdAddPointGraph" CurveName="Curve1" ScreenX="391.58" ScreenY="339.226" Ordinal="1" Description="Add graph point" Identifier="Curve1	point	6"/> | |
42 | <Cmd Type="CmdAddPointGraph" CurveName="Curve1" ScreenX="513.994" ScreenY="369.75" Ordinal="1" Description="Add graph point" Identifier="Curve1	point	7"/> | |
43 | <Cmd Type="CmdAddPointGraph" CurveName="Curve1" ScreenX="617.236" ScreenY="337.145" Ordinal="2.5" Description="Add graph point" Identifier="Curve1	point	8"/> | |
44 | <Cmd Type="CmdAddPointGraph" CurveName="Curve1" ScreenX="698.354" ScreenY="366.975" Ordinal="3.5" Description="Add graph point" Identifier="Curve1	point	9"/> | |
45 | <Cmd Type="CmdEditPointGraph" IsX="False" X="0" IsY="True" Y="0" Description="Edit curve points"> | |
46 | <Point Identifier="Curve1	point	7"/> | |
47 | <Point Identifier="Curve1	point	8"/> | |
48 | <Point Identifier="Curve1	point	6"/> | |
49 | <Point Identifier="Curve1	point	9"/> | |
50 | </Cmd> | |
51 | </CmdMediator> | |
52 | <Error File="src/main/MainWindow.cpp" Line="1305" Context="Shift+Control+E" Comment="userTriggered"/> | |
53 | </Document> | |
54 | </ErrorReport> |
0 | -errorreport ../test/polar_linear_linear_3curve.xml -regression | |
0 | -errorreport ../test/polar_linear_linear_3curve.xml -regression -reset |
0 | -errorreport ../test/polar_linear_linear_nonzero_center.xml -regression | |
0 | -errorreport ../test/polar_linear_linear_nonzero_center.xml -regression -reset |
0 | -errorreport ../test/undo_redo.xml -regression | |
0 | -errorreport ../test/undo_redo.xml -regression -reset |
0 | -filecmdscript ../test/version5_1.test.xml | |
0 | -filecmdscript ../test/version5_1.xml -regression -reset |
0 | <Script> | |
1 | <Cmd Type="CmdFileOpen" FileName="../test/version5_1.dig" /> | |
2 | <Cmd Type="CmdFileClose" /> | |
3 | <Cmd Type="CmdFileOpen" FileName="../test/version5_1.dig" /> | |
4 | <Cmd Type="CmdFileClose" /> | |
5 | </Script> | |
6 |
0 | <Script> | |
1 | <Cmd Type="CmdFileOpen" FileName="../test/version5_1.dig" /> | |
2 | <Cmd Type="CmdFileClose" /> | |
3 | <Cmd Type="CmdFileOpen" FileName="../test/version5_1.dig" /> | |
4 | <Cmd Type="CmdFileClose" /> | |
5 | </Script> | |
6 |
0 | -errorreport ../test/version5_2.dig -regression | |
0 | -errorreport ../test/version5_2.dig -regression -reset | |
1 | 1 |
0 | -filecmdscript ../test/version6_1.test.xml | |
0 | -filecmdscript ../test/version6_1.xml -regression -reset |
0 | <Script> | |
1 | <Cmd Type="CmdFileOpen" FileName="../test/version6_1.dig" /> | |
2 | <Cmd Type="CmdFileClose" /> | |
3 | <Cmd Type="CmdFileOpen" FileName="../test/version6_1.dig" /> | |
4 | <Cmd Type="CmdFileClose" /> | |
5 | </Script> | |
6 |
0 | <Script> | |
1 | <Cmd Type="CmdFileOpen" FileName="../test/version6_1.dig" /> | |
2 | <Cmd Type="CmdFileClose" /> | |
3 | <Cmd Type="CmdFileOpen" FileName="../test/version6_1.dig" /> | |
4 | <Cmd Type="CmdFileClose" /> | |
5 | </Script> | |
6 |
0 | -errorreport ../test/version6_2.dig -regression | |
0 | -errorreport ../test/version6_2.dig -regression -reset | |
1 | 1 |
0 | -filecmdscript ../test/version7.1_1.test.xml | |
0 | -filecmdscript ../test/version7.1_1.xml -regression -reset |
0 | <Script> | |
1 | <Cmd Type="CmdFileOpen" FileName="../test/version7.1_1.dig" /> | |
2 | <Cmd Type="CmdFileClose" /> | |
3 | <Cmd Type="CmdFileOpen" FileName="../test/version7.1_1.dig" /> | |
4 | <Cmd Type="CmdFileClose" /> | |
5 | <Cmd Type="CmdFileImport" FileName="../samples/huge.png" /> | |
6 | <Cmd Type="CmdFileClose" /> | |
7 | </Script> | |
8 |
0 | <Script> | |
1 | <Cmd Type="CmdFileOpen" FileName="../test/version7.1_1.dig" /> | |
2 | <Cmd Type="CmdFileClose" /> | |
3 | <Cmd Type="CmdFileOpen" FileName="../test/version7.1_1.dig" /> | |
4 | <Cmd Type="CmdFileClose" /> | |
5 | <Cmd Type="CmdFileImport" FileName="../samples/huge.png" /> | |
6 | <Cmd Type="CmdFileClose" /> | |
7 | </Script> | |
8 |
0 | -errorreport ../test/version7.1_2.dig -regression | |
0 | -errorreport ../test/version7.1_2.dig -regression -reset | |
1 | 1 |
0 | -filecmdscript ../test/version7_1.test.xml | |
0 | -filecmdscript ../test/version7_1.xml -regression -reset |
0 | <Script> | |
1 | <Cmd Type="CmdFileOpen" FileName="../test/version7_1.dig" /> | |
2 | <Cmd Type="CmdFileClose" /> | |
3 | <Cmd Type="CmdFileOpen" FileName="../test/version7_1.dig" /> | |
4 | <Cmd Type="CmdFileClose" /> | |
5 | <Cmd Type="CmdFileImport" FileName="../samples/huge.png" /> | |
6 | <Cmd Type="CmdFileClose" /> | |
7 | </Script> | |
8 |
0 | <Script> | |
1 | <Cmd Type="CmdFileOpen" FileName="../test/version7_1.dig" /> | |
2 | <Cmd Type="CmdFileClose" /> | |
3 | <Cmd Type="CmdFileOpen" FileName="../test/version7_1.dig" /> | |
4 | <Cmd Type="CmdFileClose" /> | |
5 | <Cmd Type="CmdFileImport" FileName="../samples/huge.png" /> | |
6 | <Cmd Type="CmdFileClose" /> | |
7 | </Script> | |
8 |
0 | -errorreport ../test/version7_2.dig -regression | |
0 | -errorreport ../test/version7_2.dig -regression -reset | |
1 | 1 |
0 | -errorreport ../test/version8_1.dig -regression | |
0 | -errorreport ../test/version8_1.dig -regression -reset | |
1 | 1 |
0 | -errorreport ../test/version8_2.dig -regression | |
0 | -errorreport ../test/version8_2.dig -regression -reset | |
1 | 1 |
0 | x;Curve1 | |
1 | -9.936;6.032 | |
2 | -9.675;6.388 | |
3 | -9.347;6.711 | |
4 | -8.976;7.002 | |
5 | -8.517;7.212 | |
6 | -7.971;7.276 | |
7 | -7.468;7.146 | |
8 | -7.053;6.918 | |
9 | -6.965;6.87 | |
10 | -6.593;6.577 | |
11 | -6.265;6.253 | |
12 | -5.937;5.929 | |
13 | -5.652;5.572 | |
14 | -5.368;5.231 | |
15 | -5.083;4.875 | |
16 | -4.842;4.518 | |
17 | -4.579;4.161 | |
18 | -4.316;3.821 | |
19 | -4.054;3.448 | |
20 | -3.813;3.092 | |
21 | -3.55;2.735 | |
22 | -3.265;2.394 | |
23 | -3.003;2.038 | |
24 | -2.696;1.697 | |
25 | -2.39;1.357 | |
26 | -2.061;1.032 | |
27 | -1.711;0.724 | |
28 | -1.339;0.448 | |
29 | -0.902;0.188 | |
30 | 0.65;0.089 | |
31 | 1.131;0.282 | |
32 | 1.524;0.541 | |
33 | 1.917;0.848 | |
34 | 2.244;1.155 | |
35 | 2.549;1.495 | |
36 | 2.855;1.834 | |
37 | 3.139;2.174 | |
38 | 3.4;2.53 | |
39 | 3.684;2.869 | |
40 | 3.924;3.242 | |
41 | 4.186;3.597 | |
42 | 4.448;3.953 | |
43 | 4.709;4.309 | |
44 | 4.971;4.665 | |
45 | 5.211;5.021 | |
46 | 5.517;5.36 | |
47 | 5.778;5.716 | |
48 | 6.084;6.04 | |
49 | 6.411;6.363 | |
50 | 6.76;6.686 | |
51 | 7.044;6.88 | |
52 | 7.481;7.123 | |
53 | 7.984;7.251 | |
54 | 8.508;7.186 | |
55 | 8.967;6.991 | |
56 | 9.361;6.699 | |
57 | 9.69;6.374 | |
58 | 9.952;6.018 |
0 | <?xml version="1.0" encoding="UTF-8"?> | |
1 | <!DOCTYPE engauge> | |
2 | <Document VersionNumber="9.0" AxesPointsRequired="0"> | |
3 | <Image Width="1000" Height="800"><![CDATA[AAAAAYlQTkcNChoKAAAADUlIRFIAAAPoAAADIAgCAAAAP3rfagAAAAlwSFlzAAAOxAAADsQBlSsOGwAAIABJREFUeJzt3euR21a2gFFwynk0HImQiTGRGI5kcCMxFInQkfD+gE1RfDVI4nH2OWvV1NRIajVbGhL4emsDPByPxwoAAEjbf/b+AgAAgK8JdwAACEC4AwBAAMIdAAACEO4AABCAcAcAgACEOwAABCDcAQAgAOEOAAABCHcAAAhAuAMAQADCHQAAAlg43MdxbNv2cDhc/1Lf93VdHw6Huq77vl/2cQEAIG9Lhnvf903TNE1z/UvDMHRd1/f98Xjs+77rumEYFnxoAADI2+F4PC71udq27bpuGqtffNq2bZumadt2+mHf98MwmLsDAMBMS4b7z096Fe51XQ/DUNf19MNxHJumGcdx8YcGAIAsbRTuc34GAAC4x11lAAAgAOEOAAAB/LbNw3x8fIzjeL7j/vHxMf+337y/JAAApGa9bfCNwr1pmmEYzu8qc/OukQ9YiCcK128QhecqgXi6EsWq4+aNwr3ruqZp6rqeCn66HeQ2Dw0AABlY8vvXm99hnD7/NHH//Pz8+Ph4duLu+2wC8XQlCs9VAvF0JYpVn6sxXgZergTi6UoUnqsE4ulKFKs+V91VBgAAAhDuAAAQgHAHAIAAhDsAAAQg3GFhLp8iCs9VAvF0fdZTdxOfebu/Lz+maZq+7+c/Ls8S7gAAkcyJ8vnf6gzD0HXdl8E9DENd16cfdl1X1/XhcKjr+vR7+77vus579axHuAMAxDA18cfHR1VV4zgu8jnbtp0q/MuHPk3c27adfuZ4PE5vrDm1e13XXddNv8oahDsAQFoullLGcZx+Znor+qqq6rqe+nj6pcPhcDgcmqY51fz5VL6u62lefvEx1b9z9FNq33vc6ircT60/Tdy7rjv90vRwb/zpuUu4AwCk5WJu3XXdVMZTPX9+frZtO8Vx27Zt2x6Px+PxOP3v68/2+fk5bbAcj8emac4/5mK7/d7jVlU1juNpKv942d2m+3qEOwBAWqYynvJ3+u/pZ6a9lL///rvv+yncv3//fkrtU81fOw3I27b9/v376efP5+iPH/derI/jeN73028xcV/Jb3t/AQAAXOr7fkrtrutOyy3TUkrTNNPlpE3T/PHHH23bNk3TNM2DPfVTdl9/zMXP3Hzce+E+LeRMX8O9T8iCTNwBAFLUtu1///vfi82W6Ydt257m4tMlob///vvF/vocn5+f1519/bj3wv14PP748aP6dzw/qev68/PzqS+DmQ4hbox6OMT4OgEAFjFdGDqV+sWtGO99/LS1Mq2pnLfTRUed//B03eqDx51+5sG3BBcf8OXH3/DMXec38mp5rlqtJu4AAMmZrhOdtmLON8jvqeu6aZrz/fWZLgr7+nGvx+2Prz195T6Vx2Ny/0mScAcASMswDNP7IlVnN02/+ZHnt3Dp+/7bt29PPdDFhaQ3H/c63KePmQJ9HMfp7pDnvzrnfVh5QYwVFKsyAEA5ppujX9zv5Wa7Tw09Ddq/fft2urR05qrM9NtPn/nm447jeL2rMy3SfH5+fnx8XP+W0/3mC7RqtcYIYuEOALCGZd/udLrvzVLv6hqRHXcAAFaxYGpPV8d696X1xJhkm7gDAKyk7/vTOzq9Y3pb1qWG90FZlRHuAAAEYFUGAABKJ9wBACAA4Q4AAAEIdwCA3BwOh/kffHEj9nu+/Jjzd4NiDcIdACCSOVE+//rI6T2Yvgzu6/dgmvR9f/p6pjtLvn93Gu4R7gAAMUxN/PHxUVXVUm9y1LZt13U3o/zioa8n7tON208/XPa9nLgm3AEA0nKRyOM4Tj/Tdd30P+q6nvp4+qXD4XA4HJqmOdX8+VS+rutpXn7xMdW/c/RTat973OpOuLdtezGqb9t2erjn/sDMI9wBANJyMbfuum4abE/1/Pn52bbtFMfTGx4dj8fj8XjvzY8+Pz+nDZbj8Ti9R9Lply622+89blVV4zheTOWnD76ueZvu6xHuAABpmWp4yt/pv6efGYah7/u///779Ean379/P6X2qeavnZZh2rb9/v376ecv5ugPHvci0IdhGIbh5vcJTdOYuK/kt72/AAAALvV9P6V213Wn5Zbp6s+maabLSZum+eOPP6axd9M0D/bUT9l9/TEXP3PzcS/CfRzHB98kfLkuz8tM3AEAUtS27X//+9+LzZbph6fl8qmzu677/fffL/bX5/j8/Lzu7OvHvQj3aUnmXqDXdf35+fnUl8FMh/l3C9rR4RDj6wQAWMR0YehU6vduxXjx8dM9XqZB+Hk7XXTU+Q9P160+eNzpZ86/Jbh5P8o///xzWoi//vgvHb4/cdf5bRy/vVieq1arVRkAgOScLv2crhD98nLPuq7ruj7fX5/p4qrT68e9XnC/CNOLVH3hPpUvV3JprMoAAKRluvRzGmBPKyv3FsrPb+HS9/23b9+eeqCLC0lvPu7NG0E+/uKf+njmi7GCYlUGAChHXdcXN2q8d6uWqbOnQfu3b99Ol5bOXJWZfvvpM9983HEcH+/qXHz+aVpfbLuvWq0xgli4AwCsYdm3O53ue7PUu7pGtGq1WpUBACjXgqk9XR3r3ZfWE2OSbeIOALCSvu9P7+j0jultWZca3gdlVUa4AwAQgFUZAAAonXAHAIAAhDsAAAQg3AEAcnM4HOZ/8MW92+/58mPO3w2KNQh3AIBI5kT5/Osjp/dg+jK4z9+DqW3bw6+mX5ruLPn+3Wm4R7gDAMQwNfHHx0dVVUu9yVHbtl3XPXhj1NNDnybu4zj++PHjeGb6YpZ9LyeuCXcAgLRcLKWM4zj9TNd10/+o63rq4+mXprF30zSnmj+fytd1Pc3LLz6m+neOfkrte49b/RruD7RtOz3czD8pTxHuAABpuZhbd13XdV31bz1/fn62bTvF8fSGR9PY+96bH31+fk4bLMfjcXqPpNMvXWy333vcqqrGcTxN5R8P+226r0e4AwCkZYrpKX+n/55+ZhiGvu///vvv0xudfv/+/ZTap5q/dlqGadv2+/fvp5+/mKM/eNybw/hpu/0i05umMXFfyW97fwEAAFzq+35K7a7rThPu6erPpmmmy0mbpvnjjz/atm2apmmaB3vqp+y+/piLn7n5uBfhPi3DTB85DMP0ncPp+4cv1+V52YpvyrqgVd88FgAgQV3X/fXXX3/++edpX+Xeh/V9//n5+e3bt1N2n7fTRUc9+KV7jzttv9wr8qndz/dnSi63Vf/sMf5aS/6/HwAo0LSL0vf9tADz5Rh7HMdxHE93Y5wZ7qfrVh887vQzj/fazz/nnI+//O1/zf/YjRz/fPE3rlqtYVZlpv9HX/5LBAAIZLpOdNqKmXOf9bqu67o+31+f6fyq05uPe3PB/fy3DMPw7du381999mvII/A2+PYjTLhP/4+e/43k8f8xAMCFYRiGYZgKeJp837sb43SXmGm/vO/784CeY7qQ9Pyej9ePe/3QU9mf7vw43Qn+/Iufc+PIPFyn6aFb8+FCrKDc/EcHEQ8AZGm6VcvF/V5u3qplet/TadD+wo779NtPn/nm447jeL1OM/2uz8/Pj4+Pi5tITtP6jNv9cYLacf/6r+D0N6jgAQDmW/btTqf73iz1rq5JmVmbwv2JvwIFDwAw37TrMuf61y+dLmzNadz+bFsK91f+ChQ8AMAcfd+f3tHpHecL99G9XJLC/a2/ArejAQBgpjfTUbgv8FdgAA8AwD1LtaJwX/KvwAAeAICTZeNQuC//VyDfAQAKt0YQCve1/grkOwBAgdaLQOG+8l+BfAcAKMPa4Sfc1/0r+Och5DsAQL62iT3hvkW4//NA8h0AIC9bBp5w3y7c/3m4v7Q7AEAONu66Vav1Pyt93tCOf/68lycAAEFlNo01cb//oNZmAABi2ivkrMrsE+7/PHRe36gBAGRvx36zKrMnazMAAIFkPHU1cZ/3BVibAQBIWwrBZlVm/3D/58vI9xs4AIDQEuk0qzKpsDYDAJCgRKp9bcL9OdodACAphVR7ZVXmNSlsUAEAFC7BJLPjnly4T8r59g4AIDVplpgd90RZmwEA2EWa1b62FCfZ19KcuE8S/DcaAIBcJZ5eVmWSDvdJmd/2AQBsKf3isioTgLUZAIBVpV/taxPui9HuAAArUe2VcF+WdgcAWJxqnwj3hWl3AIAFqfaT1C/6nKR/ceoFzzAAgDclfgOZm9xVJl64VzGfagAAiQg6BhXuIcN9EvQ5BwCwo7gF5XaQgVl5BwB4StxqX5twX512BwCYSbU/INy3oN0BAL6k2h8T7hvR7gAAD6j2Lwn37Wh3AICbVPscwn1T2h0A4IJqn0m4b027AwCcqPb5hPsOtDsAQKXanyTcAQAgAOG+D0N3AKBwxu3PEu670e4AQLFU+wuE+560OwBQINX+GuG+M+0OABRFtb9MuO9PuwMAhVDt7xDuSdDuAED2VPubhHsqtDsAkDHV/j7hnhDtDgBkSbUvQrinRbsDAJlR7UsR7gAAEIBwT46hOwCQDeP2BQn3FGl3ACADqn1Zwj1R2h0ACE21L064p0u7AwBBqfY1CPekaXcAIBzVvhLhnjrtDgAEotrXs124D8PQNM3hcGiaZhiGzR4XAAAysFG49/86Ho+n/73NQ2fA0B0ACMG4fVWH4/G4wcPUdT0MQ13X0w/HcWyaZhzHmb/9cNjo60yZVwIAkDKtUq1crXbcwzB3BwCSpdo3sFG4d13Xtu00Yh/Hseu6ruu2eWgAAMjARuHetm1d17///vvhcPj999+nn9nmoXNi6A4AJMi4fRvbXZw6juOPHz+Ox+OPHz/GcXRx6mu0OwCQFNW+mTAXp977pTIvWvUKAQBSUGyT7FKnv630eRdXZqADAJCge2n6IOjf5+LUkCzMAAC7K3bcvpft7o8+DEPbtp+fnx8fH33fN00z//e6j/tNXi0AwF50yE2rVmuMIBbu93jNAADbUyD3eAMm7rIzAwBsTLXvRbgDAEAAwj08Q3cAYDPG7TsS7jnQ7gDABlT7voR7JrQ7ALAq1b474Z4P7Q4ArES1p0C4Z0W7AwCLU+2JEO4AABCAcM+NoTsAsCDj9nQI9wxpdwBgEao9KcI9T9odAHiTak+NcAcAgACEe7YM3QGAlxm3J0i450y7AwAvUO1pEu4AABCAcM+coTsA8BTj9mQJ9/xpdwBgJtWeMuFeBO0OAHxJtSdOuAMAQADCvRSG7gDAA8bt6RPuBdHuAMBNqj0E4Q4AAAEI97IYugMAF4zboxDuxdHuAMCJag9EuAMAQADCvUSG7gBAZdwejXAvlHYHgMKp9nCEOwAABCDcy2XoDgDFMm6PSLgXTbsDQIFUe1DCHQAAAhDupTN0B4CiGLfHJdwBACAA4Y6hOwCUwrg9NOFOVWl3ACiAao9OuAMAQADCnX8YugNAxozbMyDc+Um7A0CWVHsehDsAAAQg3PmFoTsAZMa4PRu/7f0FcNvh+2HmRx6/HVf9SgAALgiVXRyOxwB/m4dDjK/zTeevgfnP8otXziIvD9+aA0Aeljqnv9wbr+VNXKtWa4wgzjjcF382L/UJtTsARPfm2TzZSknZqtVqVWYfpyfu4s/a8084PUquLwwAYCUrJcR1pazxKBmLMcnOZuK+y3P05deeoTsAxPXaeXz7qV9mBW/iHt6+z8jpQU3fAYAH9kqF0yNqlS/FmGTHnbin9hR89usxdAeAiJ46gyeVK0l9MS9wcWrIcE/5affU16bdASCW+efuZHMl2S/sS1Zlgkn/qWZ5BgAKl3gGaJWbYkyyo0zcIz695nzNhu4AEMWXZ+1wuRLrCzZxj+Hw/RDlKXXOd7QAUIigp3utchJkkp38xD1otV948KcwdAeA9D04X2ffKolwcWrS4Z7Z93/aHQCCyr7aJ4mnl1WZdOX0Mpgcvx0Tfz0AAPPld1o/bc7k9IeaKd1J9rk0J+55P2Nu/ukM3QEgTTfP0QW2yu5Wrdb/rPR583b4fkjzubKg0+gdAIiokFYpKldSnGRfS2rinv3L4Nz1v68ZugNAai7OzvmtxzyWVJu5ODWhcE/qmbGZiz+1dgeAdFxXu1bZkVWZVKTznNiYtRkACEGr5E24z1XsK2Fy/no4/lkd/tr3ywEAqurXcbtWyb7dhfsshb8SJgVeAgIAIZRw24w5sm/3VHbHH9txx720yzvmmA4NNt0BYF/TuViyX9g33lyculu4eyXco90BYF+q/bG9/mZcnLoPr4QHsv+nKABIn1Z5IMtWMXG/84heCfMYugPA9px/Z9q+6Ezct6ban5Lft7MAkDJn3vkym7sL90uq/SnHP6tqyOolAQApO3w/VMPRuH2+nNpduP9Ctb9AuwPANlT7a7Jpd+HOMrJ5SQBAmowXEe4/eT28bHovVe0OACtxI+Y35VEpwv0fqv1N2h0AVqLaF5FBpQj3qlLti8rgVQEA6VApC4peKcLd62Ex09C9iv+qAIBEnCrFuH0poSul9HBX7cvS7gCwFNW+kriVUnq4s564rwoA2J3ZIteKDncviTWchu6VdgeAl5wninH7GoImSrnhrtrXo90B4GWqfRsRE6XQcFftW4r4wgCAXUiULYVLlBLD3UtiA+dD9yrgCwMAtneRKMbtG4iVKCWGO9vQ7gAwn2rnS8WFu3H7jrQ7ANykT3YUqE/KCnevio1dDN0BgDmM2zcWpd0LCnfVvgsLMwDwmCWZFIRIlILCnUSEeGEAwDYMFpmvlHD3qtjR9cKMdgeA6lafGLfvKP0+KSLcVXuC0n9tAMCq9EmCEu+T/MPdqyIFN69STfy1AQDrudknxu0pSLlP8g93UpbyawMAVmKqyGsyD3cvjHS4NSQAPGDcno5kB4s5h7tqT42FGQCwJBNCmn2Sbbir9kDSfG0AwOL0SSAJ9km24U6a7i3MJPjaAIBl3at243ZmyjPcfTsLAMCbUhssZhjuqj1xhu4AFMi4Paik+iTDcCeupF4bALAUU0UWkVu4e2GE8ODWkNodgMw8iBPj9hDSiZOswl21AwCwuETaPatwJxBDdwBKYNzOgvIJd+P2cLQ7AHlT7TlJIU7yCXcyk8LLAwBeZqTI4jIJd6+NoB4M3QEgV8btQe0+Vcwh3FV7rnZ/eQDAa8RJrvaNkxzCndAeD921OwDhPK5243ZeFj7cfUebPe0OQCDKJHs7lknscPfayINNdwAKYdyeh73aPXa4UwhDdwBCMFJkVYHD3WsjJ18O3bU7AIn7skyM23OyS5kEDndKo90BSJZ5IhuIGu5eHvmx6Q5Axozb87P9SDFquFMmQ3cAEmSeyDZChruXR67mDN21OwBJmZMlxu252jhLQoY7AACUZrtwH8exaZrD4VDXddu2L38e4/a8GboDEIhxO1tmyUbhPo5j27Zt2x6Px2EY3mx30O4A7M4wkY0djsctnnBd153+e9L3/fx2Pxz++Tq9Qgoxczjh+QDAXmaeg4zbC3F6PpyqdQ0bTdyHYWia5vxnTNx5wK0hAciAamdZ263KVFU17bg3TTP98FnGq1ywMAPALjQJF7Zpko3C/fPzs+u6ruuOx2PXdW3bvtbulGPm0F27A7AxSzLsZbu7ynRdN23LNE0ztftTv923tgAAJGuDYeJG4f7x8XH+w6Zpvn///uwnOdyy3NdIcgzdAUiNcTuTXbp0o3BvmmYYhtMPh2G4SPkvHb8db1r4CyUm7Q7ABvz7Pye3w3Tlp8dG4d51Xd/3fd9XVTUMw7Tvvs1DE9r828todwBWNb/ajdtZyUbhXtf1FO6Hw2GqdreDBACA+TZ6A6Y3rXore9I3f3ThHzEBWINxOzPl8AZMsA0LMwAszlSIRAh3AvBGqgCEYNzOqoQ7uTF0B2BBxu2kQ7gTw1NDd+0OwCKeqnbjdtYm3AEAIADhThiG7gBsybid1Ah3sqXdAXiZ1XYSJNyJxO1lAEiQcTvbEO4EY2EGgLVZkiFNwh0AAAIQ7sRj6A7AeozbSZZwJ3/aHYCZXJNKyoQ7IblKFYDdGbezMeFOVBZmAFiWJRkSJ9wphXYH4AFLMqRPuBOYhRkAdmHczi6EOwUxdAfgJuN2QhDuxGboDsDGjNvZi3CnLIbuAFwwbicK4U54zw7dtTsAJ89Wu3E7OxLu5MDCDAAbUO3sS7hTIkN3ACpLMkQj3MmEoTsAqzJuZ3fCnUIZugMUzridcIQ7+XCVKgAzuSaViIQ7WbEwA8DiVDuJEO4UzdAdoECWZAhKuJMbQ3cAFmTcTjqEO6UzdAcoinE7cR2OxwDP3cMhxtfJug5P5PWhOz41IHEcByjBK9ekds8Md+RK8VatVhN30nY4/PzP8fjEf85/LwA85fwM8tTZ5/y0BUuLMck2cS/L+cHujf/ff24lnj7hw89m6A6Qt6+P87+eL97dbl/odEYsq1brbyt9XnjFabaxrNMnXOnzAxDdGieI88/mBMQSYkyyTdzzt84R7faw5P5jGboD5OruEf7OSWGVm8nI9wKYuJO17Y9ipw34jR8XgKQ4ARFNjEm2iXueNjlyfTEyufoaDN0B8nN5bP/qBLTFvdvle6bcVYYcne4Ss6/TTQBOP+G27gB5uVHtSZ6A4EvCnc2d7u24iVlvpHq6gRcAGZt3Atr0rVKdgHiGcGdbicw5rp1NPgzdAbLxc9we4QQEjwl3NrThoP3crKH7Px9q8gGQnWf+pXfTcfs57c4M7irDJgJdgnM8VlV1PBwOg6tUAWI7fD8cmyBnn+qs3aN8wWzOxJ31JfCvk08M3f/5DWd37AIgoucjeLdx+4m1GR4S7qxsp/WYa8+2+/Hb8TBod4CYDofDUD31D6f7V/uJducO4c6akqn21zl6AoTj7EOmhDurSe+4+crQ/fvB0RMgksOhOh6ffTe9hMbtJ84+XBHurCO9an+NdgeI5KVqT5ezD78S7ixt2/dXetbTV6n+/J2OngAJe+Psk+K4/cTZhzPCnUUlcAOZxf18PyZ3eQdI09nZJ59x+4mzD/8S7iwn4UH7uReG7r+0u+EHQFLOzj4vVHvS4/YTZx+qqhLuLCZItS/D0RMgEc4+lES4s4Rox823hu7//NjRE2Bvv559sh23n3P2KZtw523Rqn0xjp4AO3L2oTzCnfeEPW4uMHSvHD0BdnJ19ili3H7i7FMq4c4bwlb7y7Q7wP6WqPbwnH2KJNwp1+v3dL/8RI6eAFtZaGYUeNxOwYQ7rypv3D65MXSvtDvAJm6dekoct0+cesoj3HlJLtX+2tBduwPsYLlqz2fc7tRTGOHO83KpdgAIT7uXRLhTOkN3gACM20G487Qcx+2LXaVaaXeAFSx36smz2p16iiHceUaO1f6y20P3ygEUYFF3Tj3lXpN6k1NPGYQ7s2Vd7UsuzFQOoAALWbTa8xy3nzj1FEC4wzocQAHelPXACF4g3JmngKPnwkP3SrsDvOH+ece4/S7nndwJd2YooNoBIAfaPWvCHX4ydAdIgnE73CLc+Ypx+5u0O8BTnHfe5LyTL+EOv1h+6F45hgLM9rDajdspnHDnIWOPpWh3gC856SzFSSdTwp37Sj2ArjJ0rxxGAR766qRj3P4cJ50cCXcAAAhAuHNHqeP2iaE7wKaM29fgpJMd4Q7bchgFuFD2qAjmE+7c4hi63tC90u4AZ2accYzbX+eMkxfhzhXVDgDZ0O4ZEe5wl6E7wLqM2+EZwp1fGbf/6rV2n/eptTtQttXOOKr9kjNOLoQ7LG/W0B2Ar7w2bodcCXfOGLffYmEGYHmWZDbmjJMF4c6/VPsuHEmBAjnj7MIZJz7hDl9bceheOZIChZlX7cbtcE24U1WV4QcAFMCoKDjhDrMYugMswLgd3iDcMW5Pg3YHsud0kwKnm8iEO8y17tAdgKqqjNvhPuFePPOPZ6z4fkyVKQiQtTVPN6r9OU43YQl3WN0TQ3cHUyBLs6vdOy7BA8K9bMbtz1t36A7Ak4zbX2FOFJNwhy0YugPlMm6HhQj3ghm3v2r1obt2B7Kx8rnGuP11zjUBCXfYyHO3l3E8BTLwTLUbt8OXhHupjNvfY9MdYHfG7e8yJIpGuMN2DN2Bghi3w9KEe5GM25ewxdBduwNBrX+iMW5fhhNNKMIdXvdCu3sjVYALL4zbVTtlEu7lMW7fm4UZIHOWZGJxoolDuMNbLMwA/MKSDKxGuBfGuD0NTy/MaHcghCfPMsbtqXCWCUK4w7vcGhJgM8btlEy4l8S4PSWG7kBujNtDc5aJQLjDAjYaujuqAsnaZDZk3E7hhHsxjNvT49aQQLGM21NkPJQ84Q7LMHQHymXcDpsQ7mUwbk+VoTtQIOP2dBkPpU24w2IM3YESGbfDVoR7AYzb0/bK0F27A4l4/hRj3J46p5iECXdYknu6AyzOuB0mwh32Z+gOhGTcDtsS7rmzJ7M5Q3eABRm378BsKFXCHZJg6A4EY9wOmxPuWTNu38l2Q3ftDuxiq/OLcftunF+StEO4931/8FQgdy+0u3u6Axl7Ydyu2uHC1uE+jmPXdRs/aKGM2wOyMAMEYEmmEM4v6dk63Nu27ft+4weFXbhKFeBlxu1wbdNw77qubdumabZ80EIZt4dl6A4kzbi9KM4vidku3IdhGIahbdvNHhF25ypVICuuSYVd/bbNw4zj2LbtMAzbPByENg3dDaiADDiawYI2mrhPSzJ1XW/zcKWzJ5OS14buFmaA5Gy1JGPcnhYnl5RsFO7/93//99dffx3+VVXV4XB46vYyhzvW+ooBAOCOXdL0cNxjNHs4PPe4z3580Yzbk/TaAOmVYZUnALAG4/bCObnMtmq1eudUAAAIQLjnxTfEqbLpDgRm3I6TSxr2CXd7L7Aih1dgQUZCkAwT94w4tqZtu6E7wK6M2/NkKpQA4Q6pszAD7Mb7pEJKhHsujNsj2O6NVAFCMW6PwVRob8IdAjB0B3Zg3A6JEe6wKUN3gAvG7TCTcM+CPZlQ3BoSCMAtILnJmWVXwh3CcIcZIFmWZGADwj0+4/aAtluYMRoBXrB08bTnAAAWWklEQVTVmcW4PSRnlv0Id4jEwgywOtekQqqEe3DG7WG5ShUonHF7YEZCOxHuEIyhO7Ai43ZImHCPzLg9OEN3oFjG7eEZCe1BuEM8hu7AKozbIW3CPSzj9iwYugMFMm7PhJHQ5oQ7hGToDizMuB2SJ9xhZ4buQFGM2+Flwj0mezIYugMLMm7nNU4r2xLusD9Dd6AQxu3wDuEOgRm6AwswbocghHtA9mRyZOgOZM+4PU/mQRsS7hCboTvwFuN2iEO4R2Pcni9DdyBjxu05Mw/ainCHhLzW7obuwIu2GrerdliEcAcAgACEeyj2ZApg6A5sxLidBTmnbEK4Q8EcZ6FYJkEQkHCH5Gw3dAeYzbgddifc4zAdKcl2d5gxdIcCbXVCUe1lcUJZn3CHfBi6Aytx73ZIgXCHRBm6A6swboewhHsQ9mSYx9AdWJxxO3OZBK1MuEO6DN2BhRm3Q2TCHXJj6A4syLgd0iHcI7AnUzBDd2Axxu1swNlkTcIdUvdCuxu6A4t4Ydyu2mE9wj15xu1sxpgEMuZswmacTVYj3CEAQ3dge8btkBrhDpwxJoEsGbdDFoR72hxq+ZehO7Al43beYgy0DuEOYWx0hxlHW8jMJjMg1Q4bEO6QM0N34AXu3Q5pEu4JsyfDlY0WZgzdIRvPn0osybAMp5IVCHfgFgdcyIABEORFuEMwrlIF1mPcDikT7qkyJmF3hu4QmvMIu3MeWZpwh3gM3YE1GLdD4oQ7hOTWkMAjbgEJORLuSfLvm6zgxaG7dodwXjqJuAUkq3ASWZRwh6g2GroD3GLcDtsT7lAQQ3fIn3E75Eu4p8eeDLMZugO7MG7nCaY/yxHuUBZDd8iZcTtkTbhDbIbuwMaM22Evwj0x9mRYn6E75Mm4nWQ5gyxEuEN42w3dHXkhWVvNfYzbYUfCHXLwbLt7I1Wgen7crtphX8I9JfZkSJ+hOyTI6YP0OX0sQbhDJgzdgacYt0M4wh3K5SpVyIFrUqEYwj0Z/qGTt7lKFYrjmlQCce54m3CHolmYgQIZt0NQwh2yYugOBTFuh8II9zTYk2E5rlIFHnBNKnsy9HmPcAde5fgLOzLxgfIId8iQoTtwk3E7hCbcE2BqQlyG7rALJw7icuJ4g3CHPBm6AxeM2yE64Q68x+wENmbcDqUS7ntz/GU1hu7AiXE7CTHxeZVwB97mEAybMe6Bggl3yJmhO1AZt0MuhPuuDE5Y30bvpWroDhvY5Kyh2tmCs8ZLhDvwC0N3yMyz43YgWcId8mfoDjkwbofiCXfgkqE7ZMO4HXIi3PdjwZ0NbXSVqqE7rOSlU4ZrUkmaU8bzhDuwKAdiWJxBD1BVlXCHcrg1JBTFuB3yI9x3YnzCHizMQDyWZMiY88WThDsAAAQg3KEshu4QiXE7cEa478GeDABAZdDzHOEOxTF0hxiM24FfCXfga+4wAyF4uyXIm3CHEj07dH/1YQzd4VWbLFUat0Mswn1zFtyJydAdEmfcTlSmPLMJdyjUC0P3V9rd4Rhe8PyI54VqN26HcIQ7lGujhRkgPaodIhLu27InQ3CG7rC6TcbtkBZninmEOxTN0B0KZNwOQQl34DmG7rAi43bgPuG+IXsyJGmjq1SBFbgmlXwY8cwg3IFNFmYckeFL6893VDuEJtyBVxi6w+4syUBphDtQVYbusDvjduArwn0rFtzJjqE77Mi4nQyZ73xFuAP/MHSH3Ri3AzMId+CnZ9vd0B128ey4XbVDHoT7JuzJkK+n293QHS48eY6wJEPOnCMeEu7AL7yXKmTGuB2yIdyBdxm6w+uM24HZhPv67MkQjaE7ZMO4nXgMd+4T7sANq1+l6rgM1erjdtUOmRHuAAAQgHBfmT0ZwjJ0h3UZt8M9ThB3CHfgLsvuEJRqhywJd+CRp9rd0B3mWnPcrtohV8IdWJL3UoXFuQUkMBHua7LgThbWXZgxdKdAa54djNvJhLPDLcId+Nq6CzPAfZZkgBPhDuzNWIWi+MdY4FXCfTUOzeTFVaqwANekwnxODVe2C/eu6+q6PhwOdV0Pw7DZ4wJLcXdISJZqhxJsFO5t21ZVNQzD8XgchqHrur7vt3loYEHz293QHS6tNm5X7VCI37Z5mKZppnavqqqu677vz38mQ/Zk4N92f+I2dlO7e+2QpZXfJxXy5Lzwq00n7kAGLMxAUozboRz7XJza972Uh7gszMBzLMkAS9hoVeZc3/fDMOR8fap/0wEAWIRtmTNbT9y7rsu82qEMhu4wl3E7sJDtwn0cx2k95rX7yRzuWPaLBOZbcdldu5ON1SaFqh32tUuabrcq07Zt13VN07z2249R/onEv+bAladvLwOl8kqBG5LclrmXpqu2+3Z3lWnb9uVqB9Jk6A6PGLcDizpsM8m++c3Hjx8/6rqe+dtN3CFZMxvilVGiFxRxPf/snfkaUe2UKM7pYNVq3WhVJkx2A6uxMAMPeHUAX9rnPu7ZivPtICzIwgxcsiQDy3I6qKpKuANbevrWkFAG43ZgDuEOLMBt3eEnN24H1iHcl2NPhrJZmIGqsiQDq3EuEO7A9izMwIklGWA+4Q4sxsIMpbMkA6xJuC/EngxUVbXqwgyUSrXDP4of4gh3YB+G7uRmtXE7wES4AwszdIcFGbcDJ8IdWN7Mdjd0Jx/rjNtVO3BOuC/Bgju8SruTA0sysJmyzwLCHViFhRl4k3E7cEG4A2uxMEMRLMkAWxHuwIrWaneISbUD7xDub7PgDtszdCcRTgGwvYJPAcIdWJehO0yM24E3CXdgdau0e8ETF1LxzLhdtQPvE+5AQszdyZL7PwKLEO7vsd0I86xyd0hDd3a0wvHfuB3mKvX4L9yBjViYIR+WZIA9CHcgORZmyIYlGWBBwv0N9mTgSRZmyIElGUhBkQd/4Q5syt0hKYclGWBZwh1I1BPtXuTchX3MHrdbkgEWJ9yBrc1fmNHupGWFajduB+YT7q+y4A5vWGXZHaJR7fCW8kY2wh3Yx/LL7uUdwdnU0uN21Q48S7gDqXOhKoFYbQfWI9yB3Sy/MGPozkqWXo80bgdeINxfYsEdFmJhhgAsyUCyCjvmC3cgBgszJM6SDLA24Q7szMIMSbMkAyRDuAP783aqRGdJBtiAcH+eBXdYwcLtbujOIuYd8FU77KmkA75wB1Kx8M5MSYdyVrHomEa1A+8T7kAwFmZIimtSgc0IdyAhhu6kwrgdSI9wf5IFd1jZnHY3dCcRc8btqh1WV8yYRrgDyVmy3Ys5mrOk5a5JVe3AgoQ7kKIld2a0O09Z7l9WVTuwLOH+DHsysKEv293CDDv6ctyu2mFTZcxohDsQmIUZFrbojdsBliXcgXS5UJUEWW0H9iLcgaQttuxu6M6XFtqHVO3ASoT7bBbcYSeLLbtrdx5YaElGtcNuCjjIC3cgABeqkgLVDuxLuAOZmNXuBcxjeMWMcbsLUoHdCXcghiXv7A4rMG4H1ibc57HgDglYZmHG0J0LS4zbVTskIfcjvHAHItHuLEy1A3EIdyAY7c5iVDsQinAH4rHvTiJUO7Al4T6DBXeIxtCdr7mTDGQp62O7cAdCsjDDWyzJAAEJdyAq7c6LVDsQk3AHArPszi5UO7AL4f4VC+6QtsftbujOpbfH7aodUpfvUV24A5nT7vzkglQgMuEOhGfZnVmstgPBCXcgB5bd2YBqB/Yl3B+y4A5xWHbnEavtUJRMj+fCHciHduc21Q5kQbgDWdHuXFLtQC6EO8AV7Z4NG49ARoT7fQ73ENMCQ3dKYtwOecpxBCPcgQxZmKGqLMkAuRHuQJ60e+lUO5Ad4Q5kS7uXS7UDORLud1hwhyzYd+cm1Q5FyG74ItyBzL3b7tkd9/P31eRFtQNBCXcgf9q9IKodyJdwB4qg3Yug2oGsCfdbLLhDjuy7F061Q4nyGrsId6Agb7V7Xkf/DD2cuah2IAPCHSiLds+TagcKINyB4mj33Kh2oAzCHSiRffdCqHYgJ8L9iitToQyvt7uhe1LuH7RVO1BVWR20D8cIkXo4bPh1CncoyeN6e1R+jhUpeKnap2/YVDsUZMMj9qrVKtxvPJiTMRTlccZp93S9Wu2SHYqTS7hblQFKd/zzi7WZ+78zn39+jeel07BqB0IT7r8yP4NS3Wt3N5lJ0Uu3kVHtUK5cjtXCHeAfL7Y7KVHtQMaEO8BPr7R7LoOcMJ5fbVftQB6EO8AvtHvSVDtQMOF+xoI7UFWVdk+WagdelsVRWrgD3KDdk6PageK5j/svD2PiDpy7d4t3N3ff2pPV7i2WgBs2OT57AybhDuzp5uB2mrvfzncHk2Xd+fu893+BQTtwm3DfhnAH9nWvBe+O3h1PlnK/2q3HAM+JH+523P/lLAvc5xbvSVHtwCviX4kk3AFmea7d458eknBrpKLagWJZlfn5GCbuwJeeu1zVgeUds6vdpajAXOsflu24C3cgLfcuV9Xui3mm2iU7MJdw38Dq4e7MCjzp5pRXuy9jXrUbtAOvWPmYLNyFO5Co63Gvdn/X7GqX7MArhPvahDuQrOu57+37izvOzHH1t3T9l2nQDrxFuK9NuAOJmzV6d6h57Fa1G7QDCxPua1s33J1KgSXcHL3faPeqcsy5dOuv5eJvz6AdWMya7SfchTsQxsVI2Mr712YstRu0A0sS7qsS7kAgF7Nh7f7IV9Vu0A4sT7ivSrgD4ZwPiV2uettXl6IatAOrEO6rEu5ARF+P3ks+/jy8FNWgHViRcF/Vin8FJZ81gU18MXov8HLVqz+yQTuwtdUKULgLdyC2WaP3qoB8/+ruMQbtwEaE+3qEO5CB8yotcev94Ua7ZAc2JdzXI9yBbFzkexGj94e7MZId2IFwX89afwWqHdjJqVbvjt6rLPJdsgPJWqcDhbtwB/L0db6HPkb9+vVLdiAtwn0lwh3I2KN8Dzp6//XLluxAioT7SoQ7kL2paKuqqprI+X4n2U9/OskOpEK4P9D3fdd1n5+fHx8fXde1bTv/967yV6DagST907jNYfrhz4JPPN8fJrteB1K0Qg3mEO7DMLRt2/d90zTn/3vmbxfuQGnuDuATzPdbyV4N//xQsgPpEu43tW3bNM1pyt73/TAMfd/P/O3CHSjWecEnl+/Xya7XgUCE+011XQ/DUNf19MNxHJumGcdx5m8X7gA31sR3zPeLZLfCDkQk3G8/zNWf4ak/1fJ/BaodCOvnDH4K5Y3z/d+Hu/wyACJaugmFu3AHuO2Xeu5WPrIdDofu5+cX60AOhPuNhxHuACs7j/iTl/N62c8GkKhQ4f7bSp/3wsfHxziO5zvuHx8fT32Gw+Fw8+dD3IceYAM3q/pmf7/82QCY3EvTVW0U7qe7QE4/fOpekJMlA924HSiG/gZ45Hh8rQzvpemqQb9RuHdd1zRNXddTwU+3g9zmoQEAIAPbvXPqNHGf3jn12Yn7wttCJu4AAEwWLcMcLk59k3AHAGAVccL9Pyt93nSpdgAATqY19wjKC3cAAAhIuAMAQADCHQAAAigs3C24AwBwIciae2HhDgAAMQl3AAAIQLgDAEAAJYW7BXcAAG6KsOZeUrgDAEBYwh0AAAIQ7gAAEEAx4W7BHQCAB5Jfcy8m3AEAIDLhDgAAAQh3AAAIoIxwt+AOAMCX0l5zLyPcAQAgOOEOAAABCHcAAAiggHC34A4AwEwJr7kXEO4AABCfcAcAgACEOwAABJB7uFtwBwDgKamuuece7gAAkAXhDgAAAQh3AAAIIOtwt+AOAMALklxzzzrcAQAgF8IdAAACEO4AABBAvuFuwR0AgJelt+aeb7gDAEBGhDsAAAQg3AEAIIBMw92COwAAb0pszT3TcAcAgLwIdwAACEC4AwBAAMIdAAACyDHcXZkKAMAiUro+NcdwBwCA7Ah3AAAIQLgDAEAAwh0AAALILtxdmQoAwIKSuT41u3AHAIAcCXcAAAhAuAMAQAB5hbsFdwAAFpfGmnte4Q4AAJkS7gAAEIBwBwCAAIQ7AAAEkFG4uzIVAICVJHB9akbhDgAA+RLuAAAQgHAHAIAAhDsAAASQS7i7MhUAgFXtfX1qLuEOAABZE+4AABCAcAcAgACyCHcL7gAAbGDXNfcswh0AAHIn3AEAIADhDgAAAQh3AAAIIH64uzIVAIDN7Hd9avxwBwCAAgh3AAAIQLgDAEAAwh0AAAIIHu6uTAUAYGM7XZ8aPNwBAKAMwh0AAAIQ7gAAEEDkcLfgDgDALvZYc48c7gAAUAzhDgAAAQh3AAAIQLgDAEAAYcPdlakAAOxo8+tTw4Y7AACURLgDAEAAwh0AAAIQ7gAAEEDMcHdlKgAAu9v2+tSY4Q4AAIUR7gAAEIBwBwCAAAKGuwV3AAASseGae8BwBwCA8gh3AAAIQLgDAEAAwh0AAAKIFu6uTAUAIClbXZ8aLdwBAKBIwh0AAAIQ7gAAEIBwBwCAAEKFuytTAQBI0CbXp4YKdwAAKJVwBwCAAIQ7AAAEECfcLbgDAJCs9dfc44Q7AAAUTLgDAEAAwh0AAAIQ7gAAEECccHdlKkEc1n//BViE5yqBeLoSw8q9umm4d11X1/XhcKjrehiGLR8aAABC2y7c27atqmoYhuPxOAxD13V932/26AAAENrhuNUKSt/3U7tPxnFsmmYcxzm/93DY7uuEN3m6EoXnKoF4uhLFqs/VrSfuAADAC3a7OPViAA8AADzw2y6P2vf9MAyuTwUAgJlWDPfTnZsuFn26rhvHUbUDAMB8K4b79WL+OI7THSFfuJ+MG7gSiKcrUXiuEoinK2x6jXbTNF3XNU2z2SMCAEAeNr2rTNu2qh0AAF6w3cT95r9w/fjxo67rbb4AAACIy9sZAABAALvdxx0AAJhPuAMAQADCHQAAAhDuAAAQgHAHAIAAhDsAAAQg3AEAIIAUw30cx7Ztb75hU9/3dV0fDoe6rvu+3/xLg0em5+057y9GmhxLicJxlZRtn6zJhXvf903TNE1z/UvDMHRd1/f98Xjs+77rumEYtv764L5xHH/8+HE8M47j3l8UXHIsJRDHVZK1S7ImF+7DMAzD0Lbt9S9Nf/LpL6hpmulvZNuvDiA8x1KA9+2SrIfj8bjIJ1rc4XD5tdV1PQzD6d/IxnFsmsZ33qTj4ikKaXIsJRDHVdK3ZbImN3F/4PPz8/ylW9f15+fnfl8O3DC9OK0OkzLHUmJxXCWc9Q6zvy3yWYDq3++wp+tRTv98dvMf0QCYw3EVzu2/KnO6FPfiK7n+d4c5PwNbuvfsnUznGBsIpMaxlLgcV0nQlsm6/6rM6TrxLz/y4+Pj/LU6juPHx8eKXxl85fGzt2kaGwgkyLGUuBxXCWG9w+z+4T5f0zTnN9OZ7sKz21cDVy6GQMMwfPv2baevBe5yLCUQx1UiWvEwe0zV9df248ePj4+Pv//++3g8/v333x8fHxf3doV9ffv27c8//5yeltNT9H//+9/OXxNccSwlEMdV0rdlsiYX7o+/u5j+8FVVnf46IB0/fvz4448/Tk9RZxeS5VhKFI6rJGuXZHVBEgAABBBpxx0AAIol3AEAIADhDgAAAQh3AAAIQLgDAEAAwh0AAAIQ7gAAEIBwBwCAAIQ7AAAEINwBACAA4Q4AAAEIdwAACEC4AwBAAMIdAAACEO4AABDA/wMGe78+0EiB5wAAAABJRU5ErkJggg==]]></Image> | |
4 | <CoordSystem> | |
5 | <General CursorSize="3" ExtraPrecision="1"/> | |
6 | <Coords Type="0" TypeString="Cartesian" Coords="0" ScaleXTheta="0" ScaleXThetaString="Linear" ScaleYRadius="0" ScaleYRadiusString="Linear" UnitsX="0" UnitsXString="Number" UnitsY="0" UnitsYString="Number" UnitsTheta="0" UnitsThetaString="Degrees (DDD.DDDDD)" UnitsRadius="0" UnitsRadiusString="Number" UnitsDate="3" UnitsDateString="YYYY/MM/DD" UnitsTime="2" UnitsTimeString="HH:MM:SS"/> | |
7 | <DigitizeCurve CursorInnerRadius="5" CursorLineWidth="2" CursorSize="1" CursorStandardCross="True"/> | |
8 | <Export PointsSelectionFunctions="0" PointsSelectionFunctionsString="InterpolateAllCurves" PointsIntervalFunctions="10" PointsIntervalUnitsFunctions="1" PointsSelectionRelations="0" PointsSelectionRelationsString="Interpolate" PointsIntervalUnitsRelations="1" PointsIntervalRelations="10" LayoutFunctions="0" LayoutFunctionsString="AllPerLine" Delimiter="3" OverrideCsvTsv="True" DelimiterString="Semicolons" Header="1" HeaderString="Simple" XLabel="x"> | |
9 | <CurveNamesNotExported/> | |
10 | </Export> | |
11 | <AxesChecker Mode="1" Seconds="3" LineColor="6"/> | |
12 | <GridDisplay Stable="True" DisableX="0" CountX="5" StartX="-10" StepX="5" StopX="10" DisableY="0" CountY="4" StartY="-5" StepY="5" StopY="10" Color="0" ColorString="Black"/> | |
13 | <GridRemoval Stable="False" DefinedGridLines="False" CloseDistance="10" CoordDisableX="0" CoordDisableXString="Count" CountX="9" StartX="-10.0058" StepX="2.49611" StopX="9.96305" CoordDisableY="0" CoordDisableYString="Count" CountY="14" StartY="-2.01332" StepY="0.923125" StopY="9.98731"/> | |
14 | <PointMatch PointSize="48" ColorAccepted="4" ColorAcceptedString="Green" ColorCandidate="7" ColorCandidateString="Yellow" ColorRejected="6" ColorRejectedString="Red"/> | |
15 | <Segments PointSeparation="25" MinLength="2" FillCorners="False" LineWidth="4" LineColor="4" LineColorString="Green"/> | |
16 | <Curve CurveName="Axes"> | |
17 | <ColorFilter CurveName="Axes" Mode="2" ModeString="Intensity" IntensityLow="0" IntensityHigh="50" ForegroundLow="0" ForegroundHigh="10" HueLow="180" HueHigh="360" SaturationLow="50" SaturationHigh="100" ValueLow="0" ValueHigh="50"/> | |
18 | <CurveStyle CurveName="Axes"> | |
19 | <LineStyle Width="0" Color="8" ColorString="Transparent" ConnectAs="4" ConnectAsString="ConnectSkipForAxisCurve"/> | |
20 | <PointStyle Radius="10" LineWidth="1" Color="6" ColorString="Red" Shape="1" ShapeString="Cross"/> | |
21 | </CurveStyle> | |
22 | <CurvePoints> | |
23 | <Point Identifier="Axes	point	13" Ordinal="1" IsAxisPoint="True" IsXOnly="False" Index="76"> | |
24 | <PositionScreen X="54.5868" Y="760.999"/> | |
25 | <PositionGraph X="-10" Y="-2"/> | |
26 | </Point> | |
27 | <Point Identifier="Axes	point	15" Ordinal="2" IsAxisPoint="True" IsXOnly="False" Index="76"> | |
28 | <PositionScreen X="969.674" Y="759.096"/> | |
29 | <PositionGraph X="10" Y="-2"/> | |
30 | </Point> | |
31 | <Point Identifier="Axes	point	17" Ordinal="3" IsAxisPoint="True" IsXOnly="False" Index="76"> | |
32 | <PositionScreen X="55.345" Y="19.9762"/> | |
33 | <PositionGraph X="-10" Y="10"/> | |
34 | </Point> | |
35 | </CurvePoints> | |
36 | </Curve> | |
37 | <CurvesGraphs> | |
38 | <Curve CurveName="Curve1"> | |
39 | <ColorFilter CurveName="Curve1" Mode="2" ModeString="Intensity" IntensityLow="0" IntensityHigh="50" ForegroundLow="0" ForegroundHigh="10" HueLow="180" HueHigh="360" SaturationLow="50" SaturationHigh="100" ValueLow="0" ValueHigh="50"/> | |
40 | <CurveStyle CurveName="Curve1"> | |
41 | <LineStyle Width="1" Color="1" ColorString="Blue" ConnectAs="0" ConnectAsString="FunctionSmooth"/> | |
42 | <PointStyle Radius="10" LineWidth="1" Color="1" ColorString="Blue" Shape="1" ShapeString="Cross"/> | |
43 | </CurveStyle> | |
44 | <CurvePoints> | |
45 | <Point Identifier="Curve1	point	18" Ordinal="0" IsAxisPoint="False" IsXOnly="False" Index="76"> | |
46 | <PositionScreen X="58" Y="265"/> | |
47 | </Point> | |
48 | <Point Identifier="Curve1	point	19" Ordinal="1" IsAxisPoint="False" IsXOnly="False" Index="76"> | |
49 | <PositionScreen X="70" Y="243"/> | |
50 | </Point> | |
51 | <Point Identifier="Curve1	point	20" Ordinal="2" IsAxisPoint="False" IsXOnly="False" Index="76"> | |
52 | <PositionScreen X="85" Y="223"/> | |
53 | </Point> | |
54 | <Point Identifier="Curve1	point	21" Ordinal="3" IsAxisPoint="False" IsXOnly="False" Index="76"> | |
55 | <PositionScreen X="102" Y="205"/> | |
56 | </Point> | |
57 | <Point Identifier="Curve1	point	22" Ordinal="4" IsAxisPoint="False" IsXOnly="False" Index="76"> | |
58 | <PositionScreen X="123" Y="192"/> | |
59 | </Point> | |
60 | <Point Identifier="Curve1	point	23" Ordinal="5" IsAxisPoint="False" IsXOnly="False" Index="76"> | |
61 | <PositionScreen X="148" Y="188"/> | |
62 | </Point> | |
63 | <Point Identifier="Curve1	point	24" Ordinal="6" IsAxisPoint="False" IsXOnly="False" Index="76"> | |
64 | <PositionScreen X="171" Y="196"/> | |
65 | </Point> | |
66 | <Point Identifier="Curve1	point	25" Ordinal="7" IsAxisPoint="False" IsXOnly="False" Index="76"> | |
67 | <PositionScreen X="190" Y="210"/> | |
68 | </Point> | |
69 | <Point Identifier="Curve1	point	26" Ordinal="8" IsAxisPoint="False" IsXOnly="False" Index="76"> | |
70 | <PositionScreen X="194" Y="213"/> | |
71 | </Point> | |
72 | <Point Identifier="Curve1	point	27" Ordinal="9" IsAxisPoint="False" IsXOnly="False" Index="76"> | |
73 | <PositionScreen X="211" Y="231"/> | |
74 | </Point> | |
75 | <Point Identifier="Curve1	point	28" Ordinal="10" IsAxisPoint="False" IsXOnly="False" Index="76"> | |
76 | <PositionScreen X="226" Y="251"/> | |
77 | </Point> | |
78 | <Point Identifier="Curve1	point	29" Ordinal="11" IsAxisPoint="False" IsXOnly="False" Index="76"> | |
79 | <PositionScreen X="241" Y="271"/> | |
80 | </Point> | |
81 | <Point Identifier="Curve1	point	30" Ordinal="12" IsAxisPoint="False" IsXOnly="False" Index="76"> | |
82 | <PositionScreen X="254" Y="293"/> | |
83 | </Point> | |
84 | <Point Identifier="Curve1	point	31" Ordinal="13" IsAxisPoint="False" IsXOnly="False" Index="76"> | |
85 | <PositionScreen X="267" Y="314"/> | |
86 | </Point> | |
87 | <Point Identifier="Curve1	point	32" Ordinal="14" IsAxisPoint="False" IsXOnly="False" Index="76"> | |
88 | <PositionScreen X="280" Y="336"/> | |
89 | </Point> | |
90 | <Point Identifier="Curve1	point	33" Ordinal="15" IsAxisPoint="False" IsXOnly="False" Index="76"> | |
91 | <PositionScreen X="291" Y="358"/> | |
92 | </Point> | |
93 | <Point Identifier="Curve1	point	34" Ordinal="16" IsAxisPoint="False" IsXOnly="False" Index="76"> | |
94 | <PositionScreen X="303" Y="380"/> | |
95 | </Point> | |
96 | <Point Identifier="Curve1	point	35" Ordinal="17" IsAxisPoint="False" IsXOnly="False" Index="76"> | |
97 | <PositionScreen X="315" Y="401"/> | |
98 | </Point> | |
99 | <Point Identifier="Curve1	point	36" Ordinal="18" IsAxisPoint="False" IsXOnly="False" Index="76"> | |
100 | <PositionScreen X="327" Y="424"/> | |
101 | </Point> | |
102 | <Point Identifier="Curve1	point	37" Ordinal="19" IsAxisPoint="False" IsXOnly="False" Index="76"> | |
103 | <PositionScreen X="338" Y="446"/> | |
104 | </Point> | |
105 | <Point Identifier="Curve1	point	38" Ordinal="20" IsAxisPoint="False" IsXOnly="False" Index="76"> | |
106 | <PositionScreen X="350" Y="468"/> | |
107 | </Point> | |
108 | <Point Identifier="Curve1	point	39" Ordinal="21" IsAxisPoint="False" IsXOnly="False" Index="76"> | |
109 | <PositionScreen X="363" Y="489"/> | |
110 | </Point> | |
111 | <Point Identifier="Curve1	point	40" Ordinal="22" IsAxisPoint="False" IsXOnly="False" Index="76"> | |
112 | <PositionScreen X="375" Y="511"/> | |
113 | </Point> | |
114 | <Point Identifier="Curve1	point	41" Ordinal="23" IsAxisPoint="False" IsXOnly="False" Index="76"> | |
115 | <PositionScreen X="389" Y="532"/> | |
116 | </Point> | |
117 | <Point Identifier="Curve1	point	42" Ordinal="24" IsAxisPoint="False" IsXOnly="False" Index="76"> | |
118 | <PositionScreen X="403" Y="553"/> | |
119 | </Point> | |
120 | <Point Identifier="Curve1	point	43" Ordinal="25" IsAxisPoint="False" IsXOnly="False" Index="76"> | |
121 | <PositionScreen X="418" Y="573"/> | |
122 | </Point> | |
123 | <Point Identifier="Curve1	point	44" Ordinal="26" IsAxisPoint="False" IsXOnly="False" Index="76"> | |
124 | <PositionScreen X="434" Y="592"/> | |
125 | </Point> | |
126 | <Point Identifier="Curve1	point	45" Ordinal="27" IsAxisPoint="False" IsXOnly="False" Index="76"> | |
127 | <PositionScreen X="451" Y="609"/> | |
128 | </Point> | |
129 | <Point Identifier="Curve1	point	46" Ordinal="28" IsAxisPoint="False" IsXOnly="False" Index="76"> | |
130 | <PositionScreen X="471" Y="625"/> | |
131 | </Point> | |
132 | <Point Identifier="Curve1	point	47" Ordinal="29" IsAxisPoint="False" IsXOnly="False" Index="76"> | |
133 | <PositionScreen X="542" Y="631"/> | |
134 | </Point> | |
135 | <Point Identifier="Curve1	point	48" Ordinal="30" IsAxisPoint="False" IsXOnly="False" Index="76"> | |
136 | <PositionScreen X="564" Y="619"/> | |
137 | </Point> | |
138 | <Point Identifier="Curve1	point	49" Ordinal="31" IsAxisPoint="False" IsXOnly="False" Index="76"> | |
139 | <PositionScreen X="582" Y="603"/> | |
140 | </Point> | |
141 | <Point Identifier="Curve1	point	50" Ordinal="32" IsAxisPoint="False" IsXOnly="False" Index="76"> | |
142 | <PositionScreen X="600" Y="584"/> | |
143 | </Point> | |
144 | <Point Identifier="Curve1	point	51" Ordinal="33" IsAxisPoint="False" IsXOnly="False" Index="76"> | |
145 | <PositionScreen X="615" Y="565"/> | |
146 | </Point> | |
147 | <Point Identifier="Curve1	point	52" Ordinal="34" IsAxisPoint="False" IsXOnly="False" Index="76"> | |
148 | <PositionScreen X="629" Y="544"/> | |
149 | </Point> | |
150 | <Point Identifier="Curve1	point	53" Ordinal="35" IsAxisPoint="False" IsXOnly="False" Index="76"> | |
151 | <PositionScreen X="643" Y="523"/> | |
152 | </Point> | |
153 | <Point Identifier="Curve1	point	54" Ordinal="36" IsAxisPoint="False" IsXOnly="False" Index="76"> | |
154 | <PositionScreen X="656" Y="502"/> | |
155 | </Point> | |
156 | <Point Identifier="Curve1	point	55" Ordinal="37" IsAxisPoint="False" IsXOnly="False" Index="76"> | |
157 | <PositionScreen X="668" Y="480"/> | |
158 | </Point> | |
159 | <Point Identifier="Curve1	point	56" Ordinal="38" IsAxisPoint="False" IsXOnly="False" Index="76"> | |
160 | <PositionScreen X="681" Y="459"/> | |
161 | </Point> | |
162 | <Point Identifier="Curve1	point	57" Ordinal="39" IsAxisPoint="False" IsXOnly="False" Index="76"> | |
163 | <PositionScreen X="692" Y="436"/> | |
164 | </Point> | |
165 | <Point Identifier="Curve1	point	58" Ordinal="40" IsAxisPoint="False" IsXOnly="False" Index="76"> | |
166 | <PositionScreen X="704" Y="414"/> | |
167 | </Point> | |
168 | <Point Identifier="Curve1	point	59" Ordinal="41" IsAxisPoint="False" IsXOnly="False" Index="76"> | |
169 | <PositionScreen X="716" Y="392"/> | |
170 | </Point> | |
171 | <Point Identifier="Curve1	point	60" Ordinal="42" IsAxisPoint="False" IsXOnly="False" Index="76"> | |
172 | <PositionScreen X="728" Y="370"/> | |
173 | </Point> | |
174 | <Point Identifier="Curve1	point	61" Ordinal="43" IsAxisPoint="False" IsXOnly="False" Index="76"> | |
175 | <PositionScreen X="740" Y="348"/> | |
176 | </Point> | |
177 | <Point Identifier="Curve1	point	62" Ordinal="44" IsAxisPoint="False" IsXOnly="False" Index="76"> | |
178 | <PositionScreen X="751" Y="326"/> | |
179 | </Point> | |
180 | <Point Identifier="Curve1	point	63" Ordinal="45" IsAxisPoint="False" IsXOnly="False" Index="76"> | |
181 | <PositionScreen X="765" Y="305"/> | |
182 | </Point> | |
183 | <Point Identifier="Curve1	point	64" Ordinal="46" IsAxisPoint="False" IsXOnly="False" Index="76"> | |
184 | <PositionScreen X="777" Y="283"/> | |
185 | </Point> | |
186 | <Point Identifier="Curve1	point	65" Ordinal="47" IsAxisPoint="False" IsXOnly="False" Index="76"> | |
187 | <PositionScreen X="791" Y="263"/> | |
188 | </Point> | |
189 | <Point Identifier="Curve1	point	66" Ordinal="48" IsAxisPoint="False" IsXOnly="False" Index="76"> | |
190 | <PositionScreen X="806" Y="243"/> | |
191 | </Point> | |
192 | <Point Identifier="Curve1	point	67" Ordinal="49" IsAxisPoint="False" IsXOnly="False" Index="76"> | |
193 | <PositionScreen X="822" Y="223"/> | |
194 | </Point> | |
195 | <Point Identifier="Curve1	point	68" Ordinal="50" IsAxisPoint="False" IsXOnly="False" Index="76"> | |
196 | <PositionScreen X="835" Y="211"/> | |
197 | </Point> | |
198 | <Point Identifier="Curve1	point	69" Ordinal="51" IsAxisPoint="False" IsXOnly="False" Index="76"> | |
199 | <PositionScreen X="855" Y="196"/> | |
200 | </Point> | |
201 | <Point Identifier="Curve1	point	70" Ordinal="52" IsAxisPoint="False" IsXOnly="False" Index="76"> | |
202 | <PositionScreen X="878" Y="188"/> | |
203 | </Point> | |
204 | <Point Identifier="Curve1	point	71" Ordinal="53" IsAxisPoint="False" IsXOnly="False" Index="76"> | |
205 | <PositionScreen X="902" Y="192"/> | |
206 | </Point> | |
207 | <Point Identifier="Curve1	point	72" Ordinal="54" IsAxisPoint="False" IsXOnly="False" Index="76"> | |
208 | <PositionScreen X="923" Y="204"/> | |
209 | </Point> | |
210 | <Point Identifier="Curve1	point	73" Ordinal="55" IsAxisPoint="False" IsXOnly="False" Index="76"> | |
211 | <PositionScreen X="941" Y="222"/> | |
212 | </Point> | |
213 | <Point Identifier="Curve1	point	74" Ordinal="56" IsAxisPoint="False" IsXOnly="False" Index="76"> | |
214 | <PositionScreen X="956" Y="242"/> | |
215 | </Point> | |
216 | <Point Identifier="Curve1	point	75" Ordinal="57" IsAxisPoint="False" IsXOnly="False" Index="76"> | |
217 | <PositionScreen X="968" Y="264"/> | |
218 | </Point> | |
219 | </CurvePoints> | |
220 | </Curve> | |
221 | </CurvesGraphs> | |
222 | </CoordSystem> | |
223 | </Document> |
3148 | 3148 | <message> |
3149 | 3149 | <location filename="../src/Callback/CallbackAxisPointsAbstract.cpp" line="123"/> |
3150 | 3150 | <location filename="../src/Callback/CallbackAxisPointsAbstract.cpp" line="217"/> |
3151 | <source>New axis point cannot be at the same screen position as an exisiting axis point</source> | |
3151 | <source>New axis point cannot be at the same screen position as an existing axis point</source> | |
3152 | 3152 | <translation type="unfinished"></translation> |
3153 | 3153 | </message> |
3154 | 3154 | <message> |
3191 | 3191 | <message> |
3192 | 3192 | <location filename="../src/Callback/CallbackAxisPointsAbstract.cpp" line="123"/> |
3193 | 3193 | <location filename="../src/Callback/CallbackAxisPointsAbstract.cpp" line="217"/> |
3194 | <source>New axis point cannot be at the same screen position as an exisiting axis point</source> | |
3194 | <source>New axis point cannot be at the same screen position as an existing axis point</source> | |
3195 | 3195 | <translation type="unfinished"></translation> |
3196 | 3196 | </message> |
3197 | 3197 | <message> |
3192 | 3192 | <message> |
3193 | 3193 | <location filename="../src/Callback/CallbackAxisPointsAbstract.cpp" line="123"/> |
3194 | 3194 | <location filename="../src/Callback/CallbackAxisPointsAbstract.cpp" line="217"/> |
3195 | <source>New axis point cannot be at the same screen position as an exisiting axis point</source> | |
3195 | <source>New axis point cannot be at the same screen position as an existing axis point</source> | |
3196 | 3196 | <translation type="unfinished"/> |
3197 | 3197 | </message> |
3198 | 3198 | <message> |
3191 | 3191 | <message> |
3192 | 3192 | <location filename="../src/Callback/CallbackAxisPointsAbstract.cpp" line="123"/> |
3193 | 3193 | <location filename="../src/Callback/CallbackAxisPointsAbstract.cpp" line="217"/> |
3194 | <source>New axis point cannot be at the same screen position as an exisiting axis point</source> | |
3194 | <source>New axis point cannot be at the same screen position as an existing axis point</source> | |
3195 | 3195 | <translation type="unfinished"></translation> |
3196 | 3196 | </message> |
3197 | 3197 | <message> |
3508 | 3508 | <message> |
3509 | 3509 | <location filename="../src/Callback/CallbackAxisPointsAbstract.cpp" line="123"/> |
3510 | 3510 | <location filename="../src/Callback/CallbackAxisPointsAbstract.cpp" line="217"/> |
3511 | <source>New axis point cannot be at the same screen position as an exisiting axis point</source> | |
3512 | <translation>Nuevo punto de eje no puede estar en la misma posición de la pantalla como un punto del eje exisiting</translation> | |
3511 | <source>New axis point cannot be at the same screen position as an existing axis point</source> | |
3512 | <translation>Nuevo punto de eje no puede estar en la misma posición de la pantalla como un punto del eje existente</translation> | |
3513 | 3513 | </message> |
3514 | 3514 | <message> |
3515 | 3515 | <location filename="../src/Callback/CallbackAxisPointsAbstract.cpp" line="129"/> |
3201 | 3201 | <message> |
3202 | 3202 | <location filename="../src/Callback/CallbackAxisPointsAbstract.cpp" line="123"/> |
3203 | 3203 | <location filename="../src/Callback/CallbackAxisPointsAbstract.cpp" line="217"/> |
3204 | <source>New axis point cannot be at the same screen position as an exisiting axis point</source> | |
3204 | <source>New axis point cannot be at the same screen position as an existing axis point</source> | |
3205 | 3205 | <translation type="unfinished"/> |
3206 | 3206 | </message> |
3207 | 3207 | <message> |
3191 | 3191 | <message> |
3192 | 3192 | <location filename="../src/Callback/CallbackAxisPointsAbstract.cpp" line="123"/> |
3193 | 3193 | <location filename="../src/Callback/CallbackAxisPointsAbstract.cpp" line="217"/> |
3194 | <source>New axis point cannot be at the same screen position as an exisiting axis point</source> | |
3194 | <source>New axis point cannot be at the same screen position as an existing axis point</source> | |
3195 | 3195 | <translation type="unfinished"></translation> |
3196 | 3196 | </message> |
3197 | 3197 | <message> |
3191 | 3191 | <message> |
3192 | 3192 | <location filename="../src/Callback/CallbackAxisPointsAbstract.cpp" line="123"/> |
3193 | 3193 | <location filename="../src/Callback/CallbackAxisPointsAbstract.cpp" line="217"/> |
3194 | <source>New axis point cannot be at the same screen position as an exisiting axis point</source> | |
3194 | <source>New axis point cannot be at the same screen position as an existing axis point</source> | |
3195 | 3195 | <translation type="unfinished"></translation> |
3196 | 3196 | </message> |
3197 | 3197 | <message> |
3191 | 3191 | <message> |
3192 | 3192 | <location filename="../src/Callback/CallbackAxisPointsAbstract.cpp" line="123"/> |
3193 | 3193 | <location filename="../src/Callback/CallbackAxisPointsAbstract.cpp" line="217"/> |
3194 | <source>New axis point cannot be at the same screen position as an exisiting axis point</source> | |
3194 | <source>New axis point cannot be at the same screen position as an existing axis point</source> | |
3195 | 3195 | <translation type="unfinished"></translation> |
3196 | 3196 | </message> |
3197 | 3197 | <message> |
3191 | 3191 | <message> |
3192 | 3192 | <location filename="../src/Callback/CallbackAxisPointsAbstract.cpp" line="123"/> |
3193 | 3193 | <location filename="../src/Callback/CallbackAxisPointsAbstract.cpp" line="217"/> |
3194 | <source>New axis point cannot be at the same screen position as an exisiting axis point</source> | |
3194 | <source>New axis point cannot be at the same screen position as an existing axis point</source> | |
3195 | 3195 | <translation type="unfinished"></translation> |
3196 | 3196 | </message> |
3197 | 3197 | <message> |
3191 | 3191 | <message> |
3192 | 3192 | <location filename="../src/Callback/CallbackAxisPointsAbstract.cpp" line="123"/> |
3193 | 3193 | <location filename="../src/Callback/CallbackAxisPointsAbstract.cpp" line="217"/> |
3194 | <source>New axis point cannot be at the same screen position as an exisiting axis point</source> | |
3194 | <source>New axis point cannot be at the same screen position as an existing axis point</source> | |
3195 | 3195 | <translation type="unfinished"></translation> |
3196 | 3196 | </message> |
3197 | 3197 | <message> |
3512 | 3512 | <message> |
3513 | 3513 | <location filename="../src/Callback/CallbackAxisPointsAbstract.cpp" line="123"/> |
3514 | 3514 | <location filename="../src/Callback/CallbackAxisPointsAbstract.cpp" line="217"/> |
3515 | <source>New axis point cannot be at the same screen position as an exisiting axis point</source> | |
3516 | <translation>Novo ponto de eixo não pode ser na mesma posição da tela como um ponto de eixo exisiting</translation> | |
3515 | <source>New axis point cannot be at the same screen position as an existing axis point</source> | |
3516 | <translation>Novo ponto de eixo não pode ser na mesma posição da tela como um ponto de eixo exisitente</translation> | |
3517 | 3517 | </message> |
3518 | 3518 | <message> |
3519 | 3519 | <location filename="../src/Callback/CallbackAxisPointsAbstract.cpp" line="129"/> |
3191 | 3191 | <message> |
3192 | 3192 | <location filename="../src/Callback/CallbackAxisPointsAbstract.cpp" line="123"/> |
3193 | 3193 | <location filename="../src/Callback/CallbackAxisPointsAbstract.cpp" line="217"/> |
3194 | <source>New axis point cannot be at the same screen position as an exisiting axis point</source> | |
3194 | <source>New axis point cannot be at the same screen position as an existing axis point</source> | |
3195 | 3195 | <translation type="unfinished"></translation> |
3196 | 3196 | </message> |
3197 | 3197 | <message> |
3200 | 3200 | <message> |
3201 | 3201 | <location filename="../src/Callback/CallbackAxisPointsAbstract.cpp" line="123"/> |
3202 | 3202 | <location filename="../src/Callback/CallbackAxisPointsAbstract.cpp" line="217"/> |
3203 | <source>New axis point cannot be at the same screen position as an exisiting axis point</source> | |
3203 | <source>New axis point cannot be at the same screen position as an existing axis point</source> | |
3204 | 3204 | <translation type="unfinished"/> |
3205 | 3205 | </message> |
3206 | 3206 | <message> |