Not logged in.  Login/Logout/Register | List snippets | | Create snippet | Upload image | Upload data

252
LINES

< > BotCompany Repo | #1035027 // G22Mesh

JavaX fragment (include) [tags: use-pretranspiled]

Transpiled version (11072L) is out of date.

1  
// A "mesh" is a set of points ("anchors") connected through curves.
2  
3  
// An anchor is either
4  
// -the end of a curve
5  
// -an intersection of curves
6  
// -or a randomly chosen point along a curve (type 3)
7  
8  
// A type 3 anchor can be necessary to define an "o" shape
9  
// (because such a shape doesn't have an anchor point per se,
10  
// so we just choose one point along the ring).
11  
12  
// Sometimes however, a type 3 anchor is an artifact of the mesh
13  
// finding process and can be eliminated, reducing the anchor and
14  
// curve count by 1.
15  
16  
// G22Mesh has identity-based equality although it would be possible
17  
// to define a value-based equality function.
18  
19  
persistable sclass G22Mesh > Meta is MakesBufferedImage {
20  
  new LinkedHashMap<Pt, Anchor> anchorMap; // sorted by index
21  
  gettable new LinkedHashSet<Curve> curves;
22  
23  
  // cached signature
24  
  S cachedSignature;
25  
  
26  
  persistable sclass Curve {
27  
    gettable Anchor start;
28  
    gettable Anchor end;
29  
    gettable OnePathWithOrigin path; // origin = start.pt
30  
    
31  
    *(Anchor start, Anchor end, L<Pt> points) {
32  
      this(start, end, new OnePathWithOrigin(points, false));
33  
    }
34  
    
35  
    *(Anchor *start, Anchor *end, OnePathWithOrigin *path) {
36  
      start.outgoingCurves.add(this);
37  
      end.incomingCurves.add(this);
38  
    }
39  
    
40  
    toString {
41  
      ret "Curve of length " + n2(path.nSteps())
42  
        + " connecting " + start?.shortToString() + " and " + end?.shortToString();
43  
    }
44  
    
45  
    // This counts one of the anchors, but not the other.
46  
    // So if the anchors are right next to each other,
47  
    // the curve's length is 1.
48  
    int length() { ret path.nSteps(); }
49  
    
50  
    L<Anchor> anchors() { ret ll(start, end); }
51  
    
52  
    bool connectedTo(Anchor a) {
53  
      ret start == a || end == a;
54  
    }
55  
    
56  
    Anchor anchor(bool endAnchor) { ret endAnchor ? end : start; }
57  
    
58  
    Anchor anchorOpposite(Anchor a) {
59  
      ret a == start ? end : a == end ? start : null;
60  
    }
61  
  } // end of Curve
62  
  
63  
  persistable sclass Anchor {
64  
    int index; // every anchor gets a number starting from one
65  
    gettable Pt pt;
66  
    new L<Curve> outgoingCurves;
67  
    new L<Curve> incomingCurves;
68  
    
69  
    *(int *index, Pt *pt) {}
70  
    
71  
    int arity() { ret l(outgoingCurves) + l(incomingCurves); }
72  
    
73  
    S shortToString() {
74  
      ret "Anchor " + index + " at " + pt;
75  
    }
76  
    
77  
    toString {
78  
      L<Int> connections = sorted(map(connectedToAnchors(), a -> a.index));
79  
      ret shortToString() + ", arity " + arity()
80  
        + stringIf(isRingAnchor(), " [arbitrarily chosen ring anchor]")
81  
        + (empty(connections) ? "" : ", connected to " + joinWithComma(connections));
82  
    }
83  
    
84  
    Set<Curve> curves() {
85  
      ret joinSets(outgoingCurves, incomingCurves);
86  
    }
87  
    
88  
    Set<Anchor> connectedToAnchors() {
89  
      ret joinSets(
90  
        map(outgoingCurves, c -> c.end),
91  
        map(incomingCurves, c -> c.start));
92  
    }
93  
94  
    // The ring case where we just randomly select an anchor    
95  
    bool isRingAnchor() {
96  
      ret l(outgoingCurves) == 1 && l(incomingCurves) == 1
97  
        && first(outgoingCurves) == first(incomingCurves);
98  
    }
99  
  } // end of Anchor
100  
  
101  
  Cl<Pt> anchorPts() { ret keys(anchorMap); }
102  
  Cl<Anchor> anchors() { ret values(anchorMap); }
103  
  int nAnchors() { ret l(anchorMap); }
104  
  L<Anchor> anchorList() { ret valuesList(anchorMap); }
105  
  Anchor getAnchor(Pt p) { ret anchorMap.get(p); }
106  
  Anchor getAnchor(int idx) { ret anchorList().get(idx); }
107  
  
108  
  // Internal structure sanity check 
109  
  void checkArities {
110  
    new MultiMap<Anchor, Curve> outgoing;
111  
    new MultiMap<Anchor, Curve> incoming;
112  
    
113  
    for (Curve curve : curves) {
114  
      outgoing.add(curve.start, curve);
115  
      if (!anchorMap.containsKey(curve.start.pt))
116  
        fail("Start of curve not found: " + curve);
117  
      incoming.add(curve.end, curve);
118  
      if (!anchorMap.containsKey(curve.end.pt))
119  
        fail("End of curve not found: " + curve);
120  
    }
121  
     
122  
    for (Anchor anchor : anchors()) {
123  
      assertSetEquals(anchor + " outgoing", outgoing.get(anchor), anchor.outgoingCurves);
124  
      assertSetEquals(anchor + " incoming", incoming.get(anchor), anchor.incomingCurves);
125  
    }
126  
  }
127  
  
128  
  Anchor newAnchor aka addAnchor(Pt p) {  
129  
    Anchor anchor = new(l(anchorMap)+1, p);
130  
    anchorMap.put(p, anchor);
131  
    _invalidateSignature();
132  
    ret anchor;
133  
  }
134  
  
135  
  void removeAnchor(Anchor anchor) {
136  
    anchorMap.remove(anchor.pt);
137  
  }
138  
  
139  
  Curve addCurve(Curve curve) {
140  
    curves.add(curve);
141  
    _invalidateSignature();
142  
    ret curve;
143  
  }
144  
  
145  
  void removeCurve(Curve curve) {
146  
    curves.remove(curve);
147  
    curve.start.outgoingCurves.remove(curve);
148  
    curve.end.incomingCurves.remove(curve);
149  
    _invalidateSignature();
150  
  }
151  
  
152  
  // all anchor arities in descending order
153  
  // (a sort of fingerprint of the mesh)
154  
  int[] sortedArities() {
155  
    int[] array = mapToIntArray(anchors(), a -> a.arity());
156  
    ret sortIntArrayInPlaceDesc(array);
157  
  }
158  
  
159  
  S sortedAritiesToString aka aritySignature aka signature() {
160  
    try object cachedSignature;
161  
    int[] arities = sortedArities();
162  
    bool compact = all(arities, arity -> arity < 10);
163  
    ret cachedSignature = compact
164  
      ? join(asList(arities))
165  
      : roundBracket(joinWithComma(asList(arities)));
166  
  }
167  
  
168  
  toString {
169  
    ret "Mesh type " + sortedAritiesToString();
170  
  }
171  
  
172  
  // re-number anchors starting from 1 after anchors were removed
173  
  void renumberAnchors {
174  
    int i = 0;
175  
    for (anchor : anchors())
176  
      anchor.index = ++i;
177  
  }
178  
179  
  public Rect bounds() {
180  
    new BoundsFinder bf;
181  
    for (p : keys(anchorMap)) bf.add(p);
182  
    for (curve : curves)
183  
      for (p : curve.path.pointIterator())
184  
        bf.add(p);
185  
    ret bf!;
186  
  }
187  
188  
  public int getWidth() { ret bounds().w; }
189  
  public int getHeight() { ret bounds().h; }
190  
191  
  public BufferedImage getBufferedImage() {
192  
    var r = bounds();
193  
    ret new G22VisualizeMeshes(widthAndHeight(r.x2()+2, r.y2()+2), ll(this))!;
194  
  }
195  
  
196  
  void _invalidateSignature {
197  
    cachedSignature = null;
198  
  }
199  
  
200  
  bool containsAnchor(Anchor a) {
201  
    ret a != null && anchorMap.get(a.pt) == a;
202  
  }
203  
  
204  
  bool containsCurve(Curve c) {
205  
    ret curves.contains(c);
206  
  }
207  
  
208  
  L<Curve> curveList() { ret asList(curves); }
209  
  
210  
  // SOME OPERATIONS
211  
  
212  
  void moveAnchor(Anchor a, Pt p) {
213  
    if (eq(a.pt(), p)) ret;
214  
    assertNotNull(p);
215  
    anchorMap.remove(a.pt);
216  
    a.pt = p;
217  
    anchorMap.put(p, a);
218  
  }
219  
  
220  
  // coalesce a1 into a2, keeping a2's position intact
221  
  void mergeAnchorInto(Anchor a1, Anchor a2) {
222  
    mergeAnchors(a1, a2, a2.pt);
223  
  }
224  
  
225  
  // merges a1 and a2 (and their connections) into a new anchor
226  
  // at newPosition
227  
  void mergeAnchors(Anchor a1, Anchor a2, Pt newPosition) {
228  
    if (scaffoldingEnabled())
229  
      printVars("mergeAnchors", mesh := this, +a1, +a2, +newPosition);
230  
    assertNotSame(a1, a2);
231  
    assertNotNull(a1);
232  
    assertNotNull(a2);
233  
      
234  
    for (Curve curve : a1.outgoingCurves) {
235  
      // first step is now going from a2 to a1
236  
      curve.path.insertStep(0, ptMinus(a1.pt, a2.pt));
237  
      curve.path.origin(a2.pt);
238  
      curve.start = a2;
239  
      a2.outgoingCurves.add(curve);
240  
    }
241  
    
242  
    for (Curve curve : a1.incomingCurves) {
243  
      // last step is now going from a1 to a2
244  
      curve.path.addStep(ptMinus(a2.pt, a1.pt));
245  
      curve.end = a2;
246  
      a2.incomingCurves.add(curve);
247  
    }
248  
    
249  
    moveAnchor(a2, newPosition);
250  
    removeAnchor(a1);
251  
  }
252  
}

Author comment

Began life as a copy of #1035010

download  show line numbers  debug dex  old transpilations   

Travelled to 4 computer(s): bhatertpkbcr, ekrmjmnbrukm, mowyntqkapby, mqqgnosmbjvj

No comments. add comment

Snippet ID: #1035027
Snippet name: G22Mesh
Eternal ID of this version: #1035027/48
Text MD5: cbdaeebb172eea2dc1c43b8616a581c6
Author: stefan
Category: javax
Type: JavaX fragment (include)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2022-05-22 15:19:59
Source code size: 7519 bytes / 252 lines
Pitched / IR pitched: No / No
Views / Downloads: 178 / 437
Version history: 47 change(s)
Referenced in: [show references]