Welcome to the Onshape forum! Ask questions and join in the discussions about everything Onshape.

First time visiting? Here are some places to start:
  1. Looking for a certain topic? Check out the categories filter or use Search (upper right).
  2. Need support? Ask a question to our Community Support category.
  3. Please submit support tickets for bugs but you can request improvements in the Product Feedback category.
  4. Be respectful, on topic and if you see a problem, Flag it.

If you would like to contact our Community Manager personally, feel free to send a private message or an email.

An implementation for qQueryCompoundFilter

MBartlett21MBartlett21 Member, OS Professional, Developers Posts: 2,050 ✭✭✭✭✭
I have always been annoyed by the lack of a filtering mechanism for QueryCompoundFilters, so I decided to build my own function to do the job.
Please see the code below (It also requires Query operators, an implementation of which can be found below that code)
export function qQueryCompoundFilter(q is Query, filter is QueryFilterCompound) returns Query
{
    return q * qUnion(switch (filter) {
                        (QueryFilterCompound.ALLOWS_AXIS) : [
                                qGeometry(q, GeometryType.LINE),
                                qGeometry(q, GeometryType.CIRCLE),
                                qGeometry(q, GeometryType.ARC),
                                qGeometry(q, GeometryType.CYLINDER),
                                qBodyType(q, BodyType.MATE_CONNECTOR)
                            ],

                        (QueryFilterCompound.ALLOWS_DIRECTION) : [
                                qGeometry(q, GeometryType.LINE),
                                qGeometry(q, GeometryType.CIRCLE),
                                qGeometry(q, GeometryType.ARC),
                                qGeometry(q, GeometryType.PLANE),
                                qGeometry(q, GeometryType.CYLINDER),
                                qBodyType(q, BodyType.MATE_CONNECTOR)
                            ],

                        (QueryFilterCompound.ALLOWS_PLANE) : [
                                qGeometry(q, GeometryType.PLANE),
                                qBodyType(q, BodyType.MATE_CONNECTOR)
                            ],

                        (QueryFilterCompound.ALLOWS_VERTEX) : [
                                qEntityFilter(q, EntityType.VERTEX),
                                qBodyType(q, BodyType.MATE_CONNECTOR)
                            ]
                    });
}

Query operators:
// Actually, the + (Union) and - (Subtraction) operators are not needed for this feature, only the * (intersection). I just included them for completeness
export operator+(lhs is Query, rhs is Query) returns Query
{
    if (lhs.queryType == QueryType.UNION)
    {
        lhs.subqueries = @resize(lhs.subqueries, @size(lhs.subqueries) + 1, rhs);
        return lhs;
    }
    return qUnion([lhs, rhs]);
}

export operator-(lhs is Query, rhs is Query) returns Query
{
    return qSubtraction(lhs, rhs);
}

export operator*(lhs is Query, rhs is Query) returns Query
{
    if (lhs.queryType == QueryType.INTERSECTION)
    {
        lhs.subqueries = @resize(lhs.subqueries, @size(lhs.subqueries) + 1, rhs);
        return lhs;
    }
    return qIntersection([lhs, rhs]);
}

PS: The idea of using Query operators stemmed from this discussion. As an example of their use, see my Australian Beams feature here, where they are used quite a lot. For instance, instead of making a Query by populating an array then using qUnion, I can just start off with qNothing() and then use query += stuff;
mb - draftsman - also FS author: View FeatureScripts
IR for AS/NZS 1100

Comments

  • ilya_baranilya_baran Onshape Employees, Developers, HDM Posts: 1,212
    This looks very nice!  I think it would help to see some example queries with your additions.  I have resisted adding these operators to std so far, but if people feel writing queries that way is more intuitive, I may reconsider.

    Why do you have the
    q *
    in your qQueryCompoundFilter function?  All of your subqueries in the qUnion filter q.
    Ilya Baran \ VP, Architecture and FeatureScript \ Onshape Inc
  • kevin_o_toole_1kevin_o_toole_1 Onshape Employees, Developers, HDM Posts: 565
    Great stuff @MBartlett21 . Solutions like this definitely ease the pain of writing queries, though we've yet to find the perfect one to include in the standard library.

    In this case, using qIntersection more commonly is probably going to have performance implications. A qIntersection works by first evaluating both inputs, in their entirety, and then finding common entities. If the two queries are both filters of the same root query, then you save some work by replacing the slow
    qIntersection(qEntityFilter(q, EntityType.BODY), qBodyType(q, BodyType.SOLID))
    with the faster
    qBodyType(qEntityFilter(q, EntityType.BODY), BodyType.SOLID)
    Even if qIntersection() itself were free to evaluate, the second query will be faster. The difference is: qBodyType in the latter is only filtering through the bodies, while qBodyType in the former it's filtering through all entities. The cost of this evaluation won't show up in your * code itself, but later, when that query needs to be evaluated (either directly with evaluateQuery(myQuery) or indirectly with e.g. opExtrude(... myQuery ...)). I don't see a great way of keeping the * syntax convenient while keeping the resulting queries fast (but that fact makes me like the -> syntax from the post you linked even more :wink: ).
  • konstantin_shiriazdanovkonstantin_shiriazdanov Member Posts: 1,221 ✭✭✭✭✭
    edited June 2020
     I don't see a great way of keeping the * syntax convenient while keeping the resulting queries fast (but that fact makes me like the -> syntax from the post you linked even more :wink: ).
    I you add a compact inline lambda syntax it would almost solve this problem. We would just unwrap nested construction into a sequence of functions. And this would be helpful for not only queries.
    One of the alternatives to the arrow syntax is an approach from Wolfram Language: they use f(#1,#2, ...)& for inline lambda definition.

  • MBartlett21MBartlett21 Member, OS Professional, Developers Posts: 2,050 ✭✭✭✭✭
    edited June 2020
    This looks very nice!  I think it would help to see some example queries with your additions.  I have resisted adding these operators to std so far, but if people feel writing queries that way is more intuitive, I may reconsider.

    Why do you have the
    q *
    in your qQueryCompoundFilter function?  All of your subqueries in the qUnion filter q.
    @ilya_baran
    The reason I have it in there is so that the Query evaluates in the proper order (see the documentation for qIntersection - "qIntersection preserves the order of the first subquery")

    EDIT: Fixed @mention
    mb - draftsman - also FS author: View FeatureScripts
    IR for AS/NZS 1100
  • MBartlett21MBartlett21 Member, OS Professional, Developers Posts: 2,050 ✭✭✭✭✭
    Also, another filter that we don't have an implementation for is SheetMetalDefinitionEntityType.
    Currently, to filter by that, we need to get the internal body, then filter by an EntityType, then get the entities in the part.
    mb - draftsman - also FS author: View FeatureScripts
    IR for AS/NZS 1100
Sign In or Register to comment.