Mercurial > hg > svgui
comparison layer/TextLayer.cpp @ 44:ad214997dddb
* Refactor Layer classes so as no longer to store a single View pointer;
instead they need to be able to draw themselves on any View on demand.
Layers with caches (e.g. spectrogram) will need to be further refactored
so as to maintain a per-View cache
* Begin refactoring MainWindow by pulling out the document stuff (set of
layers, models etc) into a Document class. Not yet in use.
This revision is fairly unstable.
author | Chris Cannam |
---|---|
date | Thu, 02 Mar 2006 16:58:49 +0000 |
parents | 78515b1e29eb |
children | 01ab51f72e84 |
comparison
equal
deleted
inserted
replaced
43:78515b1e29eb | 44:ad214997dddb |
---|---|
21 #include <QInputDialog> | 21 #include <QInputDialog> |
22 | 22 |
23 #include <iostream> | 23 #include <iostream> |
24 #include <cmath> | 24 #include <cmath> |
25 | 25 |
26 TextLayer::TextLayer(View *w) : | 26 TextLayer::TextLayer() : |
27 Layer(w), | 27 Layer(), |
28 m_model(0), | 28 m_model(0), |
29 m_editing(false), | 29 m_editing(false), |
30 m_originalPoint(0, 0.0, tr("Empty Label")), | 30 m_originalPoint(0, 0.0, tr("Empty Label")), |
31 m_editingPoint(0, 0.0, tr("Empty Label")), | 31 m_editingPoint(0, 0.0, tr("Empty Label")), |
32 m_editingCommand(0), | 32 m_editingCommand(0), |
33 m_colour(255, 150, 50) // orange | 33 m_colour(255, 150, 50) // orange |
34 { | 34 { |
35 m_view->addLayer(this); | 35 |
36 } | 36 } |
37 | 37 |
38 void | 38 void |
39 TextLayer::setModel(TextModel *model) | 39 TextLayer::setModel(TextModel *model) |
40 { | 40 { |
136 m_colour = colour; | 136 m_colour = colour; |
137 emit layerParametersChanged(); | 137 emit layerParametersChanged(); |
138 } | 138 } |
139 | 139 |
140 bool | 140 bool |
141 TextLayer::isLayerScrollable() const | 141 TextLayer::isLayerScrollable(const View *v) const |
142 { | 142 { |
143 QPoint discard; | 143 QPoint discard; |
144 return !m_view->shouldIlluminateLocalFeatures(this, discard); | 144 return !v->shouldIlluminateLocalFeatures(this, discard); |
145 } | 145 } |
146 | 146 |
147 | 147 |
148 TextModel::PointList | 148 TextModel::PointList |
149 TextLayer::getLocalPoints(int x, int y) const | 149 TextLayer::getLocalPoints(View *v, int x, int y) const |
150 { | 150 { |
151 if (!m_model) return TextModel::PointList(); | 151 if (!m_model) return TextModel::PointList(); |
152 | 152 |
153 long frame0 = getFrameForX(-150); | 153 long frame0 = v->getFrameForX(-150); |
154 long frame1 = getFrameForX(m_view->width() + 150); | 154 long frame1 = v->getFrameForX(v->width() + 150); |
155 | 155 |
156 TextModel::PointList points(m_model->getPoints(frame0, frame1)); | 156 TextModel::PointList points(m_model->getPoints(frame0, frame1)); |
157 | 157 |
158 TextModel::PointList rv; | 158 TextModel::PointList rv; |
159 QFontMetrics metrics = QPainter().fontMetrics(); | 159 QFontMetrics metrics = QPainter().fontMetrics(); |
161 for (TextModel::PointList::iterator i = points.begin(); | 161 for (TextModel::PointList::iterator i = points.begin(); |
162 i != points.end(); ++i) { | 162 i != points.end(); ++i) { |
163 | 163 |
164 const TextModel::Point &p(*i); | 164 const TextModel::Point &p(*i); |
165 | 165 |
166 int px = getXForFrame(p.frame); | 166 int px = v->getXForFrame(p.frame); |
167 int py = getYForHeight(p.height); | 167 int py = getYForHeight(v, p.height); |
168 | 168 |
169 QString label = p.label; | 169 QString label = p.label; |
170 if (label == "") { | 170 if (label == "") { |
171 label = tr("<no text>"); | 171 label = tr("<no text>"); |
172 } | 172 } |
173 | 173 |
174 QRect rect = metrics.boundingRect | 174 QRect rect = metrics.boundingRect |
175 (QRect(0, 0, 150, 200), | 175 (QRect(0, 0, 150, 200), |
176 Qt::AlignLeft | Qt::AlignTop | Qt::TextWordWrap, label); | 176 Qt::AlignLeft | Qt::AlignTop | Qt::TextWordWrap, label); |
177 | 177 |
178 if (py + rect.height() > m_view->height()) { | 178 if (py + rect.height() > v->height()) { |
179 if (rect.height() > m_view->height()) py = 0; | 179 if (rect.height() > v->height()) py = 0; |
180 else py = m_view->height() - rect.height() - 1; | 180 else py = v->height() - rect.height() - 1; |
181 } | 181 } |
182 | 182 |
183 if (x >= px && x < px + rect.width() && | 183 if (x >= px && x < px + rect.width() && |
184 y >= py && y < py + rect.height()) { | 184 y >= py && y < py + rect.height()) { |
185 rv.insert(p); | 185 rv.insert(p); |
188 | 188 |
189 return rv; | 189 return rv; |
190 } | 190 } |
191 | 191 |
192 QString | 192 QString |
193 TextLayer::getFeatureDescription(QPoint &pos) const | 193 TextLayer::getFeatureDescription(View *v, QPoint &pos) const |
194 { | 194 { |
195 int x = pos.x(); | 195 int x = pos.x(); |
196 | 196 |
197 if (!m_model || !m_model->getSampleRate()) return ""; | 197 if (!m_model || !m_model->getSampleRate()) return ""; |
198 | 198 |
199 TextModel::PointList points = getLocalPoints(x, pos.y()); | 199 TextModel::PointList points = getLocalPoints(v, x, pos.y()); |
200 | 200 |
201 if (points.empty()) { | 201 if (points.empty()) { |
202 if (!m_model->isReady()) { | 202 if (!m_model->isReady()) { |
203 return tr("In progress"); | 203 return tr("In progress"); |
204 } else { | 204 } else { |
217 .arg(rt.toText(true).c_str()) | 217 .arg(rt.toText(true).c_str()) |
218 .arg(points.begin()->height) | 218 .arg(points.begin()->height) |
219 .arg(points.begin()->label); | 219 .arg(points.begin()->label); |
220 } | 220 } |
221 | 221 |
222 pos = QPoint(getXForFrame(useFrame), getYForHeight(points.begin()->height)); | 222 pos = QPoint(v->getXForFrame(useFrame), |
223 getYForHeight(v, points.begin()->height)); | |
223 return text; | 224 return text; |
224 } | 225 } |
225 | 226 |
226 | 227 |
227 //!!! too much overlap with TimeValueLayer/TimeInstantLayer | 228 //!!! too much overlap with TimeValueLayer/TimeInstantLayer |
228 | 229 |
229 bool | 230 bool |
230 TextLayer::snapToFeatureFrame(int &frame, | 231 TextLayer::snapToFeatureFrame(View *v, int &frame, |
231 size_t &resolution, | 232 size_t &resolution, |
232 SnapType snap) const | 233 SnapType snap) const |
233 { | 234 { |
234 if (!m_model) { | 235 if (!m_model) { |
235 return Layer::snapToFeatureFrame(frame, resolution, snap); | 236 return Layer::snapToFeatureFrame(v, frame, resolution, snap); |
236 } | 237 } |
237 | 238 |
238 resolution = m_model->getResolution(); | 239 resolution = m_model->getResolution(); |
239 TextModel::PointList points; | 240 TextModel::PointList points; |
240 | 241 |
241 if (snap == SnapNeighbouring) { | 242 if (snap == SnapNeighbouring) { |
242 | 243 |
243 points = getLocalPoints(getXForFrame(frame), -1); | 244 points = getLocalPoints(v, v->getXForFrame(frame), -1); |
244 if (points.empty()) return false; | 245 if (points.empty()) return false; |
245 frame = points.begin()->frame; | 246 frame = points.begin()->frame; |
246 return true; | 247 return true; |
247 } | 248 } |
248 | 249 |
297 frame = snapped; | 298 frame = snapped; |
298 return found; | 299 return found; |
299 } | 300 } |
300 | 301 |
301 int | 302 int |
302 TextLayer::getYForHeight(float height) const | 303 TextLayer::getYForHeight(View *v, float height) const |
303 { | 304 { |
304 int h = m_view->height(); | 305 int h = v->height(); |
305 return h - int(height * h); | 306 return h - int(height * h); |
306 } | 307 } |
307 | 308 |
308 float | 309 float |
309 TextLayer::getHeightForY(int y) const | 310 TextLayer::getHeightForY(View *v, int y) const |
310 { | 311 { |
311 int h = m_view->height(); | 312 int h = v->height(); |
312 return float(h - y) / h; | 313 return float(h - y) / h; |
313 } | 314 } |
314 | 315 |
315 void | 316 void |
316 TextLayer::paint(QPainter &paint, QRect rect) const | 317 TextLayer::paint(View *v, QPainter &paint, QRect rect) const |
317 { | 318 { |
318 if (!m_model || !m_model->isOK()) return; | 319 if (!m_model || !m_model->isOK()) return; |
319 | 320 |
320 int sampleRate = m_model->getSampleRate(); | 321 int sampleRate = m_model->getSampleRate(); |
321 if (!sampleRate) return; | 322 if (!sampleRate) return; |
322 | 323 |
323 // Profiler profiler("TextLayer::paint", true); | 324 // Profiler profiler("TextLayer::paint", true); |
324 | 325 |
325 int x0 = rect.left(), x1 = rect.right(); | 326 int x0 = rect.left(), x1 = rect.right(); |
326 long frame0 = getFrameForX(x0); | 327 long frame0 = v->getFrameForX(x0); |
327 long frame1 = getFrameForX(x1); | 328 long frame1 = v->getFrameForX(x1); |
328 | 329 |
329 TextModel::PointList points(m_model->getPoints(frame0, frame1)); | 330 TextModel::PointList points(m_model->getPoints(frame0, frame1)); |
330 if (points.empty()) return; | 331 if (points.empty()) return; |
331 | 332 |
332 QColor brushColour(m_colour); | 333 QColor brushColour(m_colour); |
333 | 334 |
334 int h, s, v; | 335 int h, s, val; |
335 brushColour.getHsv(&h, &s, &v); | 336 brushColour.getHsv(&h, &s, &val); |
336 brushColour.setHsv(h, s, 255, 100); | 337 brushColour.setHsv(h, s, 255, 100); |
337 | 338 |
338 QColor penColour; | 339 QColor penColour; |
339 if (m_view->hasLightBackground()) { | 340 if (v->hasLightBackground()) { |
340 penColour = Qt::black; | 341 penColour = Qt::black; |
341 } else { | 342 } else { |
342 penColour = Qt::white; | 343 penColour = Qt::white; |
343 } | 344 } |
344 | 345 |
346 // << m_model->getResolution() << " frames" << std::endl; | 347 // << m_model->getResolution() << " frames" << std::endl; |
347 | 348 |
348 QPoint localPos; | 349 QPoint localPos; |
349 long illuminateFrame = -1; | 350 long illuminateFrame = -1; |
350 | 351 |
351 if (m_view->shouldIlluminateLocalFeatures(this, localPos)) { | 352 if (v->shouldIlluminateLocalFeatures(this, localPos)) { |
352 TextModel::PointList localPoints = getLocalPoints(localPos.x(), | 353 TextModel::PointList localPoints = getLocalPoints(v, localPos.x(), |
353 localPos.y()); | 354 localPos.y()); |
354 if (!localPoints.empty()) illuminateFrame = localPoints.begin()->frame; | 355 if (!localPoints.empty()) illuminateFrame = localPoints.begin()->frame; |
355 } | 356 } |
356 | 357 |
357 int boxMaxWidth = 150; | 358 int boxMaxWidth = 150; |
358 int boxMaxHeight = 200; | 359 int boxMaxHeight = 200; |
359 | 360 |
360 paint.save(); | 361 paint.save(); |
361 paint.setClipRect(rect.x(), 0, rect.width() + boxMaxWidth, m_view->height()); | 362 paint.setClipRect(rect.x(), 0, rect.width() + boxMaxWidth, v->height()); |
362 | 363 |
363 for (TextModel::PointList::const_iterator i = points.begin(); | 364 for (TextModel::PointList::const_iterator i = points.begin(); |
364 i != points.end(); ++i) { | 365 i != points.end(); ++i) { |
365 | 366 |
366 const TextModel::Point &p(*i); | 367 const TextModel::Point &p(*i); |
367 | 368 |
368 int x = getXForFrame(p.frame); | 369 int x = v->getXForFrame(p.frame); |
369 int y = getYForHeight(p.height); | 370 int y = getYForHeight(v, p.height); |
370 | 371 |
371 if (illuminateFrame == p.frame) { | 372 if (illuminateFrame == p.frame) { |
372 paint.setBrush(penColour); | 373 paint.setBrush(penColour); |
373 if (m_view->hasLightBackground()) { | 374 if (v->hasLightBackground()) { |
374 paint.setPen(Qt::white); | 375 paint.setPen(Qt::white); |
375 } else { | 376 } else { |
376 paint.setPen(Qt::black); | 377 paint.setPen(Qt::black); |
377 } | 378 } |
378 } else { | 379 } else { |
390 Qt::AlignLeft | Qt::AlignTop | Qt::TextWordWrap, label); | 391 Qt::AlignLeft | Qt::AlignTop | Qt::TextWordWrap, label); |
391 | 392 |
392 QRect textRect = QRect(3, 2, boxRect.width(), boxRect.height()); | 393 QRect textRect = QRect(3, 2, boxRect.width(), boxRect.height()); |
393 boxRect = QRect(0, 0, boxRect.width() + 6, boxRect.height() + 2); | 394 boxRect = QRect(0, 0, boxRect.width() + 6, boxRect.height() + 2); |
394 | 395 |
395 if (y + boxRect.height() > m_view->height()) { | 396 if (y + boxRect.height() > v->height()) { |
396 if (boxRect.height() > m_view->height()) y = 0; | 397 if (boxRect.height() > v->height()) y = 0; |
397 else y = m_view->height() - boxRect.height() - 1; | 398 else y = v->height() - boxRect.height() - 1; |
398 } | 399 } |
399 | 400 |
400 boxRect = QRect(x, y, boxRect.width(), boxRect.height()); | 401 boxRect = QRect(x, y, boxRect.width(), boxRect.height()); |
401 textRect = QRect(x + 3, y + 2, textRect.width(), textRect.height()); | 402 textRect = QRect(x + 3, y + 2, textRect.width(), textRect.height()); |
402 | 403 |
421 // looks like save/restore doesn't deal with this: | 422 // looks like save/restore doesn't deal with this: |
422 paint.setRenderHint(QPainter::Antialiasing, false); | 423 paint.setRenderHint(QPainter::Antialiasing, false); |
423 } | 424 } |
424 | 425 |
425 void | 426 void |
426 TextLayer::drawStart(QMouseEvent *e) | 427 TextLayer::drawStart(View *v, QMouseEvent *e) |
427 { | 428 { |
428 // std::cerr << "TextLayer::drawStart(" << e->x() << "," << e->y() << ")" << std::endl; | 429 // std::cerr << "TextLayer::drawStart(" << e->x() << "," << e->y() << ")" << std::endl; |
429 | 430 |
430 if (!m_model) { | 431 if (!m_model) { |
431 std::cerr << "TextLayer::drawStart: no model" << std::endl; | 432 std::cerr << "TextLayer::drawStart: no model" << std::endl; |
432 return; | 433 return; |
433 } | 434 } |
434 | 435 |
435 long frame = getFrameForX(e->x()); | 436 long frame = v->getFrameForX(e->x()); |
436 if (frame < 0) frame = 0; | 437 if (frame < 0) frame = 0; |
437 frame = frame / m_model->getResolution() * m_model->getResolution(); | 438 frame = frame / m_model->getResolution() * m_model->getResolution(); |
438 | 439 |
439 float height = getHeightForY(e->y()); | 440 float height = getHeightForY(v, e->y()); |
440 | 441 |
441 m_editingPoint = TextModel::Point(frame, height, ""); | 442 m_editingPoint = TextModel::Point(frame, height, ""); |
442 m_originalPoint = m_editingPoint; | 443 m_originalPoint = m_editingPoint; |
443 | 444 |
444 if (m_editingCommand) m_editingCommand->finish(); | 445 if (m_editingCommand) m_editingCommand->finish(); |
447 | 448 |
448 m_editing = true; | 449 m_editing = true; |
449 } | 450 } |
450 | 451 |
451 void | 452 void |
452 TextLayer::drawDrag(QMouseEvent *e) | 453 TextLayer::drawDrag(View *v, QMouseEvent *e) |
453 { | 454 { |
454 // std::cerr << "TextLayer::drawDrag(" << e->x() << "," << e->y() << ")" << std::endl; | 455 // std::cerr << "TextLayer::drawDrag(" << e->x() << "," << e->y() << ")" << std::endl; |
455 | 456 |
456 if (!m_model || !m_editing) return; | 457 if (!m_model || !m_editing) return; |
457 | 458 |
458 long frame = getFrameForX(e->x()); | 459 long frame = v->getFrameForX(e->x()); |
459 if (frame < 0) frame = 0; | 460 if (frame < 0) frame = 0; |
460 frame = frame / m_model->getResolution() * m_model->getResolution(); | 461 frame = frame / m_model->getResolution() * m_model->getResolution(); |
461 | 462 |
462 float height = getHeightForY(e->y()); | 463 float height = getHeightForY(v, e->y()); |
463 | 464 |
464 m_editingCommand->deletePoint(m_editingPoint); | 465 m_editingCommand->deletePoint(m_editingPoint); |
465 m_editingPoint.frame = frame; | 466 m_editingPoint.frame = frame; |
466 m_editingPoint.height = height; | 467 m_editingPoint.height = height; |
467 m_editingCommand->addPoint(m_editingPoint); | 468 m_editingCommand->addPoint(m_editingPoint); |
468 } | 469 } |
469 | 470 |
470 void | 471 void |
471 TextLayer::drawEnd(QMouseEvent *e) | 472 TextLayer::drawEnd(View *v, QMouseEvent *e) |
472 { | 473 { |
473 // std::cerr << "TextLayer::drawEnd(" << e->x() << "," << e->y() << ")" << std::endl; | 474 // std::cerr << "TextLayer::drawEnd(" << e->x() << "," << e->y() << ")" << std::endl; |
474 if (!m_model || !m_editing) return; | 475 if (!m_model || !m_editing) return; |
475 | 476 |
476 bool ok = false; | 477 bool ok = false; |
477 QString label = QInputDialog::getText(m_view, tr("Enter label"), | 478 QString label = QInputDialog::getText(v, tr("Enter label"), |
478 tr("Please enter a new label:"), | 479 tr("Please enter a new label:"), |
479 QLineEdit::Normal, "", &ok); | 480 QLineEdit::Normal, "", &ok); |
480 | 481 |
481 if (ok) { | 482 if (ok) { |
482 TextModel::RelabelCommand *command = | 483 TextModel::RelabelCommand *command = |
488 m_editingCommand = 0; | 489 m_editingCommand = 0; |
489 m_editing = false; | 490 m_editing = false; |
490 } | 491 } |
491 | 492 |
492 void | 493 void |
493 TextLayer::editStart(QMouseEvent *e) | 494 TextLayer::editStart(View *v, QMouseEvent *e) |
494 { | 495 { |
495 // std::cerr << "TextLayer::editStart(" << e->x() << "," << e->y() << ")" << std::endl; | 496 // std::cerr << "TextLayer::editStart(" << e->x() << "," << e->y() << ")" << std::endl; |
496 | 497 |
497 if (!m_model) return; | 498 if (!m_model) return; |
498 | 499 |
499 TextModel::PointList points = getLocalPoints(e->x(), e->y()); | 500 TextModel::PointList points = getLocalPoints(v, e->x(), e->y()); |
500 if (points.empty()) return; | 501 if (points.empty()) return; |
501 | 502 |
502 m_editOrigin = e->pos(); | 503 m_editOrigin = e->pos(); |
503 m_editingPoint = *points.begin(); | 504 m_editingPoint = *points.begin(); |
504 m_originalPoint = m_editingPoint; | 505 m_originalPoint = m_editingPoint; |
510 | 511 |
511 m_editing = true; | 512 m_editing = true; |
512 } | 513 } |
513 | 514 |
514 void | 515 void |
515 TextLayer::editDrag(QMouseEvent *e) | 516 TextLayer::editDrag(View *v, QMouseEvent *e) |
516 { | 517 { |
517 if (!m_model || !m_editing) return; | 518 if (!m_model || !m_editing) return; |
518 | 519 |
519 long frameDiff = getFrameForX(e->x()) - getFrameForX(m_editOrigin.x()); | 520 long frameDiff = v->getFrameForX(e->x()) - v->getFrameForX(m_editOrigin.x()); |
520 float heightDiff = getHeightForY(e->y()) - getHeightForY(m_editOrigin.y()); | 521 float heightDiff = getHeightForY(v, e->y()) - getHeightForY(v, m_editOrigin.y()); |
521 | 522 |
522 long frame = m_originalPoint.frame + frameDiff; | 523 long frame = m_originalPoint.frame + frameDiff; |
523 float height = m_originalPoint.height + heightDiff; | 524 float height = m_originalPoint.height + heightDiff; |
524 | 525 |
525 // long frame = getFrameForX(e->x()); | 526 // long frame = v->getFrameForX(e->x()); |
526 if (frame < 0) frame = 0; | 527 if (frame < 0) frame = 0; |
527 frame = (frame / m_model->getResolution()) * m_model->getResolution(); | 528 frame = (frame / m_model->getResolution()) * m_model->getResolution(); |
528 | 529 |
529 // float height = getHeightForY(e->y()); | 530 // float height = getHeightForY(v, e->y()); |
530 | 531 |
531 if (!m_editingCommand) { | 532 if (!m_editingCommand) { |
532 m_editingCommand = new TextModel::EditCommand(m_model, tr("Drag Label")); | 533 m_editingCommand = new TextModel::EditCommand(m_model, tr("Drag Label")); |
533 } | 534 } |
534 | 535 |
537 m_editingPoint.height = height; | 538 m_editingPoint.height = height; |
538 m_editingCommand->addPoint(m_editingPoint); | 539 m_editingCommand->addPoint(m_editingPoint); |
539 } | 540 } |
540 | 541 |
541 void | 542 void |
542 TextLayer::editEnd(QMouseEvent *e) | 543 TextLayer::editEnd(View *v, QMouseEvent *e) |
543 { | 544 { |
544 // std::cerr << "TextLayer::editEnd(" << e->x() << "," << e->y() << ")" << std::endl; | 545 // std::cerr << "TextLayer::editEnd(" << e->x() << "," << e->y() << ")" << std::endl; |
545 if (!m_model || !m_editing) return; | 546 if (!m_model || !m_editing) return; |
546 | 547 |
547 if (m_editingCommand) { | 548 if (m_editingCommand) { |
565 m_editingCommand = 0; | 566 m_editingCommand = 0; |
566 m_editing = false; | 567 m_editing = false; |
567 } | 568 } |
568 | 569 |
569 void | 570 void |
570 TextLayer::editOpen(QMouseEvent *e) | 571 TextLayer::editOpen(View *v, QMouseEvent *e) |
571 { | 572 { |
572 std::cerr << "TextLayer::editOpen" << std::endl; | 573 std::cerr << "TextLayer::editOpen" << std::endl; |
573 | 574 |
574 if (!m_model) return; | 575 if (!m_model) return; |
575 | 576 |
576 TextModel::PointList points = getLocalPoints(e->x(), e->y()); | 577 TextModel::PointList points = getLocalPoints(v, e->x(), e->y()); |
577 if (points.empty()) return; | 578 if (points.empty()) return; |
578 | 579 |
579 QString label = points.begin()->label; | 580 QString label = points.begin()->label; |
580 | 581 |
581 bool ok = false; | 582 bool ok = false; |
582 label = QInputDialog::getText(m_view, tr("Enter label"), | 583 label = QInputDialog::getText(v, tr("Enter label"), |
583 tr("Please enter a new label:"), | 584 tr("Please enter a new label:"), |
584 QLineEdit::Normal, label, &ok); | 585 QLineEdit::Normal, label, &ok); |
585 if (ok && label != points.begin()->label) { | 586 if (ok && label != points.begin()->label) { |
586 TextModel::RelabelCommand *command = | 587 TextModel::RelabelCommand *command = |
587 new TextModel::RelabelCommand(m_model, *points.begin(), label); | 588 new TextModel::RelabelCommand(m_model, *points.begin(), label); |