Jump to content

David Schwartz

  • Content Count

  • Joined

  • Last visited

  • Days Won


David Schwartz last won the day on February 6

David Schwartz had the most liked content!

Community Reputation

18 Good

Recent Profile Visitors

The recent visitors block is disabled and is not being shown to other users.

  1. There used to be a library named Hipparchus that used Voronoi maps to accomplish this sort of thing. Microsoft bought Hipparchus, converted it to C# (from Fortran and C) and embedded it into SQL Server as it's GIS engine. These guys published an article in Dr. Dobb's back in 1992 or so that explained it very well. They also published c code and some tools in conjunction with that article. But they also sold the Hipparchus library commercially. It was a lot more involved than what the Dr. Dobb's article did. Since MS bought them out, they started an open-source effort to do similar stuff, but I haven't seen any updates in quite a while. I'd love to get hold of a copy of their library with the source code, if anybody might know of a copy sitting on a shelf somewhere. Unfortunately, once they sold to MS, the company had to pull their stuff off the market. I learned about the sale about a month too late. 😞 Essentially, there's one app that preprocesses a sampling of the data and creates a voronoi map. Then all of the points are translated from lat/lon to vectors based on the centroid of a voronoi cell where each point is a tuple <cos(p), offset>. As it happens, all of the math can then be done with simple 16-bit signed integer calculations, which makes looking for common types of things, like nearest-neighbor clusters in a set of points, extremely quick. But, if you have access to MS SQL Server since 2010 or so, I believe this logic is included in their GIS package.
  2. David Schwartz

    How to switch condition position?

    Rudy said: I think this order is guaranteed, but I would not really count on it. There's a compiler switch that overrides this, so it's not really "guaranteed".
  3. David Schwartz

    How to switch condition position?

    There's always the IfThen function. Result := IfThen( aStr = 'OK', True, False ); The problem is, this form If (condition) Then Result := True; does not set Result if condition is false. So it can be undefined or random.
  4. Better. Now, refactor this so the implementation of Arguments is not visible anywhere other than inside of a constructor somewhere. Again, the whole idea of encapsulation is to hide the implementation of data so it can change without affecting how it's used by clients. IOW, if you were to change it from TArray to TList or TDictionary, none of your application code would be affected.
  5. David Schwartz

    Should my record be a class instead?

    Gotcha. My mistake.
  6. That looks a LOT better! I'd fill out the constructors. The purpose of a ctor is to initialize the state of an object. When it's a simple item like what you've got, there might be multiple ctors: one would take no arguments and return an empty object, but initialize the contents anyway just to be safe. The other(s) would offer different combinations of parameters to allow you to create and set values in one statement. Instead, you create an empty object that's not initialized, then assign values to it separately. While that's fine, it's extra coding that can be eliminated. Also, you seem addicted to using TArray, even though the way you're using it is more like a TList. You never set the initial size anywhere, which appears to be unbounded. So why not use a TList instead? In ParseFile, you don't need try...finally because you don't want to delete the object you just created b/c it's being added to a list, as your comment suggests. If you delete it, you'll end up with a list full of pointers to freed objects. Consider this instead of that whole block: AddNode( TABCStructureNode.Create( 25, 'parent_of_25', 'contents of node 25' ) ); But, if you stare at that long enough, you start to think, "why not just do this instead?" AddNode( 25, 'parent_of_25', 'contents of node 25' ); where the TABCStructureNode is created implicitly by AddNode
  7. David Schwartz

    Should my record be a class instead?

    records and classes are different. Classes already have destructors.
  8. David Schwartz

    libpq.dll for FireDAC?

    I cannot seem to find a libpq.dll for Postgres that works with FireDAC in D10.2.3. Any suggestions on where to get a copy? NOTE: Please don't say to ask Google! I've pulled down five different versions that all have different datetime stamps and are supposedly 32-bit versions, but none of them work! If you have one that DOES work, where can I get a copy?
  9. I did not show the class definition on purpose. So that's only implied. Why don't you try writing the class definition (interface part) from what I've shown here so far?
  10. It seems you've got some heuristics in your head that are confusing you. There are no such rules. I suspect folks here could come up with a half-dozen different approaches. This is my approach. None of them is "the right approach" if they all work. I didn't put in any properties just to keep things simple for you. But you're welcome to add them and hide the explicit Get/Set methods. OOP has three legs: Encapsulation, Inheritance, polymorphism. Virtually all OOP situations involve Encapsulation; the others are only used if/when needed. All I've done is employ encapsulation. The others are not needed. In your approach, your encapsulation was overly complex and you kept trying to introduce unnecessary inheritance and composition. If you simply use a TStringlist, you don't need a class. But if you do that, all of your interactions require the client code to know exactly what your implementation is -- a TStringlist of TStringlists. Or an array of TUPLEs (or 2-member records). By encapsulating your implementation inside of a class, you can present a simple interface to the clients and completely hide the implementation. It doesn't matter if it's just one string or an entire frigging database system in the cloud with two levels of fall-back in case of failure. The client just sees one simple interface. And if you change the implementation, you don't have to change the way any other code deals with this class. That's the whole goal.
  11. Whoa. Spaghetti AND meatballs. 😮 Do NOT mix UI elements with data classes! I don't have time to unravel this mess for you. I'd start with your basic "item", which seems to be something like a TStringlist plus a name (that record thing). This could be a TUPLE of some sort. Alternatively, you could use the first entry of the stringlist to contain its own name, simply to avoid the additional structure just to have a separate identifier for it. But it may not even be necessary ... hang on. Your second level is you have a collection of these items. You use a TArray, but it could be a TList or even a TCollection. Whatever. It needs Add, Insert, Get, and Delete methods, and maybe a lookup of some kind (so you can find an "Item by name"). However, because of the simplicity of this, you could use one main TStringlist where the Strings[n] element is a 'name' and Objects[n] is a TStringlist. Then sl.IndexOf(some_name) -> n, and sl.Objects[n] -> the TStringlist (from your record). Viola! No need for a record or even an array. Just one TStringlist. Why use multiple structures when one will work fine for all needs? Technically speaking, while you could get by with just a single TStringlist, I'd wrap it into a class just to provide a simpler and more appropriate interface for it (eg., so you don't know how it's actually implemented). Memo.Lines is of type TStrings, so you'd want methods like these to interface nicely with TMemos: function TmyClass.GetItem( const nm : string ) : TStrings; var n : integer; begin Result := NIL; n := sl.IndexOf(nm); // assums 'sl' is the name of the main TStringlist in this object if (n >= 0) then Result := TStrings( sl.Objects[n] ) end; procedure TmyClass.SetItem( const nm : string; Value : TStrings ); var n : integer; sl2 : TStringlist; begin sl2 := GetItem(nm); if Assigned(sl2) then sl2.Assign(Value) else begin sl2 := TStringlist.Create(); sl2.Assign(Value); sl.AddObject( nm, sl2 ); end; end; Then when you need to get an item's value to a Memo, you'd use: memo1.Lines.Assign( myClassObj.GetItem( some_name ) ); // maybe do GetItem first to check for NIL before calling Assign in case Assign chokes if you give it NIL and to save the memo into an item buffer, you'd use: myClassObj.SetItem( some_name, memo1.Lines ); See how you're completely hiding the implementation, while providing an interface that makes using it very simple? And it knows nothing about UI elements, and yet works very simply with them. The class TmyClass is actually very simple, as it just contains a TStringlist (named 'sl' above). (Not DERIVED from it, but CONTAINS it.) The constructor would create it, and the destructor would destroy it. You'd have GetItem, SetItem, and maybe one or two other methods. That's it.
  12. David Schwartz

    General DB access question -- paging query results

    We're using Oracle 10g.
  13. David Schwartz

    Should my record be a class instead?

    When you pass everything as a string, as this guy seemed to be doing, you probably do. Or you need lots of exception handling code to deal with conversion errors.
  14. David Schwartz

    Version Control System

    I suggest git with GitHub or GitLab. I use Tower.
  15. David Schwartz

    Delphi and WebBroker on CentOS

    Given that all you need to make Delphi work on Centos is changing 9 search paths ... that's very encouraging! Can the SDK be modified to do that for each Linux project you create after that? Or will the updates be needed every time you set up a new project in that platform?