1515 QgsProcessingParameterEnum ,
1616 QgsProcessingParameterFeatureSink ,
1717 QgsProcessingParameterFeatureSource ,
18+ QgsProcessingParameterMatrix ,
1819 QgsVectorLayer ,
19- QgsWkbTypes
20+ QgsWkbTypes ,
21+ QgsSettings
2022)
21-
23+ from ...main .vectorLayerWrapper import qgsLayerToDataFrame
24+ import json
2225# ────────────────────────────────────────────────
2326# map2loop sorters
2427# ────────────────────────────────────────────────
4144 "Observation projections" : SorterObservationProjections ,
4245}
4346
44- class StratigraphySorterAlgorithm (QgsProcessingAlgorithm ):
47+ # class AutomaticStratigraphyAlgorithm(QgsProcessingAlgorithm):
48+ # """
49+ # Creates a one-column ‘stratigraphic column’ table ordered
50+ # by the selected map2loop sorter.
51+ # """
52+ # METHOD = "METHOD"
53+ # INPUT_GEOLOGY = "INPUT_GEOLOGY"
54+ # INPUT_STRATI_COLUMN = "INPUT_STRATI_COLUMN"
55+ # SORTING_ALGORITHM = "SORTING_ALGORITHM"
56+ # OUTPUT = "OUTPUT"
57+
58+ # # ----------------------------------------------------------
59+ # # Metadata
60+ # # ----------------------------------------------------------
61+ # def name(self) -> str:
62+ # return "loop_sorter"
63+
64+ # def displayName(self) -> str:
65+ # return "Stratigraphy Tools: Automatic Stratigraphic Column"
66+
67+ # def group(self) -> str:
68+ # return "Stratigraphy Tools"
69+
70+ # def groupId(self) -> str:
71+ # return "Loop3d"
72+
73+ # # ----------------------------------------------------------
74+ # # Parameters
75+ # # ----------------------------------------------------------
76+ # def initAlgorithm(self, config: Optional[dict[str, Any]] = None) -> None:
77+
78+ # self.addParameter(
79+ # QgsProcessingParameterFeatureSource(
80+ # self.INPUT_GEOLOGY,
81+ # "Geology polygons",
82+ # [QgsProcessing.TypeVectorPolygon],
83+ # )
84+ # )
85+
86+ # strati_settings = QgsSettings()
87+ # last_strati_column = strati_settings.value("m2l/strati_column", "")
88+ # self.addParameter(
89+ # QgsProcessingParameterMatrix(
90+ # name=self.INPUT_STRATI_COLUMN,
91+ # description="Stratigraphic Order",
92+ # headers=["Unit"],
93+ # numberRows=0,
94+ # defaultValue=last_strati_column
95+ # )
96+ # )
97+
98+ # # enum so the user can pick the strategy from a dropdown
99+ # self.addParameter(
100+ # QgsProcessingParameterEnum(
101+ # self.SORTING_ALGORITHM,
102+ # "Sorting strategy",
103+ # options=list(SORTER_LIST.keys()),
104+ # defaultValue=0, # Age-based is safest default
105+ # )
106+ # ) #:contentReference[oaicite:0]{index=0}
107+
108+ # self.addParameter(
109+ # QgsProcessingParameterFeatureSink(
110+ # self.OUTPUT,
111+ # "Stratigraphic column",
112+ # )
113+ # )
114+
115+ # # ----------------------------------------------------------
116+ # # Core
117+ # # ----------------------------------------------------------
118+ # def processAlgorithm(
119+ # self,
120+ # parameters: dict[str, Any],
121+ # context: QgsProcessingContext,
122+ # feedback: QgsProcessingFeedback,
123+ # ) -> dict[str, Any]:
124+
125+ # # 1 ► fetch user selections
126+ # geology: QgsVectorLayer = self.parameterAsVectorLayer(parameters, self.INPUT, context)
127+ # algorithm_index: int = self.parameterAsEnum(parameters, self.ALGO, context)
128+ # sorter_class = list(SORTER_LIST.values())[algorithm_index]
129+
130+ # feedback.pushInfo(f"Using sorter: {sorter_class.__name__}")
131+
132+ # # 2 ► convert QGIS layers / tables to pandas
133+ # # geology =
134+
135+ # # 3 ► run the sorter
136+ # # sorter = sorter_cls() # instantiation is always zero-argument
137+ # # order = sorter.sort(
138+ # # units_df,
139+ # # relationships_df,
140+ # # contacts_df,
141+ # # map_data,
142+ # # )
143+
144+ # # 4 ► write an in-memory table with the result
145+ # sink_fields = QgsFields()
146+ # sink_fields.append(QgsField("strat_pos", int))
147+ # sink_fields.append(QgsField("unit_name", str))
148+
149+ # (sink, dest_id) = self.parameterAsSink(
150+ # parameters,
151+ # self.OUTPUT,
152+ # context,
153+ # sink_fields,
154+ # QgsWkbTypes.NoGeometry,
155+ # geology.sourceCrs(),
156+ # )
157+
158+ # for pos, name in enumerate(order, start=1):
159+ # f = QgsFeature(sink_fields)
160+ # f.setAttributes([pos, name])
161+ # sink.addFeature(f, QgsFeatureSink.FastInsert)
162+
163+ # return {self.OUTPUT: dest_id}
164+
165+ # # ----------------------------------------------------------
166+ # def createInstance(self) -> QgsProcessingAlgorithm:
167+ # return __class__()
168+
169+
170+ class UserDefinedStratigraphyAlgorithm (QgsProcessingAlgorithm ):
45171 """
46172 Creates a one-column ‘stratigraphic column’ table ordered
47173 by the selected map2loop sorter.
48174 """
49- METHOD = "METHOD"
50- INPUT_GEOLOGY = "INPUT_GEOLOGY"
51175 INPUT_STRATI_COLUMN = "INPUT_STRATI_COLUMN"
52- SORTING_ALGORITHM = "SORTING_ALGORITHM"
53176 OUTPUT = "OUTPUT"
54177
55178 # ----------------------------------------------------------
@@ -59,63 +182,35 @@ def name(self) -> str:
59182 return "loop_sorter"
60183
61184 def displayName (self ) -> str :
62- return "Loop3d: Stratigraphic sorter "
185+ return "Stratigraphy: User-Defined Stratigraphic Column "
63186
64187 def group (self ) -> str :
65- return "Loop3d "
188+ return "Stratigraphy "
66189
67190 def groupId (self ) -> str :
68- return "Loop3d"
69-
70- def updateParameters (self , parameters ):
71- selected_method = parameters .get (self .METHOD , 0 )
72- if selected_method == 0 : # User-Defined selected
73- self .parameterDefinition (self .INPUT_STRATI_COLUMN ).setMetadata ({'widget_wrapper' : {'visible' : True }})
74- self .parameterDefinition (self .SORTING_ALGORITHM ).setMetadata ({'widget_wrapper' : {'visible' : False }})
75- self .parameterDefinition (self .INPUT_GEOLOGY ).setMetadata ({'widget_wrapper' : {'visible' : False }})
76- else : # Automatic selected
77- self .parameterDefinition (self .INPUT_GEOLOGY ).setMetadata ({'widget_wrapper' : {'visible' : True }})
78- self .parameterDefinition (self .SORTING_ALGORITHM ).setMetadata ({'widget_wrapper' : {'visible' : True }})
79- self .parameterDefinition (self .INPUT_STRATI_COLUMN ).setMetadata ({'widget_wrapper' : {'visible' : False }})
80-
81- return super ().updateParameters (parameters )
191+ return "Stratigraphy_Column"
82192
83193 # ----------------------------------------------------------
84194 # Parameters
85195 # ----------------------------------------------------------
86196 def initAlgorithm (self , config : Optional [dict [str , Any ]] = None ) -> None :
87-
88- self .addParameter (
89- QgsProcessingParameterEnum (
90- name = self .METHOD ,
91- description = 'Select Method' ,
92- options = ['User-Defined' , 'Automatic' ],
93- defaultValue = 0
94- )
95- )
96- self .addParameter (
97- QgsProcessingParameterFeatureSource (
98- self .INPUT_GEOLOGY ,
99- "Geology polygons" ,
100- [QgsProcessing .TypeVectorPolygon ],
101- )
102- )
103197
104-
105- # enum so the user can pick the strategy from a dropdown
198+ strati_settings = QgsSettings ()
199+ last_strati_column = strati_settings . value ( "m2l/strati_column" , "" )
106200 self .addParameter (
107- QgsProcessingParameterEnum (
108- self .ALGO ,
109- "Sorting strategy" ,
110- options = list (SORTER_LIST .keys ()),
111- defaultValue = 0 , # Age-based is safest default
201+ QgsProcessingParameterMatrix (
202+ name = self .INPUT_STRATI_COLUMN ,
203+ description = "Stratigraphic Order" ,
204+ headers = ["Unit" ],
205+ numberRows = 0 ,
206+ defaultValue = last_strati_column
112207 )
113- ) #:contentReference[oaicite:0]{index=0}
208+ )
114209
115210 self .addParameter (
116211 QgsProcessingParameterFeatureSink (
117212 self .OUTPUT ,
118- self . tr ( "Stratigraphic column" ) ,
213+ "Stratigraphic column" ,
119214 )
120215 )
121216
@@ -128,101 +223,15 @@ def processAlgorithm(
128223 context : QgsProcessingContext ,
129224 feedback : QgsProcessingFeedback ,
130225 ) -> dict [str , Any ]:
226+
227+ strati_column = self .parameterAsMatrix (parameters , self .INPUT_STRATI_COLUMN , context )
228+ strati_settings = QgsSettings ()
229+ last_strati_column = strati_settings .value ("m2l/strati_column" , "" )
131230
132- # 1 ► fetch user selections
133- in_layer : QgsVectorLayer = self .parameterAsVectorLayer (parameters , self .INPUT , context )
134- algo_index : int = self .parameterAsEnum (parameters , self .ALGO , context )
135- sorter_cls = list (SORTER_LIST .values ())[algo_index ]
136-
137- feedback .pushInfo (f"Using sorter: { sorter_cls .__name__ } " )
138-
139- # 2 ► convert QGIS layers / tables to pandas
140- # --------------------------------------------------
141- # You must supply these three DataFrames:
142- # units_df — required (layerId, name, minAge, maxAge, group)
143- # relationships_df — required (Index1 / Unitname1, Index2 / Unitname2 …)
144- # contacts_df — required for all but Age‐based
145- #
146- # Typical workflow:
147- # • iterate over in_layer.getFeatures()
148- # • build dicts/lists
149- # • pd.DataFrame(…)
150- #
151- # NB: map2loop does *not* need geometries – only attribute values.
152- # --------------------------------------------------
153- units_df , relationships_df , contacts_df , map_data = build_input_frames (in_layer , feedback )
154-
155- # 3 ► run the sorter
156- sorter = sorter_cls () # instantiation is always zero-argument
157- order = sorter .sort (
158- units_df ,
159- relationships_df ,
160- contacts_df ,
161- map_data ,
162- )
163-
164- # 4 ► write an in-memory table with the result
165- sink_fields = QgsFields ()
166- sink_fields .append (QgsField ("strat_pos" , int ))
167- sink_fields .append (QgsField ("unit_name" , str ))
168-
169- (sink , dest_id ) = self .parameterAsSink (
170- parameters ,
171- self .OUTPUT ,
172- context ,
173- sink_fields ,
174- QgsWkbTypes .NoGeometry ,
175- in_layer .sourceCrs (),
176- )
177-
178- for pos , name in enumerate (order , start = 1 ):
179- f = QgsFeature (sink_fields )
180- f .setAttributes ([pos , name ])
181- sink .addFeature (f , QgsFeatureSink .FastInsert )
231+ json_list = json .dumps (strati_column )
182232
183- return {self .OUTPUT : dest_id }
233+ return {self .OUTPUT : json_list }
184234
185235 # ----------------------------------------------------------
186236 def createInstance (self ) -> QgsProcessingAlgorithm :
187- return StratigraphySorterAlgorithm ()
188-
189-
190- # -------------------------------------------------------------------------
191- # Helper stub – you must replace with *your* conversion logic
192- # -------------------------------------------------------------------------
193- def build_input_frames (layer : QgsVectorLayer , feedback ) -> tuple :
194- """
195- Placeholder that turns the geology layer (and any other project
196- layers) into the four objects required by the sorter.
197-
198- Returns
199- -------
200- (units_df, relationships_df, contacts_df, map_data)
201- """
202- import pandas as pd
203- from m2l .map2loop .mapdata import MapData # adjust import path if needed
204-
205- # Example: convert the geology layer to a very small units_df
206- units_records = []
207- for f in layer .getFeatures ():
208- units_records .append (
209- dict (
210- layerId = f .id (),
211- name = f ["UNITNAME" ], # attribute names → your schema
212- minAge = f .attribute ("MIN_AGE" ),
213- maxAge = f .attribute ("MAX_AGE" ),
214- group = f ["GROUP" ],
215- )
216- )
217- units_df = pd .DataFrame .from_records (units_records )
218-
219- # relationships_df and contacts_df are domain-specific ─ fill them here
220- relationships_df = pd .DataFrame (columns = ["Index1" , "UNITNAME_1" , "Index2" , "UNITNAME_2" ])
221- contacts_df = pd .DataFrame (columns = ["UNITNAME_1" , "UNITNAME_2" , "length" ])
222-
223- # map_data can be mocked if you only use Age-based sorter
224- map_data = MapData () # or MapData.from_project(…) / MapData.from_files(…)
225-
226- feedback .pushInfo (f"Units → { len (units_df )} records" )
227-
228- return units_df , relationships_df , contacts_df , map_data
237+ return __class__ ()
0 commit comments