freenode/#clim - IRC Chatlog
Search
10:21:05
lukego
Sorry to be dense but is there an easy way, e.g. at the listener, to get an output record representing a draw-rectangle* call? I'm trying stuff but it's erroring e.g. (with-recording-options (t :draw nil :record t) (draw-rectangle* t 0 0 1 1)) errors probably because the latter t should be something else..?
10:28:03
lukego
yeah I'm reading through the docs but I don't get how to create/acquire a suitable medium
10:29:30
lukego
Is the sheet something that I create, or something that already exists that I need to reference, or is that a very context-dependent question? Just now I'm working in the clim listener but ideally I'd be typing expressions into Emacs and seeing results in CLIM instead
10:32:59
lukego
I'm having a hard time because the streams/sheets/etc are being created somewhere deep in CLIM via e.g. run-frame-top-level so I don't really understand e.g. how I could create a throw-away dummy one for these purposes
10:33:05
jackdaniel
lukego: writing to clim stream from the emacs repl is very likely to break - you access stream output history from outside its thread
10:34:08
lukego
so is that idea that I should "live" in the clim listener while experimenting with clim?
10:34:33
jackdaniel
not necessarily, you may execute commands on other application frames (and that is thread safe now)
10:34:48
jackdaniel
another option is to queue an event and handle it on the clim side (also thread safe)
10:35:59
jackdaniel
that said, if you want to implement thread-safe stream operations, I can provide some insight and an idea how that coould be done ;; I'm doing too many things right now to start that task though
10:36:11
lukego
I'm not sure if that's what I want... I don't actually want any graphics at all, I just want to call e.g. draw-rectangle* and get an output record to extract geometry data from. I'm using the listener because that seems like the easiest way to get a medium to draw on
10:37:14
lukego
I did replace t with *standard-output* above ^^ which got rid of the error but didn't actually give me an output record
10:37:22
jackdaniel
alternatives are using the render port, or (even better) the null port; but they are less tested
10:37:33
jackdaniel
if you just want to get the output record, you want to use (with-new-output-record …)
10:38:27
jackdaniel
I have (somewhere) a hack where I've created a *null-stream* that works with with-new-output-record
10:39:19
jackdaniel
ikrabbe: with interactive streams (like drei) it is important to have the text-view specialization that works only with text (for sake of parsing/unparsing results)
10:39:47
jackdaniel
so the easy way out for you would be defining two present methods: one specialized on (view text-view), and second not specialized on it (or specialized on some other view)
10:40:39
jackdaniel
example of interactive stream present use: autocompletion after tab -- if you put there arbitrary output, you could have a command line filled with circles, not really something you could rescan (as in parsing)
10:41:04
jackdaniel
perhaps that would make a nice extension, but I hope that gives you an intuition why it is required to be a string
10:58:16
jackdaniel
(let ((clim:*default-server-path* :null)) (defparameter *stream* (clim:open-window-stream)))
11:00:27
lukego
I really appreciate this. I have a problem where I really don't have a "global" view of CLIM and can get lost on really basic things. Helps immensely to have an example to start from
11:01:22
lukego
This seems to immediately DWIM with with-translation/with-scaling too i.e. the output record contains the final transformed coordinates
11:02:06
jackdaniel
but since it is a null medium, you may have problems if you probe i.e a bounding rectangle of a text output record
11:02:42
jackdaniel
mind, that this is not thread safe either, but since null backend does not generate any events - the "proper" thread doesn't do anything
11:03:05
jackdaniel
so there is no risk of a race condition unless you start multiple threads accessing the stream yourself
11:04:05
jackdaniel
probably a cleaner soultion would be creating an instance of the standard-output-recording-stream and use that as the macro argument, but I haven't tested it
11:12:00
lukego
re: thread-safety, would a simple hack be to just inject a closure into a clim thread to do anything clim-related?
11:12:36
jackdaniel
yes, that's the gist of the solution I have in mind. send a continuation wrapped in an event
11:12:40
lukego
IIRC that's how Java finally resolved their thread safety problems in Swing i.e. just decided that one thread has to own the whole GUI because otherwise it's a nightmare
11:13:52
lukego
*nod* don't let me distract you. hopefully I can help out a bit with stuff if I get my own CLIM application in the air
11:15:21
lukego
CLIM is still a bit magic to me e.g. here https://twitter.com/lukego/status/1363497447532675077 I printed a bunch of debug coordinates with FORMAT and expected them to appear in the SLIME REPL but actually got them in the diagram (which in this case was pretty convenient :-))
11:16:27
jackdaniel
of course you may define your own methods so streams are bound to something else
11:16:56
lukego
I think that I just haven't internalized the idea of graphical streams yet. drawing rectangles with coordinates doesn't feel very stream-like so it's easy to forget about the CLIM model
11:17:54
jackdaniel
think about the clim application pane as a terminal that was designed right (and implemented so-so!)
11:42:06
lukego
btw in the short term should I just roll the dice on thread-safety when calling clim from emacs or e.g. is there some mutex I can grab to make things safe-ish?
12:40:56
lukego
How do you normally lookup CLIM reference documentation e.g. by symbol? There don't seem to be docstrings in mcclim but maybe a clhs-style lookup hack from emacs or something?
12:47:27
jackdaniel
and given I will finish some day the documentation system London, I want to load clim spec to it and have that inside image
12:58:59
lukego
So is (slot-value A-DRAW-RECTANGLE-OUTPUT-RECORD 'clim-internals::coordinates) basically the way to pull apart the info that I want or is there a proper protocol for exatracting things like rectangle bounds? I don't see it in the spec (although maybe I could use bounding boxes as a proxy but that sounds risky)
13:08:27
jackdaniel
there is no protocol to access these. you need to take a look at the draw-rectangle-output-record itself to see what it stores in its slots (of course, that's an implementation detail)
13:11:27
jackdaniel
(but not for polygons that may result from calling medium-draw-rectangle* with non-rectilinear transformation)
13:16:59
lukego
Thanks. I'm digging into transformations now. It would be kind-of neat if I can always draw my rectangles left-to-right even if they are really being drawn e.g. along each side of a rectangle.
13:17:44
lukego
My experiments with rotations so far have given surprising results including giving polygons when I expect rectangles. Hopefully trial and error will get it worked out
13:36:59
lukego
For example suppose that you are drawing the rectangles along the four sides in this picture: https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQN7fLJjMqixkfJkFmYTsndRsyJ85viRtmVNA&usqp=CAU
13:37:50
lukego
if you write the code to draw the top row then you could presumably just run that under four different transformations
14:05:33
jackdaniel
something like that I suppose: http://turtleware.eu/static/paste/062c0ba3-legs.lisp.txt
14:06:08
jackdaniel
mind, that compose-transformations works like the standard transformation composition operator (transformations are applied right-to-left)
14:59:59
lukego
Glad to see that in the example if I capture the output records they are all rectangles. I'd been concerned that some weird stuff might happen due to rotating by floating point angles. Maybe rounding it back to integer pixel coordinates takes care of that.
15:04:48
jackdaniel
huh, there isn't even a kludge, are you sure that said rectangles are not polygon output records?
15:05:31
jackdaniel
(clim:rectilinear-transformation-p (clim:make-rotation-transformation pi)) ; > NIL
15:06:56
lukego
... though that's after I put in a with-output-to-output-record which had the side-effect of not actually rendering that on screen
15:07:32
jackdaniel
that's not what I mean. the instance is expected to always be draw-rectangle-output-record
15:10:31
lukego
yeah I'm thinking from the perspective of wanting to write a function that turns all the CLIM figures into humble (x0 y0 x1 y1) lists at the end
15:11:46
jackdaniel
"pure" clim programmer should always work on streams (which are subclasses sheets)
15:13:02
jackdaniel
most if not all functions that work on medium have trampolines specialized on a sheet
15:13:08
lukego
neat it seems like if I wrap the rectangles in (with-output-as-presentation ...) then the output records are still nice and clear and include juicy metadata that I can put in
15:14:23
jackdaniel
(so if you write tools that help you work with output records, they should work also on presentations)
15:28:40
lukego
So I now find myself writing a generic routine for converting output records into lists, e.g. ((:presentation :foo 'string (:rectangle 0 0 1 1))), and I can't help but wonder if this is a code smell that I've yet to recognize..
15:29:38
lukego
Maybe I should just operate on output records directly instead of converting them? but it seems like most of the interesting accessors are internal to climi so that'd be a bit messy. Or maybe something similar already exists? Or maybe I should be capturing the relevant data during drawing rather than hacking it out of the output records?
15:35:19
jackdaniel
if it is just a flat list of what you put on the screen, you could access them with output-record-children
15:41:02
lukego
I'm writing a program to output a printed circuit board design. I'm trying to do it in two main steps: decide where the components go and then decide how to connect them together.
15:42:12
lukego
For each component I need to pick a position on the board and then draw the "land" for its "footprint" there. That basically means to draw some ink that marks where the copper pads will be for soldering the part onto. So basically I'm drawing the yellowey golden bits of a picture like this: https://file.pcbway.com/websponsor/18/08/29/165932718_Top.png
15:44:00
lukego
Producing an actual drawing like this is important -- I can review it on the screen and I can also send it off to a fabricator to produce the PCB, which is the ultimate goal of the whole endeavor.
15:45:05
lukego
However, I also need to do a separate "routing" step to make all the necessary conncetions between these golden pads. That means basically to draw the dark green lines and make sure they follow all the necessary rules e.g. don't intersect.
15:46:57
lukego
and I'm thinking that the input to the "routing problem" will be basically the set of all those golden pads, including their positions, and the set of connections between them that have to be made. So I need to "reverse engineer" out of the image e.g. the locations of all golden pads that reprsent "Ground" or "1.2V power"and so on
15:48:22
lukego
aaaand the routing will be done on a separate data structure, something called "corner stitching" that I'm knocking off from Ousterhout's ancient 80s/90s CAD stuff. So I need to convert from this very concrete pixel-based repreesntation into a somewhat more abstract cell-based topological one
15:49:04
jackdaniel
I would start with the abstract cell-based topological representation and define presentation methods present on them
15:49:52
jackdaniel
you will still have the output record hierarchy generated from the abstract representation, and you could modify present methods or instances parameters to tweak the board
15:55:10
lukego
That's definitely what I'd do with a regular GUI toolkit. However I'm wondering if a CLIM sheet would make a reasonable data structure for "defining the problem" i.e. placing all of the golden pads that will need to be routed. The downside is that I need a conversion routine to translate that into a topological representation. The upside is that I can use CLIM's convenient drawing functions for defining the pads
15:55:59
lukego
So for example in your example code above ^^^ the repetition of left/right/top/bottom is relying on CLIM transformation functionality that I'd presumably need to write by hand if I "ported" this code to the abstract representation instead
16:00:45
admich
I have seen that recently the mirror of a sheet is no more the x11 window but an object clx-mirror. Is it correct respect to the spec? What is the benefit of this indirections?
16:02:00
jackdaniel
admich: it is correct, spec says that the mirror is not defined (so it is a backend-specific object)
16:02:32
jackdaniel
regarding benefits, I'm implementing xrender-based mechanism with double buffering, so I want to put a pixmap in clx-mirror as a backbuffer
16:05:06
jackdaniel
admich: regarding sheet geometry: http://turtleware.eu/static/paste/3a5704e8- (demo wip)
16:05:26
jackdaniel
slyrus was interested in it, afaik Krystof did implement it partially, but the source code is lost :)
16:07:34
lukego
jackdaniel: Here's a quick hack approach to converting CLIM output records back into geometry (rectangles) tagged with metadata (presentation objects). maybe not so nasty? https://imgur.com/a/bS0rmaM
16:11:40
admich
Eventually if I want to try to write a svg backend, what is the dependency policy? Can I use a library as spinneret or cl-who to produce xml code or better to use only format?
16:12:21
jackdaniel
admich: it is fine for backend to have dependencies (especially if it saves time and maintanance burden)
16:15:22
lukego
(Could also be that there's a simpler and more convenient drawing abstraction that I should be using e.g. turtle graphics instead of affine transformations.)
16:15:36
jackdaniel
I'm not sure how much of javascript is required for svg, but maybe cl-javascript (as a compiler) could be a sensible dependency too
16:17:35
admich
for an output only backend like pdf and postscript, I think javascript isn't necessary.
16:35:10
jackdaniel
lukego: I'm thinking about something like this: http://turtleware.eu/static/paste/be799619-legs.lisp.txt
16:35:38
jackdaniel
since all output is presentations, you could define commands - i.e add-pin and add-leg that works on the empty slot
16:36:07
jackdaniel
notice, that in the function #'draw we position the board, and the board operates in its own coordinate systems
16:36:22
jackdaniel
moreover, the board introduces yet another (inner) coordinate system for its pins etc etc
16:37:23
jackdaniel
you could get fancy and store the output record references inside each object (i.e leg holds in a slot a reference to its own presentation output record), however that doesn't seem to be necessary
16:38:59
jackdaniel
moreover, since these are presentations, you could define a multi-point drag-and-drop translator to manually set a route between pins
16:41:46
jackdaniel
now, if you define a command like this: (define-app-command (com-foo :keystroke #\space) ())
16:42:01
jackdaniel
then you may recompile the function draw, and after pressing space in the application window, it will get redrawn
16:48:19
lukego
jackdaniel: Is there an easy way to see the output records for this example? e.g. once it's already loaded on the screen can I somehow grab the output records in the SLIME inspector to see what CLIM did?
16:50:37
lukego
re: interactive commands, I'd like to be able to write a lot of commands for understanding what's going on in the diagram, e.g. showing all the pads that should be connected to GROUND, etc, but I don't want to do any "imperative" changes to the design e.g. placing pads or routing traces. I want to do that purely algorithmically.
16:52:01
lukego
but that's maybe also a grey area e.g. maybe I could click on something to change the parameters of the algorithm that routes it e.g. quickly test what happens if I'd rotate a part by 90deg and then if I like it I could add that constraint to the board-layout code.
16:52:58
lukego
(Maybe it's double gray area. If the board design "code" turns out to be mostly constraint expressions and parameters then interactively tweaking them might make sense while looking for the values to keep.)
16:59:42
jackdaniel
when you press space, it gets redisplayed, but if you press control+space, it will print all output records
17:04:12
lukego
So I think the next step for me is to write drawing routines for the different shapes of chips, then draw the ~100 chips that make up my design, then extract the ~1000 pin/pad locations, then write a function to create routes between them.
17:07:10
jackdaniel
this is somewhat improved example with interactivity: http://turtleware.eu/static/paste/85cbb9a8-legs.lisp.txt
17:07:50
jackdaniel
my old house collapsed, so this time I will build it starting from the smoke on the chimney
17:08:18
pjb
lukego: I would guess modern datasheets include the drawing and pin/pad positions. You can just download a database for them…
17:10:14
lukego
pjb: Genreally I'm doing the hardest and riskiest parts first but there are dependencies e.g. I need to define all the parts that I need, define what they look like, define guesstimated positions of them. that's what I've been working on. then I can route 'em.
17:12:09
lukego
yeah there will need to be some kind of a feedback loop there. I'm doing my placements using Screamer at the moment and I'm thinking that will be flexible for incrementally adding constraints ("move that towards bottom-left", "pick rotations for these that minimize intersections", etc)
17:12:12
pjb
lukego: you may have some constraints for the connectors for example, but the rest can be subject to the routing.
17:13:07
jackdaniel
n.b I'm quite satisfied with the defpresent macro, I will add it to my repl-hack-utilities :)
17:13:10
lukego
but I've spent enough time thinking about routing to identify an initial strategy to take from the litetrature ("Contour") so it's not a complete unknown.
17:14:30
jackdaniel
see how I've defined another view class that is default for the stream I'm drawing on
17:14:41
jackdaniel
otoh, when I right-click on the pin, the "textual" representation appears in the menu
17:15:37
lukego
"Contour" router is basically to shop the board up into tiles representing used and empty space and then find the pairs of things that need to be connected and do A* search from both ends in parallel until they meet. rinse and repeat. see how that goes... it's designed for VLSI and not PCB
17:18:37
lukego
I'm also currently "floorplanning" the board into discrete modules. that's mostly for divide-and-conquer purposes e.g. to have small enough domains to do Screamer backtracking searches usefully in. but also because a lot of good PCBs seem to be designed that way in practice. https://twitter.com/lukego/status/1363497447532675077
17:34:12
lukego
oh also, experience so far suggests it's easier said than done to import geometry from vendor datasheets, which means e.g. diagrams like this in pdf files https://imgur.com/a/aKsigfY and I'm still thinking hard about how to get accurate and reliable footprints. I think though that I'll start with cartoonish approximations for writing the router and then get the fine details right at the end.